added first tile render + fullscreen

This commit is contained in:
MasterGordon 2022-10-31 01:50:13 +01:00
parent e1a8c9410d
commit 74245c8409
22 changed files with 265 additions and 26 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

View File

@ -9,7 +9,7 @@
<TrimmerDefaultAction>link</TrimmerDefaultAction> <TrimmerDefaultAction>link</TrimmerDefaultAction>
<PublishReadyToRun>true</PublishReadyToRun> <PublishReadyToRun>true</PublishReadyToRun>
<PublishSingleFile>true</PublishSingleFile> <PublishSingleFile>true</PublishSingleFile>
<Nullable>enable</Nullable> <Nullable>disable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -7,7 +7,9 @@ class Context
public FrontendGameState FrontendGameState { get; set; } public FrontendGameState FrontendGameState { get; set; }
public Window Window { get; set; } public Window Window { get; set; }
public Renderer Renderer { 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( public Context(
bool isHost, bool isHost,
@ -26,6 +28,8 @@ class Context
this.FrontendGameState = frontendGameState; this.FrontendGameState = frontendGameState;
this.Renderer = renderer; this.Renderer = renderer;
this.Window = window; this.Window = window;
this.TileRegistry = new TileRegistry();
this.ResourceLoader = new ResourceLoader();
Context.instance = this; Context.instance = this;
} }

View File

@ -29,6 +29,7 @@ class MultiPlayerGame : Game
window window
); );
} }
Bootstrapper.Bootstrap();
ctx.Backend.Init(); ctx.Backend.Init();
ctx.Frontend.Init(); ctx.Frontend.Init();
} }

View File

@ -1,4 +1,3 @@
using System.Numerics;
using System.Text; using System.Text;
using Newtonsoft.Json; using Newtonsoft.Json;
using WatsonTcp; using WatsonTcp;
@ -8,20 +7,17 @@ class Backend : IBackend
private WatsonTcpServer server; private WatsonTcpServer server;
private Publisher publisher; private Publisher publisher;
private Queue<ValueType> pendingPackets = new Queue<ValueType>(); private Queue<ValueType> pendingPackets = new Queue<ValueType>();
private uint tick = 0;
public void Process(double dt) public void Process(double dt)
{ {
var ctx = Context.Get(); var ctx = Context.Get();
this.ProcessPacket(new TickPacket(tick++));
while (pendingPackets.Count > 0) while (pendingPackets.Count > 0)
{ {
var packet = pendingPackets.Dequeue(); var packet = pendingPackets.Dequeue();
this.ProcessPacket(packet); this.ProcessPacket(packet);
} }
ctx.GameState.PlayerPositions.ForEach(player =>
{
player.position += player.movement;
});
// this.sendGameState();
} }
public void ProcessPacket(ValueType packet) public void ProcessPacket(ValueType packet)
@ -33,9 +29,7 @@ class Backend : IBackend
public void Init() public void Init()
{ {
Task.Run(Run); Task.Run(Run);
this.publisher = new Publisher( this.publisher = new Publisher(InteractorKind.Server);
Context.Get().IsHost ? InteractorKind.Server : InteractorKind.Client
);
} }
public void Run() public void Run()
@ -47,7 +41,7 @@ class Backend : IBackend
server.Start(); server.Start();
} }
private void clientConnected(object? sender, ConnectionEventArgs args) private void clientConnected(object sender, ConnectionEventArgs args)
{ {
Console.WriteLine("Client connected: " + args.IpPort); Console.WriteLine("Client connected: " + args.IpPort);
var gameState = Context.Get().GameState; 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); Console.WriteLine("Client disconnected: " + args.IpPort);
} }
private void messageReceived(object? sender, MessageReceivedEventArgs args) private void messageReceived(object sender, MessageReceivedEventArgs args)
{ {
var time = DateTime.Now; var time = DateTime.Now;
Console.WriteLine("Message Received: " + args.IpPort); Console.WriteLine("Message Received: " + args.IpPort);

View File

@ -5,18 +5,24 @@ using System.Text;
class RemoteBackend : IBackend class RemoteBackend : IBackend
{ {
private WatsonTcpClient client; private WatsonTcpClient client;
private Publisher publisher;
private Queue<ValueType> pendingPackets = new Queue<ValueType>();
private uint tick = 0;
public void Process(double dt) public void Process(double dt)
{ {
var ctx = Context.Get(); 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) public void ProcessPacket(ValueType packet)
{ {
this.publisher.Publish(packet);
var json = JsonConvert.SerializeObject(packet); var json = JsonConvert.SerializeObject(packet);
var bytes = Encoding.UTF8.GetBytes(json); var bytes = Encoding.UTF8.GetBytes(json);
client.Send(bytes); client.Send(bytes);
@ -25,6 +31,7 @@ class RemoteBackend : IBackend
public void Init() public void Init()
{ {
Task.Run(this.Run); Task.Run(this.Run);
this.publisher = new Publisher(InteractorKind.Client);
} }
public void Run() public void Run()

View File

@ -17,9 +17,22 @@ readonly struct ConnectPacket
{ {
public readonly string type = "connect"; public readonly string type = "connect";
public readonly string playerName; public readonly string playerName;
public readonly Guid playerGuid;
public ConnectPacket(string playerName) public ConnectPacket(string playerName, Guid playerGuid)
{ {
this.playerName = playerName; 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;
} }
} }

View File

@ -14,6 +14,7 @@ class Connect
new Player new Player
{ {
name = packet.playerName, name = packet.playerName,
guid = packet.playerGuid,
position = new Vector2(0, 0), position = new Vector2(0, 0),
movement = new Vector2(0, 0) movement = new Vector2(0, 0)
} }

View File

@ -11,4 +11,14 @@ class Move
player.movement = packet.movement * 4; 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;
});
}
} }

View File

@ -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));
}
}

View File

@ -0,0 +1,4 @@
class Constants
{
public const int ChunkSize = 32;
}

View File

@ -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;
}
}

View File

@ -0,0 +1,19 @@
class World
{
public Dictionary<string, Chunk> Chunks { get; set; } = new Dictionary<string, Chunk>();
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);
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,19 @@
enum Tiles : int
{
stone = 1,
}
class TileRegistry
{
public Dictionary<int, Tile> Tiles { get; set; } = new Dictionary<int, Tile>();
public void RegisterTile()
{
Tiles.Add(1, new Tile("stone", "stone"));
}
public Tile GetTile(int id)
{
return Tiles[id];
}
}

View File

@ -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);
}
}

View File

@ -108,4 +108,15 @@ class Renderer
{ {
return SDL_CreateTextureFromSurface(renderer, surface); 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);
}
} }

View File

@ -38,4 +38,9 @@ class Window
SDL_GetWindowSize(this.window, out w, out h); SDL_GetWindowSize(this.window, out w, out h);
return (w, h); return (w, h);
} }
public IntPtr GetRaw()
{
return this.window;
}
} }

View File

@ -4,12 +4,16 @@ using static SDL2.SDL;
class Frontend : IFrontend class Frontend : IFrontend
{ {
private string playerName = "Player"; private string playerName = "Player";
private bool fullscreen = false;
public void Init() public void Init()
{ {
this.playerName = Context.Get().IsHost ? "Host" : "Client"; this.playerName = Context.Get().IsHost ? "Host" : "Client";
var conntectPacket = new ConnectPacket(playerName); var guid = Guid.NewGuid();
Context.Get().Backend.ProcessPacket(conntectPacket); Context.Get().FrontendGameState.PlayerGuid = guid;
var connectPacket = new ConnectPacket(playerName, guid);
Context.Get().Backend.ProcessPacket(connectPacket);
Context.Get().TileRegistry.RegisterTile();
} }
public void Process() public void Process()
@ -21,9 +25,33 @@ class Frontend : IFrontend
{ {
System.Environment.Exit(0); 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) 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) if (e.key.keysym.scancode == SDL_Scancode.SDL_SCANCODE_A)
{ {
movementInput.X -= 1; movementInput.X -= 1;
@ -40,11 +68,11 @@ class Frontend : IFrontend
{ {
movementInput.Y += 1; movementInput.Y += 1;
} }
ctx.FrontendGameState.movementInput = movementInput; ctx.FrontendGameState.MovementInput = movementInput;
} }
if (e.type == SDL_EventType.SDL_KEYUP && e.key.repeat == 0) 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) if (e.key.keysym.scancode == SDL_Scancode.SDL_SCANCODE_A)
{ {
movementInput.X += 1; movementInput.X += 1;
@ -61,7 +89,7 @@ class Frontend : IFrontend
{ {
movementInput.Y -= 1; movementInput.Y -= 1;
} }
ctx.FrontendGameState.movementInput = movementInput; ctx.FrontendGameState.MovementInput = movementInput;
} }
if ( if (
e.key.keysym.scancode e.key.keysym.scancode
@ -75,7 +103,7 @@ class Frontend : IFrontend
{ {
if (e.key.repeat == 1) if (e.key.repeat == 1)
continue; continue;
var movement = ctx.FrontendGameState.movementInput; var movement = ctx.FrontendGameState.MovementInput;
if (movement.Length() > 0) if (movement.Length() > 0)
movement = Vector2.Normalize(movement); movement = Vector2.Normalize(movement);
ctx.Backend.ProcessPacket(new MovePacket(playerName, movement)); ctx.Backend.ProcessPacket(new MovePacket(playerName, movement));
@ -87,6 +115,7 @@ class Frontend : IFrontend
} }
ctx.Renderer.Clear(); ctx.Renderer.Clear();
new WorldRenderer().Render();
ctx.GameState.PlayerPositions.ForEach(player => ctx.GameState.PlayerPositions.ForEach(player =>
{ {
if (player.name == playerName) if (player.name == playerName)

View File

@ -0,0 +1,4 @@
interface IRenderer
{
public void Render();
}

View File

@ -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);
}
}
}
}
}

View File

@ -5,14 +5,27 @@ class Player
public string name; public string name;
public Vector2 position; public Vector2 position;
public Vector2 movement; public Vector2 movement;
public Guid guid;
} }
class FrontendGameState 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 class GameState
{ {
public List<Player> PlayerPositions { get; set; } = new List<Player>(); public List<Player> PlayerPositions { get; set; } = new List<Player>();
public World World { get; set; }
public Settings Settings { get; set; } = new Settings();
} }