diff --git a/.gitignore b/.gitignore index fea8d3f..fa6f4c7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ .config/ .vscode/ -src/bin -src/**/obj \ No newline at end of file +**/bin/ +**/obj/ \ No newline at end of file diff --git a/Content/Content.mgcb b/Content/Content.mgcb new file mode 100644 index 0000000..15f5d4e --- /dev/null +++ b/Content/Content.mgcb @@ -0,0 +1,30 @@ + +#----------------------------- Global Properties ----------------------------# + +/outputDir:bin/$(Platform) +/intermediateDir:obj/$(Platform) +/platform:DesktopGL +/config: +/profile:Reach +/compress:False + +#-------------------------------- References --------------------------------# + + +#---------------------------------- Content ---------------------------------# + +#begin images/atlas-definition.xml +/copy:images/atlas-definition.xml + +#begin images/atlas.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:images/atlas.png + diff --git a/Content/images/atlas-definition.xml b/Content/images/atlas-definition.xml new file mode 100755 index 0000000..4002841 --- /dev/null +++ b/Content/images/atlas-definition.xml @@ -0,0 +1,7 @@ + + + images/atlas + + + + diff --git a/Content/images/atlas.kra b/Content/images/atlas.kra new file mode 100644 index 0000000..32e204d Binary files /dev/null and b/Content/images/atlas.kra differ diff --git a/Content/images/atlas.png b/Content/images/atlas.png new file mode 100644 index 0000000..02346da Binary files /dev/null and b/Content/images/atlas.png differ diff --git a/Game1.cs b/Game1.cs new file mode 100644 index 0000000..2715c9e --- /dev/null +++ b/Game1.cs @@ -0,0 +1,140 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; + +using MonoGameLibrary; +using MonoGameLibrary.Graphics; + +// using tunnet.World; + +namespace tunnet; + +public class Game1 : Core +{ + // private World.Map _world; + // private Texture2D _logo; + + public Game1() : base("Tunnet but not", 1280, 720, fullScreen: false) + { + // Content.RootDirectory = "Content"; + // IsMouseVisible = true; + } + + protected override void Initialize() + { + // TODO: Add your initialization logic here + // _world = new World.Map(mapId: 0); + // _world.LoadMap(); + // + + base.Initialize(); + } + + private Sprite _404; + // private AnimatedSprite _animatedSprite; + protected override void LoadContent() + { + TextureAtlas atlas = TextureAtlas.FromFile(Content, "images/atlas-definition.xml"); + + _404 = atlas.CreateSprite("404"); + // _animatedSprite = atlas.CreateAnimatedSprite("404"); + } + + private const int _CAMERA_SPEED = 5; + Viewport _cameraPosition; + Point _mousePosition; + protected override void Update(GameTime gameTime) + { + if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) + Exit(); + + // TODO: Add your update logic here + + // Animations + // _animatedSprite.Update(gameTime); + + // Inputs + // https://docs.monogame.net/articles/tutorials/building_2d_games/10_handling_input/ + + if (_cameraPosition.Equals(new Viewport())) _cameraPosition = GraphicsDevice.Viewport; + + CheckKeyboardInput(); + CheckMouseInput(); + + base.Update(gameTime); + } + private void CheckKeyboardInput() + { + // Get the state of keyboard input + KeyboardState keyboardState = Keyboard.GetState(); + + // If the space key is held down, the movement speed increases by 1.5 + int speed = _CAMERA_SPEED; + if (keyboardState.IsKeyDown(Keys.Space)) + { + speed = (int)Math.Floor(speed * 1.5); + } + if (keyboardState.IsKeyDown(Keys.W) || keyboardState.IsKeyDown(Keys.Up)) + { + _cameraPosition.Y += speed; + } + if (keyboardState.IsKeyDown(Keys.S) || keyboardState.IsKeyDown(Keys.Down)) + { + _cameraPosition.Y -= speed; + } + if (keyboardState.IsKeyDown(Keys.A) || keyboardState.IsKeyDown(Keys.Left)) + { + _cameraPosition.X += speed; + } + if (keyboardState.IsKeyDown(Keys.D) || keyboardState.IsKeyDown(Keys.Right)) + { + _cameraPosition.X -= speed; + } + // + GraphicsDevice.Viewport = _cameraPosition; + } + private void CheckMouseInput() + { + // Get the state of mouse input + MouseState mouseState = Mouse.GetState(); + + //Move camera with right mouse button + if (mouseState.RightButton == ButtonState.Pressed) + { + _mousePosition -= mouseState.Position; // delta + + _cameraPosition!.X = _cameraPosition.X - _mousePosition.X; + _cameraPosition.Y = _cameraPosition.Y - _mousePosition.Y; + } + // + GraphicsDevice.Viewport = _cameraPosition; + _mousePosition = mouseState.Position; // here because of wasd breaking it + } + + protected override void Draw(GameTime gameTime) + { + GraphicsDevice.Clear(Color.CornflowerBlue); + + SpriteBatch.Begin(sortMode: SpriteSortMode.Deferred); + + // World.Map.Draw draw = new World.Map.Draw(in _spriteBatch); //TODO: fix + // _spriteBatch.Draw(_world._defaultTile, _world._defaultTile.Bounds.Center.ToVector2(), Color.White); //TODO: fix + + /// TODO: Draw + /// 1. floor + /// 2. wires + /// 3. buildings + /// 4. entities + /// 5. walls + /// + /// MINIMIZE texture swaps + /// MAXIMIZE drawRectangle usage per texture + + _404.Draw(SpriteBatch, Vector2.Zero); + + SpriteBatch.End(); + // + base.Draw(gameTime); + } +} diff --git a/src/Icon.bmp b/Icon.bmp similarity index 100% rename from src/Icon.bmp rename to Icon.bmp diff --git a/src/Icon.ico b/Icon.ico similarity index 100% rename from src/Icon.ico rename to Icon.ico diff --git a/src/Program.cs b/Program.cs similarity index 100% rename from src/Program.cs rename to Program.cs diff --git a/World/World.cs b/World/World.cs new file mode 100644 index 0000000..693b544 --- /dev/null +++ b/World/World.cs @@ -0,0 +1,210 @@ +// using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using Microsoft.Xna.Framework; +// using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; + +namespace tunnet.World; + +struct World +{ + private class Tile // TODO: sprite, buildings[] + { + public int Id { get; } + public Point point { get; } + + public Tile(int id) => Id = id; + public static Tile FromId(int id) + { + return new Tile(id); + } + } + private class Chunk + { + public const int Width = 32; + public const int Height = 32; + internal Tile[,] Tiles { get; private set; } + + public Chunk() + { + Tiles = new Tile[Width, Height]; + } + } + private static class ChunkStorage + { + /// + /// Saves the given chunk to disk in a compact binary format: + /// Width×Height consecutive Int32 tile IDs. + /// + public static void Save(string filePath, Chunk chunk) + { + if (chunk == null) + throw new System.ArgumentNullException(nameof(chunk)); + + Directory.CreateDirectory(Path.GetDirectoryName(filePath) ?? "."); + using var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write); + using var writer = new BinaryWriter(fs); + + for (int x = 0; x < Chunk.Width; x++) + { + for (int y = 0; y < Chunk.Height; y++) + { + // write each tile’s ID + writer.Write(chunk.Tiles[x, y]?.Id ?? 0); + } + } + } + public static void Save(int chunkX, int chunkY, Chunk chunk) + { + Save($"{chunkX}_{chunkY}.chunk", chunk); + } + + /// + /// Loads a chunk from the binary file format produced by Save(). + /// + public static Chunk Load(string filePath) + { + if (!File.Exists(filePath)) + throw new FileNotFoundException("Chunk file not found", filePath); + //TODO generate chunk instead + + var chunk = new Chunk(); + using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); + using var reader = new BinaryReader(fs); + + for (int x = 0; x < Chunk.Width; x++) + for (int y = 0; y < Chunk.Height; y++) + { + int id = reader.ReadInt32(); + chunk.Tiles[x, y] = Tile.FromId(id); + } + + return chunk; + } + public static Chunk Load(Point location) + { + var filePath = $"{location.X}_{location.Y}.chunk"; + if (File.Exists(filePath)) + return Load(filePath); + return null; + } + } + public class Map + { + private readonly Dictionary _loadedChunks = new Dictionary(); + private IReadOnlyDictionary Chunks => _loadedChunks; + private Mutex _loadWait = new(); + private readonly int id; + // private readonly int TileSize; + // public Texture2D _defaultTile; + + public Map(int mapId) + { + id = mapId; + // TileSize = 32; + } + + // Load the map by ID + public void LoadMap() + { + //TODO: Load map by ID + } + + // Generate a new map + private void GenerateMap() + { + //TODO: Implement map generation + } + + // Get a chunk (load if not in memory) + private Chunk GetChunk(Point location) + { + // var key = new Point(chunkX, chunkY); + if (!_loadedChunks.TryGetValue(location, out Chunk chunk)) + { + chunk = ChunkStorage.Load(location);// LoadChunkFromDisk(chunkX, chunkY); // Or generate + _loadedChunks[location] = chunk; + } + return chunk; + } + + // Access a specific tile + private Tile GetTile(int worldX, int worldY) + { + int chunkX = worldX / Chunk.Width; + int chunkY = worldY / Chunk.Height; + int tileX = worldX % Chunk.Width; + int tileY = worldY % Chunk.Height; + + // Handle negative coordinates + if (tileX < 0) tileX += Chunk.Width; + if (tileY < 0) tileY += Chunk.Height; + + return GetChunk(new Point(chunkX, chunkY)).Tiles[tileX, tileY]; + } + + // Unload distant chunks (memory management) + public void UnloadChunks(Point currentChunk, int keepRadius) + { + var keysToRemove = new List(); + foreach (var key in _loadedChunks.Keys) + { + if (System.Math.Abs(key.X - currentChunk.X) > keepRadius || + System.Math.Abs(key.Y - currentChunk.Y) > keepRadius) + { + ChunkStorage.Save(key.X, key.Y, _loadedChunks[key]); // Persist if needed + keysToRemove.Add(key); + } + } + keysToRemove.ForEach(k => _loadedChunks.Remove(k)); + } + + /*public class Draw(in SpriteBatch spriteBatch) + { + private SpriteBatch spriteBatch = spriteBatch; + }*/ + + // private ref struct Draw + // { + // private ref SpriteBatch _spriteBatch; + // public Draw(ref SpriteBatch spriteBatch) + // { + // _spriteBatch = ref spriteBatch; + // } + // } + + // private readonly IReadOnlyDictionary _chunks; + + /*public void Draw() + { + if (_chunks.Count == 0) + { + Console.WriteLine("No chunks loaded"); + return; + } + foreach (var kvp in _chunks) + { + Point chunkCoord = kvp.Key; + // var chunk = kvp.Value; + + for (int cx = 0; cx < Chunk.Width; cx++) + { + for (int cy = 0; cy < Chunk.Height; cy++) + { + // world‐space position in pixels + Vector2 pos = new Vector2( + (chunkCoord.X * Chunk.Width + cx) * TileSize, + (chunkCoord.Y * Chunk.Height + cy) * TileSize + ); + + // draw the default tile for now + Console.WriteLine("Sprite location: ", pos); + _spriteBatch.Draw(_defaultTile, pos, Color.White); + } + } + } + }*/ + } +} diff --git a/src/app.manifest b/app.manifest similarity index 100% rename from src/app.manifest rename to app.manifest diff --git a/run.sh b/run.sh index ef64ddd..47c536a 100755 --- a/run.sh +++ b/run.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash echo "Running..." -exec dotnet run --no-build --project src/ +exec dotnet run --no-build diff --git a/src/Content/Content.mgcb b/src/Content/Content.mgcb deleted file mode 100644 index ddc4c36..0000000 --- a/src/Content/Content.mgcb +++ /dev/null @@ -1,15 +0,0 @@ - -#----------------------------- Global Properties ----------------------------# - -/outputDir:bin/$(Platform) -/intermediateDir:obj/$(Platform) -/platform:DesktopGL -/config: -/profile:Reach -/compress:False - -#-------------------------------- References --------------------------------# - - -#---------------------------------- Content ---------------------------------# - diff --git a/src/Game1.cs b/src/Game1.cs deleted file mode 100644 index 061b2b7..0000000 --- a/src/Game1.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using Microsoft.Xna.Framework.Input; - -namespace tunnet; - -public class Game1 : Game -{ - private GraphicsDeviceManager _graphics; - private SpriteBatch _spriteBatch; - - public Game1() - { - _graphics = new GraphicsDeviceManager(this); - Content.RootDirectory = "Content"; - IsMouseVisible = true; - } - - protected override void Initialize() - { - // TODO: Add your initialization logic here - - base.Initialize(); - } - - protected override void LoadContent() - { - _spriteBatch = new SpriteBatch(GraphicsDevice); - - // TODO: use this.Content to load your game content here - } - - protected override void Update(GameTime gameTime) - { - if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) - Exit(); - - // TODO: Add your update logic here - - base.Update(gameTime); - } - - protected override void Draw(GameTime gameTime) - { - GraphicsDevice.Clear(Color.CornflowerBlue); - - // TODO: Add your drawing code here - - base.Draw(gameTime); - } -} diff --git a/tunnet.code-workspace b/tunnet.code-workspace new file mode 100644 index 0000000..de141ec --- /dev/null +++ b/tunnet.code-workspace @@ -0,0 +1,11 @@ +{ + "folders": [ + { + "path": "." + }, + { + "path": "../lib-bird" + } + ], + "settings": {} +} \ No newline at end of file diff --git a/src/tunnet.csproj b/tunnet.csproj similarity index 90% rename from src/tunnet.csproj rename to tunnet.csproj index 06680d2..3a77701 100644 --- a/src/tunnet.csproj +++ b/tunnet.csproj @@ -5,6 +5,7 @@ Major false false + app.manifest @@ -26,6 +27,9 @@ + + + diff --git a/tunnet.sln b/tunnet.sln index aa36c25..e3c59bc 100644 --- a/tunnet.sln +++ b/tunnet.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tunnet", "src/tunnet.csproj", "{728D0B55-232F-4C2B-A31F-04EA4BFF4209}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tunnet", "tunnet.csproj", "{728D0B55-232F-4C2B-A31F-04EA4BFF4209}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution