Movement WIP

This commit is contained in:
Erik Simon 2022-12-21 11:24:00 +01:00
parent 5cefdfd802
commit 2068855979
20 changed files with 192 additions and 199 deletions

View File

@ -0,0 +1,9 @@
namespace Mine2d.engine.extensions;
public static class Vector2Extensions
{
public static Vector2 Clamp(this Vector2 vector, Vector2 min, Vector2 max)
{
return new Vector2(Math.Clamp(vector.X, min.X, max.X), Math.Clamp(vector.Y, min.Y, max.Y));
}
}

View File

@ -21,8 +21,10 @@ public class Backend : IBackend
{
Tick = ++this.tick
});
Context.Get().GameState.Tick = this.tick;
var context = Context.Get();
context.GameState.Tick = this.tick;
context.GameState.DeltaTime = dt;
while (this.pendingPackets.Count > 0)
{
this.publisher.Publish(this.pendingPackets.Dequeue());

View File

@ -1,7 +1,6 @@
using Mine2d.engine;
using Mine2d.engine.networking;
using Mine2d.game.core;
using Mine2d.game.core.data;
using Mine2d.game.state;
namespace Mine2d.game;

View File

@ -1,6 +1,5 @@
using Mine2d.engine.system.annotations;
using Mine2d.game.backend.network.packets;
using Mine2d.game.core.data;
using Mine2d.game.state;
namespace Mine2d.game.backend.interactor;
@ -20,10 +19,14 @@ public class Connect
Name = packet.PlayerName,
Id = packet.PlayerGuid,
Position = new Vector2(512244, 5390),
Movement = new Vector2(0, 0)
};
ctx.GameState.Players.Add(
player
new Player
{
Name = packet.PlayerName,
Id = packet.PlayerGuid,
Position = new Vector2(512244, 5390),
}
);
}
}

View File

