added first tile render + fullscreen
This commit is contained in:
parent
e1a8c9410d
commit
74245c8409
Binary file not shown.
|
After Width: | Height: | Size: 454 B |
|
|
@ -9,7 +9,7 @@
|
|||
<TrimmerDefaultAction>link</TrimmerDefaultAction>
|
||||
<PublishReadyToRun>true</PublishReadyToRun>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<Nullable>enable</Nullable>
|
||||
<Nullable>disable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ class MultiPlayerGame : Game
|
|||
window
|
||||
);
|
||||
}
|
||||
Bootstrapper.Bootstrap();
|
||||
ctx.Backend.Init();
|
||||
ctx.Frontend.Init();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ValueType> pendingPackets = new Queue<ValueType>();
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -5,18 +5,24 @@ using System.Text;
|
|||
class RemoteBackend : IBackend
|
||||
{
|
||||
private WatsonTcpClient client;
|
||||
private Publisher publisher;
|
||||
private Queue<ValueType> pendingPackets = new Queue<ValueType>();
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ class Connect
|
|||
new Player
|
||||
{
|
||||
name = packet.playerName,
|
||||
guid = packet.playerGuid,
|
||||
position = new Vector2(0, 0),
|
||||
movement = new Vector2(0, 0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
class Constants
|
||||
{
|
||||
public const int ChunkSize = 32;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,4 +38,9 @@ class Window
|
|||
SDL_GetWindowSize(this.window, out w, out h);
|
||||
return (w, h);
|
||||
}
|
||||
|
||||
public IntPtr GetRaw()
|
||||
{
|
||||
return this.window;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
interface IRenderer
|
||||
{
|
||||
public void Render();
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Player> PlayerPositions { get; set; } = new List<Player>();
|
||||
public World World { get; set; }
|
||||
public Settings Settings { get; set; } = new Settings();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue