Showing posts with label Monogame. Show all posts
Showing posts with label Monogame. Show all posts

Map Design of the 2D RPG Game

Now we've come to the part I hate the most. Probably the most important aspect of an RPG is the game map. I haven't quite decided exactly what it will be like yet. I hope I don't make a bad start. I know I need to set up a chunk system anyway. However, I don't want to make my game map tile-based. I don't really like the grid look. That's why I asked Gemini for advice. It suggested things like decalling and splatting, which are exactly what I have in mind, but the terminology isn't very familiar to me. Now it's time to get to work. I'm going to define a WorldManager and manage the chunks from there.

If you don't know how the chunk system works, I previously made a simple application related to this topic. You can check out that post here Devlog #2 Isometric Projection

I found a library called FastNoiseLite, and it's quite useful. I think it will allow me to achieve a non-repeating appearance for terrain.

Terrain Generation for 2D Game

It's good.I could work on this until dawn to get a good result. My goal is to ensure the randomness of that landform.

2D terrain landform

I guess I would have to work on the grass texture later. But now it's like enough. I want to see the map when the character moved. That's why I need a camera also.

It worked, but there is some performance issue about chunk rendering. It's to slow and not efficient.

My problem was solved after lowering the splat resolution. I also applied the map to be drawn according to the central chunk where the player is located. However, I'm still not happy with the grass area, so it needs an update...
Terrain Grass
And that's it. Well that's enough for now. Another post, I'm going to focus the character design, and a rigging tool.


Devamını Oku »

Starting The Basic RTS Game Project Structure

First, let's start by slowly building the project structure. I mentioned that I'll be using Monogame. I previously set up a Monogame template in VS 2022, so I can create a project directly. You can take look from this link(Setting up Visual Studio on Windows | MonoGame) I created LdgRpg project as monogame desktop cross-platform project.

I executed and I can see cornflowerblue color filled display. First, I want to add my character. Therefore, I will create an entities folder and add a class called Character. In this class, I will define general properties of this character, such as its position, speed, and size.

Of course, I'll have a general character pool. Therefore, I'll create a manager class to manage this character collection collectively. I also want to assign GUIDs to my characters; this might be useful later.

Normally, Monogame offers a class like Game1, but I want to build my own separate structure. Of course, I will use this structure within the Game1 class. I'm creating my own game manager. This manager will be the hub for managing all other managers.
protected override void LoadContent()
{
    _spriteBatch = new SpriteBatch(GraphicsDevice);
    gameManager = new GameManager();
    // TODO: use this.Content to load your game content here
}
Now we need to add some ridiculous character texture. I'll create a texture manager structure for this. Because managing textures one by one is too much trouble. And let's draw it:
And there it is my little ugly man right there. That's enough for now.
Devamını Oku »

Shader Codes

 Circle Drawing:

float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0
{
    float2 center = float2(0.5, 0.5);

    float distance = length(coords - center);

    float radius = 0.4;

    float4 color = (distance < radius) ? float4(0, 0, 0, 1) : float4(1, 1, 1, 1);

    return color;
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

 sin and cos

float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0
{

    float amplitude = 0.9;
    float frequency =55.0;
    
    // vertical
    float sinValue = amplitude * sin(coords.x * frequency);

    // horizontal
    float cosValue = amplitude * cos(coords.y * frequency);

    float4 color = float4(sinValue, 0, cosValue, 1);

    return color;
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

 Basic Animation:

Pass the time parameter from update method with these code lines that float time = (float)gameTime.TotalGameTime.TotalMilliseconds;, and then effect.Parameters["time"].SetValue(time);.

float time;

float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0
{
    float amplitude = 0.9;
    float frequency =55.0;
    
    // vertical
    float sinValue = amplitude * sin((coords.x + time * 0.5) * frequency);

    float4 color = float4(sinValue, 0, 0, 1);

    return color;
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0
{
    return float4(coords.x, 0.0, 0.0, 1.0);
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0
{
    return float4(0.0, coords.y, 0.0, 1.0);
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0
{
    // make (0,0) origin
    float2 uv = (coords - float2(0.5, 0.5)) * float2(2,-2);

    return float4(uv.x, uv.y, 0.0, 1.0);
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0
{
    // make (0,0) origin
    float2 uv = (coords - float2(0.5, 0.5)) * float2(2,-2);

    // length function calculate the magnitude of the vector. length(vec(0,0)) = 0, length(vec(0,1)) = 1    
    float distance = length(uv);

    return float4(0.0, distance, distance, 1.0);
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0
{
    // make (0,0) origin
    float2 uv = (coords - float2(0.5, 0.5)) * float2(2,-2);

    // length function calculate the magnitude of the vector. length(vec(0,0)) = 0, length(vec(0,1)) = 1    
    float distance = length(uv);

    distance -= 0.7;

    distance = abs(distance);

    return float4(distance, 0, distance, 1.0);
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0
{
    // make (0,0) origin
    float2 uv = (coords - float2(0.5, 0.5)) * float2(2,-2);

    // length function calculate the magnitude of the vector. length(vec(0,0)) = 0, length(vec(0,1)) = 1    
    float distance = length(uv);

    distance -= 0.7;

    distance = abs(distance);

    //distance = step(0.1, distance)
    distance = smoothstep(0.0, 0.2, distance);

    return float4(distance, 0, distance, 1.0);
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0
{
    // make (0,0) origin
    float2 uv = (coords - float2(0.5, 0.5)) * float2(2,-2);

    // length function calculate the magnitude of the vector. length(vec(0,0)) = 0, length(vec(0,1)) = 1    
    float distance = length(uv);

    distance = cos(distance * 10)/10;

    distance = abs(distance);

    //distance = step(0.1, distance)
    distance = smoothstep(0.0, 0.2, distance);

    return float4(distance, 0, distance, 1.0);
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
float time;

float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0
{
    // make (0,0) origin
    float2 uv = (coords - float2(0.5, 0.5)) * float2(2,-2);


    // length function calculate the magnitude of the vector. length(vec(0,0)) = 0, length(vec(0,1)) = 1    
    float distance = length(uv);

    distance = cos(distance * 10 + (time * 0.005))/10;

    distance = abs(distance);

    //distance = step(0.1, distance)
    distance = smoothstep(0.0, 0.2, distance);

    return float4(distance, 0, distance, 1.0);
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
float time;

float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0
{
    // make (0,0) origin
    float2 uv = (coords - float2(0.5, 0.5)) * float2(2,-2);
    
    uv *= 4;
    uv = frac(uv);
    uv -= 0.5;

    // length function calculate the magnitude of the vector. length(vec(0,0)) = 0, length(vec(0,1)) = 1    
    float distance = length(uv);

    distance = cos(distance * 10 + (time * 0.005)) / 10;

    distance = abs(distance);

    //distance = step(0.1, distance)
    distance = smoothstep(0.0, 0.2, distance);

    return float4(distance, 0, distance, 1.0);
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
float time;

static const float PI = 3.14159;

float2x2 rotate3d(float angle) {
    return float2x2(cos(angle), -sin(angle), sin(angle), cos(angle));
}

float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0
{
    float2 p = coords * 2 - float2(1,1);

    float temp = (time * 0.005) * PI;

    p = mul(rotate3d(temp), p);

    float t = 0.075 / abs(0.7 - length(p));

    float vl = 0.2 * (sin(time) + 3.0);
    float3 temp2 = float3(t, t, t) * float3(vl, p.y * 0.8, 3.0);

    return float4(temp2, 1.0);
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

Devamını Oku »

A UI library for MonoGame - Devlog #1

I've been working on my own ui library for a while. Progress is a bit slow because I don't have much time. I can say it's more of a project I pursue for hobby purposes. 

There are some reasons why I am doing such a project:

  • I can work on projects in Monogame, so I might need some UI support.
  • I couldn't find a UI library in Monogame that truly meets my requirements. (There are some issues for ImGUI in Monogame)
And other things that I haven't thought of yet.

So far in the project, I'm progressing with two elements: Component and Panel. The components will be placed inside the panels. Yes, simply like that. I don't want it to be more complex for now. I have created elements such as panel, button, and scrollbar. It's functioning adequately in its basic form. In fact, it seems possible to achieve a responsive outcome.

An example image:


The project will not be open source for now. Additionally, my GitHub page has become quite cluttered.

In the next stage, I plan to add basic elements such as horizontal scrollbar, label, text box, grid etc.. I also need to create a suitable structure for handling and capturing events.

Let's create a todo list:
  • Label
  • TextBox
  • Handling Events
  • Horizontal Scrollbar
  • z-order (for collision ex.)
  • Grid (??)
  • ImageButton component (~)

Devamını Oku »

Viewport in Monogame

Let's making some practices about use of viewports with Monogame. In my definition, Viewport provides relative rendering area for programmers. I think, it can be useful for making user interface. I tried to create some ui library, but it failed. Let's learn how to use Monogame at first.

In Monogame, we have already a default viewport. It represents whole screen. 

(x = 0, y =  0, width = screen_width, height=screen_size)

Let's create our first viewport. I created a new project as Monogame project, and I create viewport called newViewport in Initialize method in the Game class. But also we need to store our default viewport, because we need it:


newViewport = new Viewport();
newViewport.X = 50;
newViewport.Y = 50;
newViewport.Width = 100;
newViewport.Height = 75;

defaultViewport = GraphicsDevice.Viewport;
If we want to draw on this viewport we have to activate it at first: Because the current viewport is the default viewport. We need to activate it in render method. Then we can draw some objects on newViewport:
protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.CornflowerBlue);



    GraphicsDevice.Viewport = newViewport;
    GraphicsDevice.Clear(Color.Red); // it will not work as expected 

    // render somethings on this viewport 


    // then back to the default viewport
    GraphicsDevice.Viewport = defaultViewport;


    base.Draw(gameTime);
}
After that, all screen filled by red. Because Clear method clear the buffers. This causes for all screen. But if you want to background color in viewport area, we can use RenderTarget2D for that. Let's create RenderTarget2D too in Initialize method:
newViewportTarget = new RenderTarget2D(
        GraphicsDevice,
        newViewport.Width,
        newViewport.Height
    );
So let's go in the render side. It can confuse your mind, or may not. However I confused. So instead of going deep, I'm going to be a little result-oriented. As a result, asking "why" questions is not allowed. Where we were? Rendertarget2D!. We will use RenderTarget2D for each viewport. RenderTarget is a new back buffer for us. So we can use Clear method finally. Firstly we will set rendertarget, we will clear the rendertarget and then render somethings on it and then change the rendertarget or set as null to return default backbuffer, and same steps will be start for them too:
protected override void Draw(GameTime gameTime)
{

    // red area
    GraphicsDevice.SetRenderTarget(newViewportTarget);
    GraphicsDevice.Clear(Color.Red);

    // background area
    GraphicsDevice.SetRenderTarget(null);
    GraphicsDevice.Clear(Color.CornflowerBlue);

    

    
    // draw rendertargets with related viewports

    GraphicsDevice.Viewport = newViewport;

    _spriteBatch.Begin();
    _spriteBatch.Draw(newViewportTarget, new Rectangle(0, 0, newViewport.Width, newViewport.Height), Color.White);
    _spriteBatch.End();
    
    // then back to the default viewport
    GraphicsDevice.Viewport = defaultViewport;

    

    base.Draw(gameTime);
}
Let's look at the result:
This is fair. In my opinion, this features are not enough to create complex, advances to create ui. But it's enough to make useful ui.
Devamını Oku »