@ -7,18 +7,18 @@ namespace Mine2d.game.backend.interactor;
[Interactor]
public class Move
{
[Interaction(InteractorKind.Hybrid, PacketType.Move)]
public static void MoveHybrid(MovePacket packet)
{
var ctx = Context.Get();
var player = ctx.GameState.Players.Find(p => p.Name == packet.PlayerName);
if (player != null)
{
player.Movement = packet.Movement * 4;
}
}
// [Interaction(InteractorKind.Hybrid, PacketType.Move)]
// public static void MoveHybrid(MovePacket packet)
// {
// var ctx = Context.Get();
// var player = ctx.GameState.Players.Find(p => p.Name == packet.PlayerName);
// if (player != null)
// {
// player.Movement += packet.Movement * 2;
// }
// }
[Interaction(InteractorKind.Hybrid, PacketType.Tick)]
// [Interaction(InteractorKind.Hybrid, PacketType.Tick)]
public static void TickHybrid()
{
var ctx = Context.Get();

View File

@ -0,0 +1,37 @@
using Mine2d.engine.system.annotations;
using Mine2d.game.backend.network.packets;
using Mine2d.game.core;
namespace Mine2d.game.backend.interactor;
[Interactor]
public class PlayerMovement
{
[Interaction(InteractorKind.Client, PacketType.Tick)]
public static void OnTick()
{
}
[Interaction(InteractorKind.Hybrid, PacketType.Tick)]
public static void OnHybridTick()
{
var context = Context.Get();
var gameState = context.GameState;
gameState.Players.ForEach(player =>
{
var position = player.Position;
PlayerEntity.Move(player);
PlayerEntity.Collide(player);
if (position != player.Position)
{
context.Backend.ProcessPacket(new PlayerMovedPacket
{
PlayerGuid = player.Id,
Target = player.Position
});
}
});
}
}

View File

@ -17,75 +17,91 @@ public class PlayerEntity
);
}
public static void Move(Player p)
public static void Move(Player player)
{
p.Movement += Constants.Gravity;
p.Position += p.Movement;
if (p.Movement.Y > 8)
var context = Context.Get();
var frontEndState = context.FrontendGameState;
var inputState = frontEndState.InputState;
var movement = player.PlayerMovementState;
if (!movement.IsGrounded)
movement.CurrentVelocity += Constants.Gravity;
movement.CurrentVelocity = movement.CurrentVelocity with
{
p.Movement = p.Movement with
{
Y = 8
};
}
X = inputState.GetAxis(InputAxis.Horizontal)
};
movement.CurrentMovement = movement.CurrentVelocity * movement.Speed * (float)context.GameState.DeltaTime;
player.Position += movement.CurrentMovement;
}
public static void Collide(Player p)
public static void Collide(Player player)
{
var movement = player.PlayerMovementState;
var world = Context.Get().GameState.World;
bool hasCollision;
do
{
var pL = p.Position + new Vector2(0, -8);
var pL2 = p.Position + new Vector2(0, -24);
var pL = player.Position + new Vector2(0, -8);
var pL2 = player.Position + new Vector2(0, -24);
hasCollision =
world.HasChunkAt(pL) && world.GetChunkAt(pL).HasSolidTileAt(pL)
|| world.HasChunkAt(pL2) && world.GetChunkAt(pL2).HasSolidTileAt(pL2);
if (hasCollision)
{
p.Movement = p.Movement with { X = 0 };
p.Position += new Vector2(0.1f, 0);
movement.CurrentVelocity = movement.CurrentVelocity with { X = 0 };
player.Position += new Vector2(0.1f, 0);
}
} while (hasCollision);
do
{
var pR = p.Position + new Vector2(14, -8);
var pR2 = p.Position + new Vector2(14, -24);
var pR = player.Position + new Vector2(14, -8);
var pR2 = player.Position + new Vector2(14, -24);
hasCollision =
world.HasChunkAt(pR) && world.GetChunkAt(pR).HasSolidTileAt(pR)
|| world.HasChunkAt(pR2) && world.GetChunkAt(pR2).HasSolidTileAt(pR2);
if (hasCollision)
{
p.Movement = p.Movement with { X = 0 };
p.Position += new Vector2(-0.1f, 0);
movement.CurrentVelocity = movement.CurrentVelocity with { X = 0 };
player.Position += new Vector2(-0.1f, 0);
}
} while (hasCollision);
do
{
var pL = p.Position + new Vector2(0, 0);
var pR = p.Position + new Vector2(14, 0);
var pL = player.Position + new Vector2(0, 0);
var pR = player.Position + new Vector2(14, 0);
hasCollision =
world.HasChunkAt(pL) && world.GetChunkAt(pL).HasSolidTileAt(pL)
|| world.HasChunkAt(pR) && world.GetChunkAt(pR).HasSolidTileAt(pR);
if (hasCollision)
{
p.Movement = p.Movement with { Y = 0 };
p.Position += new Vector2(0, -0.1f);
movement.CurrentVelocity = movement.CurrentVelocity with { Y = 0 };
player.Position += new Vector2(0, -0.01f);
}
} while (hasCollision);
do
{
var pL = p.Position + new Vector2(0, -28);
var pR = p.Position + new Vector2(14, -28);
var pL = player.Position + new Vector2(0, -28);
var pR = player.Position + new Vector2(14, -28);
hasCollision =
world.HasChunkAt(pL) && world.GetChunkAt(pL).HasSolidTileAt(pL)
|| world.HasChunkAt(pR) && world.GetChunkAt(pR).HasSolidTileAt(pR);
if (hasCollision)
{
p.Movement = p.Movement with { Y = 0 };
p.Position += new Vector2(0, 0.1f);
movement.CurrentVelocity = movement.CurrentVelocity with { Y = 0 };
player.Position += new Vector2(0, 0.1f);
}
} while (hasCollision);
{
var groundCheckPosition = player.Position - new Vector2(0, -1f);
var pL = groundCheckPosition + new Vector2(0, 0);
var pR = groundCheckPosition + new Vector2(14, 0);
movement.IsGrounded = world.HasChunkAt(pL) && world.GetChunkAt(pL).HasTileAt(pL)
|| world.HasChunkAt(pR) && world.GetChunkAt(pR).HasTileAt(pR);
}
}
public static bool HasCollisionWithAnyPlayer(Vector2 pos)

View File

@ -1,48 +0,0 @@
using Mine2d.engine.system;
using Mine2d.engine.system.annotations;
namespace Mine2d.game.frontend.events;
public class PlayerController
{
[EventListener(EventType.KeyDown)]
public static void OnKeyDown(SDL_Event e)
{
if (!IsMovementKey(e.key.keysym.scancode))
return;
// Context
// .Get()
// .Backend
// .ProcessPacket(new PlayerInputPacket
// {
// InputVector = e.key.keysym.scancode switch
// {
// SDL_Scancode.SDL_SCANCODE_A
// => new Vector2(-1, 0),
// SDL_Scancode.SDL_SCANCODE_D
// => new Vector2(1, 0),
// SDL_Scancode.SDL_SCANCODE_W or SDL_Scancode.SDL_SCANCODE_SPACE
// => new Vector2(0, 1),
// SDL_Scancode.SDL_SCANCODE_S
// => new Vector2(0, -1)
// }
// });
}
[EventListener(EventType.KeyUp)]
public static void OnKeyUp(SDL_Event e)
{
if (!IsMovementKey(e.key.keysym.scancode))
return;
}
private static bool IsMovementKey(SDL_Scancode scancode)
{
return scancode
is SDL_Scancode.SDL_SCANCODE_A
or SDL_Scancode.SDL_SCANCODE_D
or SDL_Scancode.SDL_SCANCODE_W
or SDL_Scancode.SDL_SCANCODE_S;
}
}

