From 74245c84097337716bb07a29aee292057a04c427 Mon Sep 17 00:00:00 2001 From: MasterGordon Date: Mon, 31 Oct 2022 01:50:13 +0100 Subject: [PATCH] added first tile render + fullscreen --- multiplayer-game/assets/stone.png | Bin 0 -> 454 bytes multiplayer-game/multiplayer-game.csproj | 2 +- multiplayer-game/src/Context.cs | 6 ++- multiplayer-game/src/MultiPlayerGame.cs | 1 + multiplayer-game/src/backend/Backend.cs | 18 +++----- multiplayer-game/src/backend/RemoteBackend.cs | 13 ++++-- multiplayer-game/src/backend/data/Packet.cs | 15 +++++- .../src/backend/interactor/Connect.cs | 1 + .../src/backend/interactor/Move.cs | 10 ++++ multiplayer-game/src/core/Bootstrapper.cs | 9 ++++ multiplayer-game/src/core/Constants.cs | 4 ++ multiplayer-game/src/core/data/Chunk.cs | 21 +++++++++ multiplayer-game/src/core/data/World.cs | 19 ++++++++ multiplayer-game/src/core/tiles/Tile.cs | 33 ++++++++++++++ .../src/core/tiles/TileRegistry.cs | 19 ++++++++ .../src/core/world/ChunkGenerator.cs | 20 ++++++++ multiplayer-game/src/engine/Renderer.cs | 11 +++++ multiplayer-game/src/engine/Window.cs | 5 ++ multiplayer-game/src/frontend/Frontend.cs | 43 +++++++++++++++--- .../src/frontend/renderer/IRenderer.cs | 4 ++ .../src/frontend/renderer/WorldRenderer.cs | 22 +++++++++ multiplayer-game/src/state/GameState.cs | 15 +++++- 22 files changed, 265 insertions(+), 26 deletions(-) create mode 100644 multiplayer-game/assets/stone.png create mode 100644 multiplayer-game/src/core/Bootstrapper.cs create mode 100644 multiplayer-game/src/core/Constants.cs create mode 100644 multiplayer-game/src/core/data/Chunk.cs create mode 100644 multiplayer-game/src/core/data/World.cs create mode 100644 multiplayer-game/src/core/tiles/Tile.cs create mode 100644 multiplayer-game/src/core/tiles/TileRegistry.cs create mode 100644 multiplayer-game/src/core/world/ChunkGenerator.cs create mode 100644 multiplayer-game/src/frontend/renderer/IRenderer.cs create mode 100644 multiplayer-game/src/frontend/renderer/WorldRenderer.cs diff --git a/multiplayer-game/assets/stone.png b/multiplayer-game/assets/stone.png new file mode 100644 index 0000000000000000000000000000000000000000..496c4acaf66689e73c6fcd8ac42308362d7c2185 GIT binary patch literal 454 zcmV;%0XhDOP)Px$fJsC_R5*=wlWUHoFbsr0KM39G!>u&Z-2W6UZ6LAtM+nd}+DHiFq{?MikngWQ zS=N=g-tRZ-y5jD%)~L1ed|dl;i7EgN5E1B+c)eZ#wAKLr3(g1t)R%=x@^h&`BEP}6 zoX;SlUqDqLi4-76pw04}3t|hsH_V*Y`qAbfPXvwVWP%WsGA!+R z*_0WSQZQ2B%wh-Wu+Xnc_k)Nlfyi`ke$o)F@@# zOc4PAO_aky0y_^+!u$6m5jB>h-E(&w9AZu79Hw%+p|^P7N9=M_>^=rF{v$g9^BqSn wFjNu{+}(&sR6l#4fIETG$9>s1%!l>=0Pb_Q3Y|10r2qf`07*qoM6N<$g5Vs)od5s; literal 0 HcmV?d00001 diff --git a/multiplayer-game/multiplayer-game.csproj b/multiplayer-game/multiplayer-game.csproj index f8c4950..f62c379 100644 --- a/multiplayer-game/multiplayer-game.csproj +++ b/multiplayer-game/multiplayer-game.csproj @@ -9,7 +9,7 @@ link true true - enable + disable diff --git a/multiplayer-game/src/Context.cs b/multiplayer-game/src/Context.cs index 6f5f2c5..7f40153 100644 --- a/multiplayer-game/src/Context.cs +++ b/multiplayer-game/src/Context.cs @@ -7,7 +7,9 @@ class Context public FrontendGameState FrontendGameState { get; set; } public Window Window { get; set; } public Renderer Renderer { get; set; } - public static Context? instance { get; set; } + public TileRegistry TileRegistry { get; set; } + public ResourceLoader ResourceLoader { get; set; } + public static Context instance { get; set; } public Context( bool isHost, @@ -26,6 +28,8 @@ class Context this.FrontendGameState = frontendGameState; this.Renderer = renderer; this.Window = window; + this.TileRegistry = new TileRegistry(); + this.ResourceLoader = new ResourceLoader(); Context.instance = this; } diff --git a/multiplayer-game/src/MultiPlayerGame.cs b/multiplayer-game/src/MultiPlayerGame.cs index e2b76fa..2796e17 100644 --- a/multiplayer-game/src/MultiPlayerGame.cs +++ b/multiplayer-game/src/MultiPlayerGame.cs @@ -29,6 +29,7 @@ class MultiPlayerGame : Game window ); } + Bootstrapper.Bootstrap(); ctx.Backend.Init(); ctx.Frontend.Init(); } diff --git a/multiplayer-game/src/backend/Backend.cs b/multiplayer-game/src/backend/Backend.cs index 226ae6d..2156339 100644 --- a/multiplayer-game/src/backend/Backend.cs +++ b/multiplayer-game/src/backend/Backend.cs @@ -1,4 +1,3 @@ -using System.Numerics; using System.Text; using Newtonsoft.Json; using WatsonTcp; @@ -8,20 +7,17 @@ class Backend : IBackend private WatsonTcpServer server; private Publisher publisher; private Queue pendingPackets = new Queue(); + private uint tick = 0; public void Process(double dt) { var ctx = Context.Get(); + this.ProcessPacket(new TickPacket(tick++)); while (pendingPackets.Count > 0) { var packet = pendingPackets.Dequeue(); this.ProcessPacket(packet); } - ctx.GameState.PlayerPositions.ForEach(player => - { - player.position += player.movement; - }); - // this.sendGameState(); } public void ProcessPacket(ValueType packet) @@ -33,9 +29,7 @@ class Backend : IBackend public void Init() { Task.Run(Run); - this.publisher = new Publisher( - Context.Get().IsHost ? InteractorKind.Server : InteractorKind.Client - ); + this.publisher = new Publisher(InteractorKind.Server); } public void Run() @@ -47,7 +41,7 @@ class Backend : IBackend server.Start(); } - private void clientConnected(object? sender, ConnectionEventArgs args) + private void clientConnected(object sender, ConnectionEventArgs args) { Console.WriteLine("Client connected: " + args.IpPort); var gameState = Context.Get().GameState; @@ -58,12 +52,12 @@ class Backend : IBackend } } - private void clientDisconnected(object? sender, DisconnectionEventArgs args) + private void clientDisconnected(object sender, DisconnectionEventArgs args) { Console.WriteLine("Client disconnected: " + args.IpPort); } - private void messageReceived(object? sender, MessageReceivedEventArgs args) + private void messageReceived(object sender, MessageReceivedEventArgs args) { var time = DateTime.Now; Console.WriteLine("Message Received: " + args.IpPort); diff --git a/multiplayer-game/src/backend/RemoteBackend.cs b/multiplayer-game/src/backend/RemoteBackend.cs index f4cf16e..0584e22 100644 --- a/multiplayer-game/src/backend/RemoteBackend.cs +++ b/multiplayer-game/src/backend/RemoteBackend.cs @@ -5,18 +5,24 @@ using System.Text; class RemoteBackend : IBackend { private WatsonTcpClient client; + private Publisher publisher; + private Queue pendingPackets = new Queue(); + private uint tick = 0; public void Process(double dt) { var ctx = Context.Get(); - ctx.GameState.PlayerPositions.ForEach(player => + this.ProcessPacket(new TickPacket(tick++)); + while (pendingPackets.Count > 0) { - player.position += player.movement; - }); + var packet = pendingPackets.Dequeue(); + this.ProcessPacket(packet); + } } public void ProcessPacket(ValueType packet) { + this.publisher.Publish(packet); var json = JsonConvert.SerializeObject(packet); var bytes = Encoding.UTF8.GetBytes(json); client.Send(bytes); @@ -25,6 +31,7 @@ class RemoteBackend : IBackend public void Init() { Task.Run(this.Run); + this.publisher = new Publisher(InteractorKind.Client); } public void Run() diff --git a/multiplayer-game/src/backend/data/Packet.cs b/multiplayer-game/src/backend/data/Packet.cs index d906260..beeeb3a 100644 --- a/multiplayer-game/src/backend/data/Packet.cs +++ b/multiplayer-game/src/backend/data/Packet.cs @@ -17,9 +17,22 @@ readonly struct ConnectPacket { public readonly string type = "connect"; public readonly string playerName; + public readonly Guid playerGuid; - public ConnectPacket(string playerName) + public ConnectPacket(string playerName, Guid playerGuid) { this.playerName = playerName; + this.playerGuid = playerGuid; + } +} + +readonly struct TickPacket +{ + public readonly string type = "tick"; + public readonly uint tick; + + public TickPacket(uint tick) + { + this.tick = tick; } } diff --git a/multiplayer-game/src/backend/interactor/Connect.cs b/multiplayer-game/src/backend/interactor/Connect.cs index e214e1c..22b4208 100644 --- a/multiplayer-game/src/backend/interactor/Connect.cs +++ b/multiplayer-game/src/backend/interactor/Connect.cs @@ -14,6 +14,7 @@ class Connect new Player { name = packet.playerName, + guid = packet.playerGuid, position = new Vector2(0, 0), movement = new Vector2(0, 0) } diff --git a/multiplayer-game/src/backend/interactor/Move.cs b/multiplayer-game/src/backend/interactor/Move.cs index 14ec141..c6ce3ae 100644 --- a/multiplayer-game/src/backend/interactor/Move.cs +++ b/multiplayer-game/src/backend/interactor/Move.cs @@ -11,4 +11,14 @@ class Move player.movement = packet.movement * 4; } } + + [Interaction(InteractorKind.Hybrid, "tick")] + public static void TickHybrid(TickPacket packet) + { + var ctx = Context.Get(); + ctx.GameState.PlayerPositions.ForEach(player => + { + player.position += player.movement; + }); + } } diff --git a/multiplayer-game/src/core/Bootstrapper.cs b/multiplayer-game/src/core/Bootstrapper.cs new file mode 100644 index 0000000..9cd4490 --- /dev/null +++ b/multiplayer-game/src/core/Bootstrapper.cs @@ -0,0 +1,9 @@ +class Bootstrapper +{ + public static void Bootstrap() + { + var ctx = Context.Get(); + ctx.GameState.World = new World(); + ctx.GameState.World.AddChunk(ChunkGenerator.CreateFilledChunk(0, 0, Tiles.stone)); + } +} diff --git a/multiplayer-game/src/core/Constants.cs b/multiplayer-game/src/core/Constants.cs new file mode 100644 index 0000000..0eeda54 --- /dev/null +++ b/multiplayer-game/src/core/Constants.cs @@ -0,0 +1,4 @@ +class Constants +{ + public const int ChunkSize = 32; +} diff --git a/multiplayer-game/src/core/data/Chunk.cs b/multiplayer-game/src/core/data/Chunk.cs new file mode 100644 index 0000000..157ba87 --- /dev/null +++ b/multiplayer-game/src/core/data/Chunk.cs @@ -0,0 +1,21 @@ +class Chunk +{ + public int[][] Tiles { get; set; } = new int[Constants.ChunkSize][]; + public int X { get; set; } + public int Y { get; set; } + + public Chunk(int x, int y) + { + X = x; + Y = y; + for (int i = 0; i < Constants.ChunkSize; i++) + { + Tiles[i] = new int[Constants.ChunkSize]; + } + } + + public void SetTile(int x, int y, int tile) + { + Tiles[x][y] = tile; + } +} diff --git a/multiplayer-game/src/core/data/World.cs b/multiplayer-game/src/core/data/World.cs new file mode 100644 index 0000000..526cc0d --- /dev/null +++ b/multiplayer-game/src/core/data/World.cs @@ -0,0 +1,19 @@ +class World +{ + public Dictionary Chunks { get; set; } = new Dictionary(); + + public void AddChunk(Chunk chunk) + { + Chunks.Add(chunk.X + "," + chunk.Y, chunk); + } + + public Chunk GetChunk(int x, int y) + { + return Chunks[x + "," + y]; + } + + public bool ChunkExists(int x, int y) + { + return Chunks.ContainsKey(x + "," + y); + } +} diff --git a/multiplayer-game/src/core/tiles/Tile.cs b/multiplayer-game/src/core/tiles/Tile.cs new file mode 100644 index 0000000..c17b0fc --- /dev/null +++ b/multiplayer-game/src/core/tiles/Tile.cs @@ -0,0 +1,33 @@ +using static SDL2.SDL; +using static SDL2.SDL_image; + +class Tile +{ + public string Name { get; set; } + public IntPtr Texture { get; set; } + + public Tile(string name, string textureName) + { + this.Name = name; + + var rl = Context.Get().ResourceLoader; + var res = rl.LoadToIntPtr("assets." + textureName + ".png"); + var sdlBuffer = SDL_RWFromMem(res.ptr, res.size); + var surface = IMG_Load_RW(sdlBuffer, 1); + var texture = Context.Get().Renderer.CreateTextureFromSurface(surface); + this.Texture = texture; + SDL_FreeSurface(surface); + } + + ~Tile() + { + SDL_DestroyTexture(this.Texture); + } + + public void Render(int x, int y) + { + var renderer = Context.Get().Renderer; + var scale = Context.Get().GameState.Settings.GameScale; + renderer.DrawTexture(this.Texture, x * scale, y * scale, 16 * scale, 16 * scale); + } +} diff --git a/multiplayer-game/src/core/tiles/TileRegistry.cs b/multiplayer-game/src/core/tiles/TileRegistry.cs new file mode 100644 index 0000000..61341ec --- /dev/null +++ b/multiplayer-game/src/core/tiles/TileRegistry.cs @@ -0,0 +1,19 @@ +enum Tiles : int +{ + stone = 1, +} + +class TileRegistry +{ + public Dictionary Tiles { get; set; } = new Dictionary(); + + public void RegisterTile() + { + Tiles.Add(1, new Tile("stone", "stone")); + } + + public Tile GetTile(int id) + { + return Tiles[id]; + } +} diff --git a/multiplayer-game/src/core/world/ChunkGenerator.cs b/multiplayer-game/src/core/world/ChunkGenerator.cs new file mode 100644 index 0000000..5f932ea --- /dev/null +++ b/multiplayer-game/src/core/world/ChunkGenerator.cs @@ -0,0 +1,20 @@ +class ChunkGenerator +{ + public static Chunk CreateFilledChunk(int x, int y, int fill) + { + Chunk chunk = new Chunk(x, y); + for (int i = 0; i < Constants.ChunkSize; i++) + { + for (int j = 0; j < Constants.ChunkSize; j++) + { + chunk.SetTile(i, j, fill); + } + } + return chunk; + } + + public static Chunk CreateFilledChunk(int x, int y, Tiles fill) + { + return CreateFilledChunk(x, y, (int)fill); + } +} diff --git a/multiplayer-game/src/engine/Renderer.cs b/multiplayer-game/src/engine/Renderer.cs index a47574c..f694ec3 100644 --- a/multiplayer-game/src/engine/Renderer.cs +++ b/multiplayer-game/src/engine/Renderer.cs @@ -108,4 +108,15 @@ class Renderer { return SDL_CreateTextureFromSurface(renderer, surface); } + + public void DrawTexture(IntPtr texture, int x, int y, int w, int h) + { + SDL_Rect rect = new SDL_Rect(); + rect.x = x; + rect.y = y; + rect.w = w; + rect.h = h; + + SDL_RenderCopy(renderer, texture, IntPtr.Zero, ref rect); + } } diff --git a/multiplayer-game/src/engine/Window.cs b/multiplayer-game/src/engine/Window.cs index 671a375..64e2aa3 100644 --- a/multiplayer-game/src/engine/Window.cs +++ b/multiplayer-game/src/engine/Window.cs @@ -38,4 +38,9 @@ class Window SDL_GetWindowSize(this.window, out w, out h); return (w, h); } + + public IntPtr GetRaw() + { + return this.window; + } } diff --git a/multiplayer-game/src/frontend/Frontend.cs b/multiplayer-game/src/frontend/Frontend.cs index 0b5646d..d61b1be 100644 --- a/multiplayer-game/src/frontend/Frontend.cs +++ b/multiplayer-game/src/frontend/Frontend.cs @@ -4,12 +4,16 @@ using static SDL2.SDL; class Frontend : IFrontend { private string playerName = "Player"; + private bool fullscreen = false; public void Init() { this.playerName = Context.Get().IsHost ? "Host" : "Client"; - var conntectPacket = new ConnectPacket(playerName); - Context.Get().Backend.ProcessPacket(conntectPacket); + var guid = Guid.NewGuid(); + Context.Get().FrontendGameState.PlayerGuid = guid; + var connectPacket = new ConnectPacket(playerName, guid); + Context.Get().Backend.ProcessPacket(connectPacket); + Context.Get().TileRegistry.RegisterTile(); } public void Process() @@ -21,9 +25,33 @@ class Frontend : IFrontend { System.Environment.Exit(0); } + if (e.type == SDL_EventType.SDL_WINDOWEVENT) + { + if (e.window.windowEvent == SDL_WindowEventID.SDL_WINDOWEVENT_RESIZED) + { + ctx.FrontendGameState.WindowWidth = e.window.data1; + ctx.FrontendGameState.WindowHeight = e.window.data2; + Console.WriteLine($"Window resized to {e.window.data1}x{e.window.data2}"); + } + } if (e.type == SDL_EventType.SDL_KEYDOWN && e.key.repeat == 0) { - var movementInput = ctx.FrontendGameState.movementInput; + var movementInput = ctx.FrontendGameState.MovementInput; + if (e.key.keysym.scancode == SDL_Scancode.SDL_SCANCODE_F11) + { + if (!fullscreen) + { + SDL_SetWindowFullscreen( + ctx.Window.GetRaw(), + (uint)SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP + ); + } + else + { + SDL_SetWindowFullscreen(ctx.Window.GetRaw(), 0); + } + fullscreen = !fullscreen; + } if (e.key.keysym.scancode == SDL_Scancode.SDL_SCANCODE_A) { movementInput.X -= 1; @@ -40,11 +68,11 @@ class Frontend : IFrontend { movementInput.Y += 1; } - ctx.FrontendGameState.movementInput = movementInput; + ctx.FrontendGameState.MovementInput = movementInput; } if (e.type == SDL_EventType.SDL_KEYUP && e.key.repeat == 0) { - var movementInput = ctx.FrontendGameState.movementInput; + var movementInput = ctx.FrontendGameState.MovementInput; if (e.key.keysym.scancode == SDL_Scancode.SDL_SCANCODE_A) { movementInput.X += 1; @@ -61,7 +89,7 @@ class Frontend : IFrontend { movementInput.Y -= 1; } - ctx.FrontendGameState.movementInput = movementInput; + ctx.FrontendGameState.MovementInput = movementInput; } if ( e.key.keysym.scancode @@ -75,7 +103,7 @@ class Frontend : IFrontend { if (e.key.repeat == 1) continue; - var movement = ctx.FrontendGameState.movementInput; + var movement = ctx.FrontendGameState.MovementInput; if (movement.Length() > 0) movement = Vector2.Normalize(movement); ctx.Backend.ProcessPacket(new MovePacket(playerName, movement)); @@ -87,6 +115,7 @@ class Frontend : IFrontend } ctx.Renderer.Clear(); + new WorldRenderer().Render(); ctx.GameState.PlayerPositions.ForEach(player => { if (player.name == playerName) diff --git a/multiplayer-game/src/frontend/renderer/IRenderer.cs b/multiplayer-game/src/frontend/renderer/IRenderer.cs new file mode 100644 index 0000000..7423328 --- /dev/null +++ b/multiplayer-game/src/frontend/renderer/IRenderer.cs @@ -0,0 +1,4 @@ +interface IRenderer +{ + public void Render(); +} diff --git a/multiplayer-game/src/frontend/renderer/WorldRenderer.cs b/multiplayer-game/src/frontend/renderer/WorldRenderer.cs new file mode 100644 index 0000000..3c9a5c8 --- /dev/null +++ b/multiplayer-game/src/frontend/renderer/WorldRenderer.cs @@ -0,0 +1,22 @@ +class WorldRenderer : IRenderer +{ + public void Render() + { + var ctx = Context.Get(); + var world = ctx.GameState.World; + var renderer = ctx.Renderer; + var tileRegistry = ctx.TileRegistry; + foreach (var (_, chunk) in world.Chunks) + { + for (int y = 0; y < 16; y++) + { + for (int x = 0; x < 16; x++) + { + var tileId = chunk.Tiles[x][y]; + var tile = tileRegistry.GetTile(tileId); + tile.Render(x * 16, y * 16); + } + } + } + } +} diff --git a/multiplayer-game/src/state/GameState.cs b/multiplayer-game/src/state/GameState.cs index f3f8131..d2abb3b 100644 --- a/multiplayer-game/src/state/GameState.cs +++ b/multiplayer-game/src/state/GameState.cs @@ -5,14 +5,27 @@ class Player public string name; public Vector2 position; public Vector2 movement; + public Guid guid; } class FrontendGameState { - public Vector2 movementInput; + public Vector2 MovementInput; + public Vector2 CameraPosition; + public int WindowWidth; + public int WindowHeight; + public Guid PlayerGuid; +} + +class Settings +{ + public int GameScale = 4; + public int UIScale = 4; } class GameState { public List PlayerPositions { get; set; } = new List(); + public World World { get; set; } + public Settings Settings { get; set; } = new Settings(); }