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

@ -22,7 +22,9 @@ public class Backend : IBackend
Tick = ++this.tick 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) while (this.pendingPackets.Count > 0)
{ {
this.publisher.Publish(this.pendingPackets.Dequeue()); this.publisher.Publish(this.pendingPackets.Dequeue());

View File

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

View File

@ -1,6 +1,5 @@
using Mine2d.engine.system.annotations; using Mine2d.engine.system.annotations;
using Mine2d.game.backend.network.packets; using Mine2d.game.backend.network.packets;
using Mine2d.game.core.data;
using Mine2d.game.state; using Mine2d.game.state;
namespace Mine2d.game.backend.interactor; namespace Mine2d.game.backend.interactor;
@ -20,10 +19,14 @@ public class Connect
Name = packet.PlayerName, Name = packet.PlayerName,
Id = packet.PlayerGuid, Id = packet.PlayerGuid,
Position = new Vector2(512244, 5390), Position = new Vector2(512244, 5390),
Movement = new Vector2(0, 0)
}; };
ctx.GameState.Players.Add( 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] [Interactor]
public class Move public class Move
{ {
[Interaction(InteractorKind.Hybrid, PacketType.Move)] // [Interaction(InteractorKind.Hybrid, PacketType.Move)]
public static void MoveHybrid(MovePacket packet) // public static void MoveHybrid(MovePacket packet)
{ // {
var ctx = Context.Get(); // var ctx = Context.Get();
var player = ctx.GameState.Players.Find(p => p.Name == packet.PlayerName); // var player = ctx.GameState.Players.Find(p => p.Name == packet.PlayerName);
if (player != null) // if (player != null)
{ // {
player.Movement = packet.Movement * 4; // player.Movement += packet.Movement * 2;
} // }
} // }
[Interaction(InteractorKind.Hybrid, PacketType.Tick)] // [Interaction(InteractorKind.Hybrid, PacketType.Tick)]
public static void TickHybrid() public static void TickHybrid()
{ {
var ctx = Context.Get(); 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; var context = Context.Get();
p.Position += p.Movement; var frontEndState = context.FrontendGameState;
if (p.Movement.Y > 8) 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 X = inputState.GetAxis(InputAxis.Horizontal)
{
Y = 8
}; };
} 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; var world = Context.Get().GameState.World;
bool hasCollision; bool hasCollision;
do do
{ {
var pL = p.Position + new Vector2(0, -8); var pL = player.Position + new Vector2(0, -8);
var pL2 = p.Position + new Vector2(0, -24); var pL2 = player.Position + new Vector2(0, -24);
hasCollision = hasCollision =
world.HasChunkAt(pL) && world.GetChunkAt(pL).HasSolidTileAt(pL) world.HasChunkAt(pL) && world.GetChunkAt(pL).HasSolidTileAt(pL)
|| world.HasChunkAt(pL2) && world.GetChunkAt(pL2).HasSolidTileAt(pL2); || world.HasChunkAt(pL2) && world.GetChunkAt(pL2).HasSolidTileAt(pL2);
if (hasCollision) if (hasCollision)
{ {
p.Movement = p.Movement with { X = 0 }; movement.CurrentVelocity = movement.CurrentVelocity with { X = 0 };
p.Position += new Vector2(0.1f, 0); player.Position += new Vector2(0.1f, 0);
} }
} while (hasCollision); } while (hasCollision);
do do
{ {
var pR = p.Position + new Vector2(14, -8); var pR = player.Position + new Vector2(14, -8);
var pR2 = p.Position + new Vector2(14, -24); var pR2 = player.Position + new Vector2(14, -24);
hasCollision = hasCollision =
world.HasChunkAt(pR) && world.GetChunkAt(pR).HasSolidTileAt(pR) world.HasChunkAt(pR) && world.GetChunkAt(pR).HasSolidTileAt(pR)
|| world.HasChunkAt(pR2) && world.GetChunkAt(pR2).HasSolidTileAt(pR2); || world.HasChunkAt(pR2) && world.GetChunkAt(pR2).HasSolidTileAt(pR2);
if (hasCollision) if (hasCollision)
{ {
p.Movement = p.Movement with { X = 0 }; movement.CurrentVelocity = movement.CurrentVelocity with { X = 0 };
p.Position += new Vector2(-0.1f, 0); player.Position += new Vector2(-0.1f, 0);
} }
} while (hasCollision); } while (hasCollision);
do do
{ {
var pL = p.Position + new Vector2(0, 0); var pL = player.Position + new Vector2(0, 0);
var pR = p.Position + new Vector2(14, 0); var pR = player.Position + new Vector2(14, 0);
hasCollision = hasCollision =
world.HasChunkAt(pL) && world.GetChunkAt(pL).HasSolidTileAt(pL) world.HasChunkAt(pL) && world.GetChunkAt(pL).HasSolidTileAt(pL)
|| world.HasChunkAt(pR) && world.GetChunkAt(pR).HasSolidTileAt(pR); || world.HasChunkAt(pR) && world.GetChunkAt(pR).HasSolidTileAt(pR);
if (hasCollision) if (hasCollision)
{ {
p.Movement = p.Movement with { Y = 0 }; movement.CurrentVelocity = movement.CurrentVelocity with { Y = 0 };
p.Position += new Vector2(0, -0.1f); player.Position += new Vector2(0, -0.01f);
} }
} while (hasCollision); } while (hasCollision);
do do
{ {
var pL = p.Position + new Vector2(0, -28); var pL = player.Position + new Vector2(0, -28);
var pR = p.Position + new Vector2(14, -28); var pR = player.Position + new Vector2(14, -28);
hasCollision = hasCollision =
world.HasChunkAt(pL) && world.GetChunkAt(pL).HasSolidTileAt(pL) world.HasChunkAt(pL) && world.GetChunkAt(pL).HasSolidTileAt(pL)
|| world.HasChunkAt(pR) && world.GetChunkAt(pR).HasSolidTileAt(pR); || world.HasChunkAt(pR) && world.GetChunkAt(pR).HasSolidTileAt(pR);
if (hasCollision) if (hasCollision)
{ {
p.Movement = p.Movement with { Y = 0 }; movement.CurrentVelocity = movement.CurrentVelocity with { Y = 0 };
p.Position += new Vector2(0, 0.1f); player.Position += new Vector2(0, 0.1f);
} }
} while (hasCollision); } 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) 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; using Mine2d.engine;
namespace Mine2d.game.frontend.inventory; 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; using Mine2d.game.state;
namespace Mine2d.game.frontend.inventory; namespace Mine2d.game.frontend.inventory;

View File

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

View File

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

View File

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

View File

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

View File

@ -7,4 +7,5 @@ public class GameState
public List<Player> Players { get; set; } = new List<Player>(); public List<Player> Players { get; set; } = new List<Player>();
public World World { get; set; } public World World { get; set; }
public uint Tick { 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 string Name { get; set; }
public Vector2 Position { get; set; } public Vector2 Position { get; set; }
public Vector2 Movement { get; set; }
public Guid Id { get; set; } public Guid Id { get; set; }
public Vector2 Mining { get; set; } public Vector2 Mining { get; set; }
public int MiningCooldown { get; set; } public int MiningCooldown { get; set; }
public PlayerInventory Inventory { get; set; } = new(); public PlayerInventory Inventory { get; set; } = new();
public PlayerMovementState PlayerMovementState { get; set; } = new();
public Vector2 GetCenter() public Vector2 GetCenter()
{ {

View File

@ -7,7 +7,7 @@ public class PlayerInventory
{ {
public ItemStack[] Hotbar { get; set; } = new ItemStack[9]; public ItemStack[] Hotbar { get; set; } = new ItemStack[9];
public ItemStack[] Inventory { get; set; } = new ItemStack[5 * 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) public bool PickupItemStack(ItemStack itemStack)
{ {
@ -34,6 +34,6 @@ public class PlayerInventory
public void SwapWithCursor(int slot, ItemStack[] inventory) 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;
}