View File

@ -1,89 +0,0 @@
using Mine2d.engine.system;
using Mine2d.engine.system.annotations;
using Mine2d.game.backend.network.packets;
namespace Mine2d.game.frontend.events;
public class PlayerInput
{
[EventListener(EventType.KeyDown)]
public static void Move(SDL_Event e)
{
var ctx = Context.Get();
if (!IsMovementKey(e.key.keysym.scancode) || e.key.repeat == 1)
{
return;
}
var movementInput = ctx.FrontendGameState.MovementInput;
if (e.key.keysym.scancode == SDL_Scancode.SDL_SCANCODE_A)
{
movementInput.X -= 1;
}
if (e.key.keysym.scancode == SDL_Scancode.SDL_SCANCODE_D)
{
movementInput.X += 1;
}
if (e.key.keysym.scancode == SDL_Scancode.SDL_SCANCODE_W)
{
movementInput.Y -= 1;
}
if (e.key.keysym.scancode == SDL_Scancode.SDL_SCANCODE_S)
{
movementInput.Y += 1;
}
ctx.FrontendGameState.MovementInput = movementInput;
SendMovement();
}
[EventListener(EventType.KeyUp)]
public static void StopMove(SDL_Event e)
{
var ctx = Context.Get();
if (!IsMovementKey(e.key.keysym.scancode) || e.key.repeat == 1)
{
return;
}
var movementInput = ctx.FrontendGameState.MovementInput;
if (e.key.keysym.scancode == SDL_Scancode.SDL_SCANCODE_A)
{
movementInput.X += 1;
}
if (e.key.keysym.scancode == SDL_Scancode.SDL_SCANCODE_D)
{
movementInput.X -= 1;
}
if (e.key.keysym.scancode == SDL_Scancode.SDL_SCANCODE_W)
{
movementInput.Y += 1;
}
if (e.key.keysym.scancode == SDL_Scancode.SDL_SCANCODE_S)
{
movementInput.Y -= 1;
}
ctx.FrontendGameState.MovementInput = movementInput;
SendMovement();
}
private static bool IsMovementKey(SDL_Scancode scancode)
{
return scancode is SDL_Scancode.SDL_SCANCODE_A
or SDL_Scancode.SDL_SCANCODE_D
or SDL_Scancode.SDL_SCANCODE_W
or SDL_Scancode.SDL_SCANCODE_S;
}
private static void SendMovement()
{
var ctx = Context.Get();
var movement = ctx.FrontendGameState.MovementInput;
if (movement.Length() > 0)
{
movement = Vector2.Normalize(movement);
}
ctx.Backend.ProcessPacket(new MovePacket
{
PlayerName = ctx.FrontendGameState.PlayerName,
Movement = movement
});
}
}

View File

@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Mine2d.engine;
namespace Mine2d.game.frontend.inventory;

View File

@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Mine2d.game.state;
namespace Mine2d.game.frontend.inventory;

View File

@ -1,4 +1,3 @@
using System.Diagnostics;
using Mine2d.game.core;
namespace Mine2d.game.frontend.inventory
@ -51,7 +50,7 @@ namespace Mine2d.game.frontend.inventory
((4 + (i * 21)) * uiScale) + this.x,
(14 * uiScale) + this.y
);
if (player.Inventory.cursor == null &&
if (player.Inventory.Cursor == null &&
cursorPosition.X >= ((4 + (i * 21)) * uiScale) + this.x
&& cursorPosition.X <= ((4 + (i * 21)) * uiScale) + this.x + (16 * uiScale)
&& cursorPosition.Y >= (4 * uiScale) + this.y
@ -82,7 +81,7 @@ namespace Mine2d.game.frontend.inventory
((4 + ((i % 9) * 21)) * uiScale) + this.x,
((14 + 21 + ((i / 9) * 21)) * uiScale) + this.y
);
if (player.Inventory.cursor == null &&
if (player.Inventory.Cursor == null &&
cursorPosition.X >= ((4 + ((i % 9) * 21)) * uiScale) + this.x
&& cursorPosition.X <= ((4 + ((i % 9) * 21)) * uiScale) + this.x + (16 * uiScale)
&& cursorPosition.Y >= ((4 + 21 + ((i / 9) * 21)) * uiScale) + this.y

View File

@ -29,10 +29,10 @@ public class HudRenderer : IRenderer
public void Render()
{
this.renderHotbar();
this.RenderHotbar();
}
private void renderHotbar()
private void RenderHotbar()
{
var renderer = Context.Get().Renderer;
var uiScale = Context.Get().FrontendGameState.Settings.UiScale;

View File

@ -17,10 +17,10 @@ namespace Mine2d.game.frontend.renderer
var inventoryRenderer = ctx.InventoryRegistry.GetInventory(inventory);
inventoryRenderer.Render();
var player = PlayerEntity.GetSelf();
if (player.Inventory.cursor != null)
if (player.Inventory.Cursor != null)
{
var cursorPosition = ctx.FrontendGameState.CursorPosition;
var itemTexture = player.Inventory.cursor.GetTexture();
var itemTexture = player.Inventory.Cursor.GetTexture();
var uiScale = ctx.FrontendGameState.Settings.UiScale;
ctx.Renderer.DrawTexture(
itemTexture,
@ -30,7 +30,7 @@ namespace Mine2d.game.frontend.renderer
16 * uiScale
);
ctx.Renderer.DrawText(
"" + player.Inventory.cursor.Count,
"" + player.Inventory.Cursor.Count,
(int)(cursorPosition.X + 2),
(int)(cursorPosition.Y + (12 * uiScale))
);

View File

@ -21,6 +21,7 @@ public class FrontendGameState
public int HotbarIndex { get; set; }
public string Tooltip { get; set; } = "Test";
public InventoryKind OpenInventory { get; set; } = InventoryKind.None;
public InputState InputState { get; set; } = new();
}
public class Settings

View File

@ -7,4 +7,5 @@ public class GameState
public List<Player> Players { get; set; } = new List<Player>();
public World World { get; set; }
public uint Tick { get; set; }
public double DeltaTime { get; set; }
}

View File

@ -0,0 +1,57 @@
using System.Runtime.InteropServices;
using Mine2d.engine.system.annotations;
using Mine2d.game.backend.network.packets;
namespace Mine2d.game.state;
public enum InputAxis
{
Horizontal,
Vertical
}
public enum KeyEventType
{
KeyPressed,
KeyReleased
}
[Interactor]
public class InputState
{
[Interaction(InteractorKind.Client, PacketType.Tick)]
public static void OnTick()
{
Context.Get()
.FrontendGameState
.InputState
.UpdateInput();
}
private readonly byte[] keys;
public InputState()
{
var keysPtr = SDL_GetKeyboardState(out var keyCount);
this.keys = new byte[keyCount];
Marshal.Copy(keysPtr, this.keys, 0, keyCount);
}
public void UpdateInput()
{
var keysPtr = SDL_GetKeyboardState(out var keyCount);
Marshal.Copy(keysPtr, this.keys, 0, keyCount);
}
public float GetAxis(InputAxis axis)
{
return axis switch
{
InputAxis.Horizontal
=> this.keys[(int)SDL_Scancode.SDL_SCANCODE_D] - this.keys[(int)SDL_Scancode.SDL_SCANCODE_A],
InputAxis.Vertical
=> this.keys[(int)SDL_Scancode.SDL_SCANCODE_S] - this.keys[(int)SDL_Scancode.SDL_SCANCODE_W],
_ => 0
};
}
}

View File

@ -4,11 +4,11 @@ public class Player
{
public string Name { get; set; }
public Vector2 Position { get; set; }
public Vector2 Movement { get; set; }
public Guid Id { get; set; }
public Vector2 Mining { get; set; }
public int MiningCooldown { get; set; }
public PlayerInventory Inventory { get; set; } = new();
public PlayerMovementState PlayerMovementState { get; set; } = new();
public Vector2 GetCenter()
{

View File

@ -7,7 +7,7 @@ public class PlayerInventory
{
public ItemStack[] Hotbar { get; set; } = new ItemStack[9];
public ItemStack[] Inventory { get; set; } = new ItemStack[5 * 9];
public ItemStack cursor { get; set; }
public ItemStack Cursor { get; set; }
public bool PickupItemStack(ItemStack itemStack)
{
@ -34,6 +34,6 @@ public class PlayerInventory
public void SwapWithCursor(int slot, ItemStack[] inventory)
{
(inventory[slot], this.cursor) = (this.cursor, inventory[slot]);
(inventory[slot], this.Cursor) = (this.Cursor, inventory[slot]);
}
}

View File

@ -0,0 +1,14 @@
namespace Mine2d.game.state;
public class PlayerMovementState
{
public Vector2 Speed { get; set; } = new Vector2
{
X = 50f,
Y = 20f,
};
public float Drag { get; set; } = 0.1f;
public bool IsGrounded { get; set; } = false;
public Vector2 CurrentVelocity { get; set; } = Vector2.Zero;
public Vector2 CurrentMovement { get; set; } = Vector2.Zero;
}