From eec346349b58b6816a64d790c35cdfa93f6d9aab Mon Sep 17 00:00:00 2001 From: danilwhale Date: Wed, 18 Oct 2023 10:34:27 +0300 Subject: [PATCH 001/107] cleanup branch --- BuildingGame.csproj | 4 + ConfigParser.cs | 70 ----- Gui.cs | 104 -------- GuiElements/BackgroundBlock.cs | 20 -- GuiElements/Brushes/ColorBrush.cs | 19 -- GuiElements/Brushes/GradientBrush.cs | 18 -- GuiElements/Brushes/IBrush.cs | 6 - GuiElements/CheckBox.cs | 36 --- GuiElements/Control.cs | 70 ----- GuiElements/ControlInfo.cs | 17 -- GuiElements/HoverButton.cs | 35 --- GuiElements/ImageArea.cs | 26 -- GuiElements/InputBox.cs | 77 ------ GuiElements/ListView.cs | 75 ------ GuiElements/RgbBoxLine.cs | 92 ------- GuiElements/TextBlock.cs | 59 ----- GuiElements/Tooltip.cs | 52 ---- LICENSE | 21 -- Program.cs | 188 -------------- README.md | 15 -- Screens/CreateWorldScreen.cs | 59 ----- Screens/GameScreen.cs | 285 --------------------- Screens/MenuScreen.cs | 144 ----------- Screens/Screen.cs | 8 - Screens/SelectPackScreen.cs | 78 ------ Screens/WorldSelectScreen.cs | 91 ------- Screenshot.cs | 14 - Settings.cs | 73 ------ TilePacks/TilePack.cs | 83 ------ TilePacks/TilePackManager.cs | 47 ---- Tiles/Chunk.cs | 43 ---- Tiles/PhysicTileType.cs | 12 - Tiles/Tile.cs | 92 ------- Tiles/TileFlags.cs | 14 - Tiles/TileInfo.cs | 23 -- Tiles/World.cs | 368 --------------------------- assets/atlas.png | Bin 8474 -> 0 bytes assets/atlas.txt | 41 --- assets/check.png | Bin 205 -> 0 bytes assets/font.ttf | Bin 18704 -> 0 bytes assets/font_old.ttf | Bin 10252 -> 0 bytes assets/icon.ico | Bin 95415 -> 0 bytes assets/icon.png | Bin 301 -> 0 bytes 43 files changed, 4 insertions(+), 2475 deletions(-) delete mode 100644 ConfigParser.cs delete mode 100644 Gui.cs delete mode 100644 GuiElements/BackgroundBlock.cs delete mode 100644 GuiElements/Brushes/ColorBrush.cs delete mode 100644 GuiElements/Brushes/GradientBrush.cs delete mode 100644 GuiElements/Brushes/IBrush.cs delete mode 100644 GuiElements/CheckBox.cs delete mode 100644 GuiElements/Control.cs delete mode 100644 GuiElements/ControlInfo.cs delete mode 100644 GuiElements/HoverButton.cs delete mode 100644 GuiElements/ImageArea.cs delete mode 100644 GuiElements/InputBox.cs delete mode 100644 GuiElements/ListView.cs delete mode 100644 GuiElements/RgbBoxLine.cs delete mode 100644 GuiElements/TextBlock.cs delete mode 100644 GuiElements/Tooltip.cs delete mode 100644 LICENSE delete mode 100644 Program.cs delete mode 100644 README.md delete mode 100644 Screens/CreateWorldScreen.cs delete mode 100644 Screens/GameScreen.cs delete mode 100644 Screens/MenuScreen.cs delete mode 100644 Screens/Screen.cs delete mode 100644 Screens/SelectPackScreen.cs delete mode 100644 Screens/WorldSelectScreen.cs delete mode 100644 Screenshot.cs delete mode 100644 Settings.cs delete mode 100644 TilePacks/TilePack.cs delete mode 100644 TilePacks/TilePackManager.cs delete mode 100644 Tiles/Chunk.cs delete mode 100644 Tiles/PhysicTileType.cs delete mode 100644 Tiles/Tile.cs delete mode 100644 Tiles/TileFlags.cs delete mode 100644 Tiles/TileInfo.cs delete mode 100644 Tiles/World.cs delete mode 100644 assets/atlas.png delete mode 100644 assets/atlas.txt delete mode 100644 assets/check.png delete mode 100644 assets/font.ttf delete mode 100644 assets/font_old.ttf delete mode 100644 assets/icon.ico delete mode 100644 assets/icon.png diff --git a/BuildingGame.csproj b/BuildingGame.csproj index 7f1e567..553143f 100644 --- a/BuildingGame.csproj +++ b/BuildingGame.csproj @@ -38,4 +38,8 @@ + + <_DeploymentManifestIconFile Remove="assets\icon.ico" /> + + diff --git a/ConfigParser.cs b/ConfigParser.cs deleted file mode 100644 index 109c741..0000000 --- a/ConfigParser.cs +++ /dev/null @@ -1,70 +0,0 @@ -namespace BuildingGame; - -public static class ConfigParser -{ - public static Dictionary Parse(string fileName) - { - var dict = new Dictionary(); - if (!File.Exists(fileName)) return dict; - - foreach (var line in File.ReadAllLines(fileName)) - { - string[] kv = line.Split(':'); - if (kv.Length > 2 || kv.Length < 2) continue; - dict.Add(kv[0].Trim(), kv[1].Trim()); - } - - return dict; - } - - public static Dictionary ParseTriple(string fileName) - { - var dict = new Dictionary(); - if (!File.Exists(fileName)) return dict; - - foreach (var line in File.ReadAllLines(fileName)) - { - string[] kv = line.Split(':'); - if (kv.Length != 3) continue; - dict.Add(kv[0].Trim(), (kv[1].Trim(), kv[2].Trim())); - } - - return dict; - } - - public static Dictionary ParseFourth(string fileName) - { - var dict = new Dictionary(); - if (!File.Exists(fileName)) return dict; - - foreach (var line in File.ReadAllLines(fileName)) - { - string[] kv = line.Split(':'); - if (kv.Length != 4) continue; - dict.Add(kv[0].Trim(), (kv[1].Trim(), kv[2].Trim(), kv[3].Trim())); - } - - return dict; - } - - public static void Write(string fileName, Dictionary data) - { - List strList = new List(); - - foreach (var key in data.Keys) - { - strList.Add($"{key}:{data[key]}"); - } - - File.WriteAllLines(fileName, strList.ToArray()); - } - - public static Vector2 ToVector2i(string str) - { - string[] xy = str.Split(','); - if (xy.Length < 2) return new Vector2(0, 0); - if (int.TryParse(xy[0], out int x) && int.TryParse(xy[1], out int y)) - return new(x, y); - return new Vector2(0, 0); - } -} \ No newline at end of file diff --git a/Gui.cs b/Gui.cs deleted file mode 100644 index 2a3a2ce..0000000 --- a/Gui.cs +++ /dev/null @@ -1,104 +0,0 @@ -namespace BuildingGame; - -public static class Gui -{ - public static Font GuiFont => _font; - public static bool ProcessGui { get; set; } = true; - private static Font _font; - - private static List _controls = - new List(); - - public static void SetGuiFont(Font font) - { - _font = font; - } - public static void SetGuiFont(string fileName) - { - _font = LoadFont(fileName); - } - public static void UnloadGuiFont() => UnloadFont(_font); - - public static ControlInfo[] GetControls() - { - return _controls.ToArray(); - } - - public static bool IsMouseOverControl - { - get - { - foreach (var control in GetControls()) - { - if (control.Control.Active && control.Control.IsMouseHovered() && (control.Holder == Program.currentScreen || control.MultiScreen)) - { - return true; - } - } - return false; - } - } - - public static void PutControl(ControlInfo info) - { - if (!_controls.Contains(info)) - _controls.Add(info); - - foreach (var child in info.Control.Children) - { - PutControl(new ControlInfo(child, info.Holder, info.MultiScreen)); - } - } - - public static void PutControl(Control control, Screen holder, bool multiscreen = false) - { - PutControl(new ControlInfo(control, holder, multiscreen)); - } - public static Control PopControl(string id) - { - var control = _controls.Find(m => m.Control.Name == id); - _controls.Remove(control); - return control.Control; - } - public static void RemoveControl(string id) - { - var control = _controls.Find(m => m.Control.Name == id); - _controls.Remove(control); - } - public static Control GetControl(string id) => _controls.Find(m => m.Control.Name == id).Control; - - public static void Update() - { - if (!ProcessGui) return; - - var curControls = GetControls(); - foreach (var control in curControls) - { - if (control.Holder == Program.currentScreen || control.MultiScreen) - { - control.Control.Update(); - foreach (var child in control.Control.Children) - { - var info = new ControlInfo(child, control.Holder, control.MultiScreen); - if (!_controls.Contains(info)) - _controls.Add(info); - } - } - - } - } - - public static void Draw() - { - if (!ProcessGui) return; - - var curControls = GetControls(); - - curControls.ToList().Sort((x, y) => x.Control.ZIndex.CompareTo(y.Control.ZIndex)); - foreach (var control in curControls) - { - if (control.Control.Active && (control.Holder == Program.currentScreen || control.MultiScreen)) - control.Control.Draw(); - } - } -} \ No newline at end of file diff --git a/GuiElements/BackgroundBlock.cs b/GuiElements/BackgroundBlock.cs deleted file mode 100644 index c945bdd..0000000 --- a/GuiElements/BackgroundBlock.cs +++ /dev/null @@ -1,20 +0,0 @@ -using BuildingGame.GuiElements.Brushes; - -namespace BuildingGame.GuiElements; - -public class BackgroundBlock : Control -{ - public IBrush? Background { get; set; } - - public BackgroundBlock(string name, IBrush? background = null) - : base(name) - { - Background = background; - } - - public override void Draw() - { - if (Background != null) - Background.FillArea(Area); - } -} \ No newline at end of file diff --git a/GuiElements/Brushes/ColorBrush.cs b/GuiElements/Brushes/ColorBrush.cs deleted file mode 100644 index a25f1c9..0000000 --- a/GuiElements/Brushes/ColorBrush.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace BuildingGame.GuiElements.Brushes; - -public class ColorBrush : IBrush -{ - public Color Color { get; set; } - - public ColorBrush(Color color) - { - Color = color; - } - - public void FillArea(Rectangle area) - { - DrawRectangleRec(area, Color); - } - - public static implicit operator Color(ColorBrush bg) => bg.Color; - public static implicit operator ColorBrush(Color color) => new ColorBrush(color); -} \ No newline at end of file diff --git a/GuiElements/Brushes/GradientBrush.cs b/GuiElements/Brushes/GradientBrush.cs deleted file mode 100644 index 0cd78e9..0000000 --- a/GuiElements/Brushes/GradientBrush.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace BuildingGame.GuiElements.Brushes; - -public class GradientBrush : IBrush -{ - public Color ColorA { get; set; } - public Color ColorB { get; set; } - - public GradientBrush(Color colorA, Color colorB) - { - ColorA = colorA; - ColorB = colorB; - } - - public void FillArea(Rectangle area) - { - DrawRectangleGradientV((int)area.x, (int)area.y, (int)area.width, (int)area.height, ColorA, ColorB); - } -} \ No newline at end of file diff --git a/GuiElements/Brushes/IBrush.cs b/GuiElements/Brushes/IBrush.cs deleted file mode 100644 index 79e7914..0000000 --- a/GuiElements/Brushes/IBrush.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace BuildingGame.GuiElements.Brushes; - -public interface IBrush -{ - void FillArea(Rectangle area); -} \ No newline at end of file diff --git a/GuiElements/CheckBox.cs b/GuiElements/CheckBox.cs deleted file mode 100644 index 803b6e4..0000000 --- a/GuiElements/CheckBox.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace BuildingGame.GuiElements; - -public class CheckBox : Control -{ - public bool Checked { get; set; } - public string? Text { get; set; } - public float TextSize { get; set; } - - public CheckBox(string name, string text, Vector2 position, float textSize) - : base(name) - { - Checked = false; - Text = text; - TextSize = textSize; - - var size = MeasureTextEx(Gui.GuiFont, Text, TextSize, 1); - Area = new Rectangle(position.X, position.Y, size.X + 18 + 8, 18 + Math.Abs(size.Y - 18)); - } - - public override void Update() - { - base.Update(); - - if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT) && IsMouseHovered()) - Checked = !Checked; - } - - public override void Draw() - { - DrawRectangle((int)Area.x, (int)Area.y, 18, 18, Color.LIGHTGRAY); - DrawRectangleLines((int)Area.x, (int)Area.y, 18, 18, Color.GRAY); - if (Checked) - DrawTexture(Program.check, (int)Area.x, (int)Area.y, Color.WHITE); - DrawTextEx(Gui.GuiFont, Text, new Vector2(Area.x + 8 + 18, Area.y), TextSize, 1, Color.WHITE); - } -} \ No newline at end of file diff --git a/GuiElements/Control.cs b/GuiElements/Control.cs deleted file mode 100644 index 52f9b8d..0000000 --- a/GuiElements/Control.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.Linq.Expressions; - -namespace BuildingGame.GuiElements; - -public class Control -{ - public string Name { get; set; } - public Rectangle Area { get; set; } - public List Children { get; set; } = new(); - public event Action? Clicked; - public event Action? ClientUpdate; - public bool Active { get; set; } - public int ZIndex { get; set; } - public string? Tooltip { get; set; } - private bool _pressed = false; - private bool _oldPressed = false; - - public Control(string name) - { - Name = name; - Active = true; - } - - public virtual void Update() - { - _oldPressed = _pressed; - _pressed = IsMouseButtonDown(MouseButton.MOUSE_BUTTON_LEFT); - - if (_oldPressed && !_pressed && IsMouseHovered()) - { - Clicked?.Invoke(); - } - - foreach (var child in Children) - { - child.Active = Active; - if (child.ZIndex < ZIndex) - child.ZIndex = ZIndex + 1; - } - - ClientUpdate?.Invoke(); - } - - public virtual void Draw() - { - - } - - public bool IsMouseHovered() - { - return CheckCollisionPointRec(GetMousePosition(), Area) && Active; - } - - public void Adapt(Func position) - { - ClientUpdate += () => - { - var pos = position.Invoke(new Vector2(Program.WIDTH, Program.HEIGHT)); - Area = new Rectangle(pos.X, pos.Y, Area.width, Area.height); - }; - } - - public void Adapt(Func area) - { - ClientUpdate += () => - { - Area = area.Invoke(new Vector2(Program.WIDTH, Program.HEIGHT)); - }; - } -} \ No newline at end of file diff --git a/GuiElements/ControlInfo.cs b/GuiElements/ControlInfo.cs deleted file mode 100644 index 2dd0992..0000000 --- a/GuiElements/ControlInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace BuildingGame; - -public struct ControlInfo -{ - public Control Control { get; } - public Screen Holder { get; } - public bool MultiScreen { get; } - - public ControlInfo(Control control, Screen holder, bool multiscreen) - { - Control = control; - Holder = holder; - MultiScreen = multiscreen; - } - public ControlInfo((Control control, Screen holder, bool multiscreen) oldControlInfo) - : this(oldControlInfo.control, oldControlInfo.holder, oldControlInfo.multiscreen) {} -} \ No newline at end of file diff --git a/GuiElements/HoverButton.cs b/GuiElements/HoverButton.cs deleted file mode 100644 index c65f852..0000000 --- a/GuiElements/HoverButton.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace BuildingGame.GuiElements; - -public class HoverButton : TextBlock -{ - public HoverButton(string name, string text, Vector2 position, float size = 12) - : base(name, text, position, size) - { - SetupButtonCollision(); - } - - public override void Update() - { - base.Update(); - - if (_centeredScreen) CenterScreen(); - - if (CheckCollisionPointRec(GetMousePosition(), Area)) - { - if (Text != null && !Text.StartsWith("> ")) - Text = Text.Insert(0, "> "); - } - else - { - if (Text != null && Text.StartsWith("> ")) - { - Text = Text.Remove(0, 2); - } - } - } - - public void SetupButtonCollision() - { - SetupCollision("> " + Text); - } -} \ No newline at end of file diff --git a/GuiElements/ImageArea.cs b/GuiElements/ImageArea.cs deleted file mode 100644 index b499f3c..0000000 --- a/GuiElements/ImageArea.cs +++ /dev/null @@ -1,26 +0,0 @@ -using BuildingGame.GuiElements.Brushes; - -namespace BuildingGame.GuiElements; - -public class ImageArea : Control -{ - public Texture2D Image { get; set; } - public Rectangle ImageSourceRect { get; set; } - public IBrush? Background { get; set; } - public Color Tint { get; set; } - - public ImageArea(string name, Texture2D image, Rectangle imageSourceRect, Color tint) - : base(name) - { - Image = image; - ImageSourceRect = imageSourceRect; - Tint = tint; - } - - public override void Draw() - { - if (Background != null) - Background.FillArea(Area); - DrawTexturePro(Image, ImageSourceRect, Area, Vector2.Zero, 0, Tint); - } -} \ No newline at end of file diff --git a/GuiElements/InputBox.cs b/GuiElements/InputBox.cs deleted file mode 100644 index 46d2bef..0000000 --- a/GuiElements/InputBox.cs +++ /dev/null @@ -1,77 +0,0 @@ -namespace BuildingGame.GuiElements; - -public class InputBox : Control -{ - public string? Text { get; set; } = string.Empty; - public Range CharacterRange { get; set; } = new Range(32, 125); - public float TextSize { get; set; } = 12f; - public int MaxCharacters { get; set; } = 3; - private bool _focused = false; - - public InputBox(string name, int maxChars = 3, float textSize = 12) - : base(name) - { - MaxCharacters = maxChars; - TextSize = textSize; - } - - public InputBox(string name, Range characterRange, int maxChars = 3, float textSize = 12) - : base(name) - { - CharacterRange = characterRange; - MaxCharacters = maxChars; - TextSize = textSize; - } - - public override void Update() - { - base.Update(); - - if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT)) - { - if (IsMouseHovered()) _focused = true; - else _focused = false; - } - - if (_focused) - { - int @char = GetCharPressed(); - if (@char >= CharacterRange.Start.Value && @char <= CharacterRange.End.Value && Text != null && Text.Length < MaxCharacters) - { - Text += char.ConvertFromUtf32(@char); - } - } - if (IsKeyPressed(KeyboardKey.KEY_BACKSPACE) && Text != null && Text.Length != 0 && _focused) - { - Text = Text.Remove(Text.Length - 1); - Log.Information(Text); - } - } - - public override void Draw() - { - DrawRectangleRec(Area, Color.LIGHTGRAY); - DrawRectangleLinesEx(Area, 1, !_focused ? Color.BLACK : Color.GRAY); - DrawTextEx(Gui.GuiFont, Text, new Vector2(Area.x + 8, Area.y), TextSize, 1, Color.BLACK); - } - - public void ResizeTo(int charCount) - { - var size = MeasureTextEx(Gui.GuiFont, CopyString('@', charCount), TextSize, 1); - Area = new Rectangle( - Area.x, - Area.y, - size.X, - size.Y - ); - MaxCharacters = charCount; - } - - private string CopyString(char c, int count) - { - string str = ""; - for (int i = 0; i < count; i++) - str += c; - return str; - } -} \ No newline at end of file diff --git a/GuiElements/ListView.cs b/GuiElements/ListView.cs deleted file mode 100644 index 0ba6bd5..0000000 --- a/GuiElements/ListView.cs +++ /dev/null @@ -1,75 +0,0 @@ -using BuildingGame.Screens; - -namespace BuildingGame.GuiElements; - -public class ListView : Control -{ - private List _strItems = new List(); - public event Action? ItemClicked; - - public ListView(string name) - : base(name) - { - } - - public override void Update() - { - base.Update(); - - var children = Children; - var first = children.First(); - var last = children.Last(); - - if (GetMouseWheelMoveV().Y < 0) - { - foreach (var child in children) child.Area = new Rectangle(child.Area.x, child.Area.y - child.Area.height, child.Area.width, child.Area.height); - } - - if (GetMouseWheelMoveV().Y > 0) - { - foreach (var child in children) child.Area = new Rectangle(child.Area.x, child.Area.y + child.Area.height, child.Area.width, child.Area.height); - } - } - - public void RecreateItems() - { - foreach (var control in Children) Gui.RemoveControl(control.Name); - Children.Clear(); - - for (int i = 0; i < _strItems.Count; i++) - { - var text = _strItems[i]; - var block = new TextBlock(Name + "_item_" + i, text, - new Vector2(0, 10 + (24 + 6) * (i + 1)), 24); - block.CenterScreen(); - block.Color = Color.WHITE; - block.Clicked += () => ItemClicked?.Invoke(text); - - Children.Add(block); - } - } - - public void PutItem(string item) - { - _strItems.Add(item); - RecreateItems(); - } - - public void RemoveItem(string item) - { - _strItems.Remove(item); - RecreateItems(); - } - - public void ReplaceItem(string orig, string @new) - { - _strItems[_strItems.IndexOf(orig)] = @new; - RecreateItems(); - } - - public void ClearItems() - { - _strItems.Clear(); - RecreateItems(); - } -} \ No newline at end of file diff --git a/GuiElements/RgbBoxLine.cs b/GuiElements/RgbBoxLine.cs deleted file mode 100644 index 335045a..0000000 --- a/GuiElements/RgbBoxLine.cs +++ /dev/null @@ -1,92 +0,0 @@ -using BuildingGame.GuiElements.Brushes; - -namespace BuildingGame.GuiElements; - -public class RgbBoxLine : Control -{ - public Color DefaultColor { get; } - public byte R { get; private set; } - public byte G { get; private set; } - public byte B { get; private set; } - - private InputBox _rBox; - private InputBox _gBox; - private InputBox _bBox; - private BackgroundBlock _colorPreview; - private TextBlock _resetButton; - - public RgbBoxLine(string name, Vector2 position, Color defaultColor) - : base(name) - { - DefaultColor = defaultColor; - Area = new Rectangle(position.X, position.Y, (48 + 4) * 5, 18); - _colorPreview = new BackgroundBlock(Name + "_colorprev", (ColorBrush)Color.WHITE) - { - Area = new Rectangle(position.X, position.Y, 32, 18) - }; - - Range numRange = new Range('\u0030', '\u0039'); - - _rBox = new InputBox(Name + "_rbox", numRange, textSize: 18) - { - Area = new Rectangle(position.X + 48 + 4, position.Y, 0, 0), - }; - _rBox.ResizeTo(3); - - _gBox = new InputBox(Name + "_gbox", numRange, textSize: 18) - { - Area = new Rectangle(position.X + (48 + 4) * 2, position.Y, 0, 0), - }; - _gBox.ResizeTo(3); - - _bBox = new InputBox(Name + "_bbox", numRange, textSize: 18) - { - Area = new Rectangle(position.X + (48 + 4) * 3, position.Y, 0, 0) - }; - _bBox.ResizeTo(3); - - _resetButton = new TextBlock(Name + "_reset", "reset", new Vector2(position.X + (48 + 4) * 4, position.Y), 18); - _resetButton.Color = Color.WHITE; - _resetButton.Clicked += () => - { - ImportColor(DefaultColor); - }; - - _colorPreview.Adapt(_ => new Vector2(Area.x, Area.y)); - _rBox.Adapt(_ => new Vector2(Area.x + 48 + 4, Area.y)); - _gBox.Adapt(_ => new Vector2(Area.x + (48 + 4) * 2, Area.y)); - _bBox.Adapt(_ => new Vector2(Area.x + (48 + 4) * 3, Area.y)); - _resetButton.Adapt(_ => new Vector2(Area.x + (48 + 4) * 4, Area.y)); - - Children.Add(_colorPreview); - Children.Add(_rBox); - Children.Add(_gBox); - Children.Add(_bBox); - Children.Add(_resetButton); - // Gui.PutControl(id, this); - } - - public override void Update() - { - base.Update(); - - if (byte.TryParse(_rBox.Text, out var r)) R = r; - if (byte.TryParse(_gBox.Text, out var g)) G = g; - if (byte.TryParse(_bBox.Text, out var b)) B = b; - - _colorPreview.Background = (ColorBrush)new Color(R, G, B, (byte)255); - } - - public Color ExportColor() => new Color(R, G, B, (byte)255); - public void ImportColor(Color color) - { - R = color.r; - G = color.g; - B = color.b; - - _rBox.Text = R.ToString(); - _gBox.Text = G.ToString(); - _bBox.Text = B.ToString(); - _colorPreview.Background = (ColorBrush)new Color(R, G, B, (byte)255); - } -} \ No newline at end of file diff --git a/GuiElements/TextBlock.cs b/GuiElements/TextBlock.cs deleted file mode 100644 index 69ef5e3..0000000 --- a/GuiElements/TextBlock.cs +++ /dev/null @@ -1,59 +0,0 @@ -namespace BuildingGame.GuiElements; - -public class TextBlock : Control -{ - public string? Text { get; set; } - public float Size { get; set; } = 12f; - public Font Font { get; set; } = Gui.GuiFont; - public Color Color { get; set; } = Color.BLACK; - protected bool _centeredScreen = false; - - public TextBlock(string name, string text, Vector2 position, float size = 12) - : base(name) - { - Text = text; - Area = new Rectangle(position.X, position.Y, 0, 0); - Size = size; - SetupCollision(); - } - - public void Center() - { - Area = new Rectangle( - Area.x + Area.width / 2 - MeasureTextEx(Font, Text, Size, 1).X / 2, - Area.y, - Area.width, - Area.height - ); - } - public void CenterScreen() - { - Area = new Rectangle( - Program.WIDTH / 2 - MeasureTextEx(Font, Text, Size, 1).X / 2, - Area.y, - Area.width, - Area.height - ); - _centeredScreen = true; - } - - public void SetupCollision(string? text = null) - { - if (text == null) text = Text; - if (text != null) - { - var size = MeasureTextEx(Font, text, Size, 1); - - Area = new Rectangle( - Area.x, - Area.y, - size.X, - size.Y - ); - } - } - public override void Draw() - { - DrawTextEx(Font, Text, new Vector2(Area.x, Area.y), Size, 1, Color); - } -} \ No newline at end of file diff --git a/GuiElements/Tooltip.cs b/GuiElements/Tooltip.cs deleted file mode 100644 index 52cbbf6..0000000 --- a/GuiElements/Tooltip.cs +++ /dev/null @@ -1,52 +0,0 @@ -using BuildingGame.GuiElements.Brushes; - -namespace BuildingGame.GuiElements; - -public class Tooltip : Control -{ - public IBrush? Background { get; set; } - public float TextSize { get; set; } - private string _currentTrigger; - - public Tooltip(string name, float size = 18) - : base(name) - { - ZIndex = 100; - TextSize = size; - Active = false; - _currentTrigger = ""; - } - - public override void Update() - { - base.Update(); - - var mpos = GetMousePosition() + new Vector2(0, 16); - var size = MeasureTextEx(Gui.GuiFont, _currentTrigger, TextSize, 1); - Area = new Rectangle( - mpos.X - 16, - mpos.Y, - size.X + 16, - size.Y + 16 - ); - - bool isTriggered = false; - foreach (var trigger in Gui.GetControls()) - { - if (trigger.Control.Tooltip != null && trigger.Control.IsMouseHovered()) - { - _currentTrigger = trigger.Control.Tooltip; - isTriggered = true; - break; - } - } - Active = isTriggered; - } - - public override void Draw() - { - if (Background != null) - Background.FillArea(Area); - DrawTextEx(Gui.GuiFont, _currentTrigger, new Vector2(Area.x + 8, Area.y + 8), TextSize, 1, Color.WHITE); - } -} \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 1e908b5..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 Danil - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/Program.cs b/Program.cs deleted file mode 100644 index cd2893b..0000000 --- a/Program.cs +++ /dev/null @@ -1,188 +0,0 @@ -global using System.Numerics; -global using BuildingGame.GuiElements; -global using BuildingGame.GuiElements.Brushes; -global using BuildingGame.Screens; -global using BuildingGame.TilePacks; -global using BuildingGame.Tiles; -global using Raylib_cs; -global using Serilog; -global using static Raylib_cs.Raylib; -global using static Raylib_cs.Raymath; -using System.Diagnostics; - -namespace BuildingGame; - -#nullable disable -internal class Program -{ - internal static int WIDTH = 800; - static int preWidth = 800; - internal static int HEIGHT = 600; - static int preHeight = 600; - - internal static Texture2D origAtlas; - internal static Texture2D atlas; - internal static Texture2D check; - - internal static bool mustClose = false; - - internal static MenuScreen menuScreen; - internal static GameScreen gameScreen; - internal static WorldSelectScreen worldSelectScreen; - internal static CreateWorldScreen createWorldScreen; - internal static Screen currentScreen; - internal static SelectPackScreen selectPackScreen; - - internal static string version = ""; - - private static bool _isFullScreen = false; - - private static void Main() - { - Log.Logger = new LoggerConfiguration() - .MinimumLevel.Debug() - .WriteTo.Console() - .WriteTo.File("logs/latest.log", rollingInterval: RollingInterval.Minute) - .CreateLogger(); - - AppDomain.CurrentDomain.UnhandledException += (sender, ev) => - { - Log.Fatal("something fatal happened on code side.\nexception: " + ev.ExceptionObject.ToString()); - }; - InitWindow(WIDTH, HEIGHT, "BuildingGame"); - SetExitKey(KeyboardKey.KEY_NULL); - SetWindowState(ConfigFlags.FLAG_WINDOW_RESIZABLE); - SetWindowState(ConfigFlags.FLAG_VSYNC_HINT); - SetWindowMinSize(800, 600); - - Gui.SetGuiFont("assets/font.ttf"); - - BeginDrawing(); - ClearBackground(new Color(20, 20, 20, 255)); - - DrawTextEx(Gui.GuiFont, "Loading assets...", new Vector2(16, HEIGHT - 18 - 16), 18, 1, Color.WHITE); - - EndDrawing(); - - Log.Information("loading assets..."); - - var versionInfo = FileVersionInfo.GetVersionInfo(Path.Join(AppContext.BaseDirectory, "buildinggame.exe")); - version = versionInfo.FileVersion; - - origAtlas = LoadTexture("assets/atlas.png"); - atlas = origAtlas; - check = LoadTexture("assets/check.png"); - SetTextureFilter(atlas, TextureFilter.TEXTURE_FILTER_POINT); - SetTextureFilter(check, TextureFilter.TEXTURE_FILTER_POINT); - - Image icon = LoadImage("assets/icon.png"); - SetWindowIcon(icon); - - Settings.Load(); - TilePackManager.LoadPacks(); - Log.Information("loaded packs and settings"); - if (Settings.CurrentPack != "default") - TilePackManager.ApplyPack(Settings.CurrentPack); - else - TilePackManager.SetDefaultPack(); - Log.Information("toggled pack to 'currentPack' value in settings (" + Settings.CurrentPack + ")"); - - gameScreen = new GameScreen(); - gameScreen.Initialize(); - - menuScreen = new MenuScreen(); - menuScreen.Initialize(); - - worldSelectScreen = new WorldSelectScreen(); - worldSelectScreen.Initialize(); - - createWorldScreen = new CreateWorldScreen(); - createWorldScreen.Initialize(); - - selectPackScreen = new SelectPackScreen(); - selectPackScreen.Initialize(); - - currentScreen = menuScreen; - - Log.Information("initialized screens"); - Log.Information("going to the event loop"); - - while (!WindowShouldClose()) - { - // SetWindowTitle("BuldingGame - " + GetFPS() + " FPS"); - if (mustClose) break; - if (IsKeyPressed(KeyboardKey.KEY_F11)) - { - if (_isFullScreen) - { - WIDTH = preWidth; - HEIGHT = preHeight; - ClearWindowState(ConfigFlags.FLAG_WINDOW_UNDECORATED); - SetWindowPosition(GetMonitorWidth(GetCurrentMonitor()) / 2 - WIDTH / 2, - GetMonitorHeight(GetCurrentMonitor()) / 2 - HEIGHT / 2); - } - else - { - preWidth = WIDTH; - preHeight = HEIGHT; - - WIDTH = GetMonitorWidth(GetCurrentMonitor()); - HEIGHT = GetMonitorHeight(GetCurrentMonitor()); - - SetWindowPosition(0, 0); - SetWindowState(ConfigFlags.FLAG_WINDOW_UNDECORATED); - } - SetWindowSize(WIDTH, HEIGHT); - _isFullScreen = !_isFullScreen; - - - - } - - // take screenshot ONLY if player is in game right now - if (IsKeyPressed(KeyboardKey.KEY_F2) && currentScreen == gameScreen) Screenshot.Create(); - // toggle gui only if player is in game right now - if (IsKeyPressed(KeyboardKey.KEY_F1) && currentScreen == gameScreen) - { - Gui.ProcessGui = !Gui.ProcessGui; - gameScreen.showPreTile = !gameScreen.showPreTile; - } - - WIDTH = GetScreenWidth(); - HEIGHT = GetScreenHeight(); - if (IsWindowResized()) - { - var bgPanel = (BackgroundBlock)Gui.GetControl("bgPanel"); - var tooltip = (Tooltip)Gui.GetControl("tileTooltip"); - // gameScreen.RecreateTileMenu(bgPanel, tooltip); - gameScreen.camera.offset = new Vector2(Program.WIDTH / 2, Program.HEIGHT); - } - - currentScreen.Update(); - - Gui.Update(); - - BeginDrawing(); - - currentScreen.Draw(); - - Gui.Draw(); - DrawTextEx(Gui.GuiFont, GetFPS().ToString(), Vector2.Zero, 18, 1, Color.LIME); - - EndDrawing(); - } - - Log.Information("saving world..."); - gameScreen.World.Save(); - Log.Information("saving settings..."); - Settings.Save(); - - Log.Information("unloading textures..."); - UnloadImage(icon); - UnloadTexture(check); - UnloadTexture(origAtlas); - TilePackManager.UnloadPacks(); - Log.Information("goodbye!"); - CloseWindow(); - } -} \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 80b731c..0000000 --- a/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# BuildingGame -### a game, where you need to place tiles... and... this is all what you can...? -![2023_03_12-11_41_50_938](https://user-images.githubusercontent.com/61111955/224536830-3f761bba-2c44-45ac-8648-445c988697bf.png) - -# tasks -✓ add infection block (and it's toggle)
-✓ add tile packs (custom atlas.png + atlas.txt w/o changing game assets)
- -# build -you need .net 7 sdk to build the game -## cli -- download source (download -> download zip) -- unpack folder somewhere -- open cmd in it -- dotnet build diff --git a/Screens/CreateWorldScreen.cs b/Screens/CreateWorldScreen.cs deleted file mode 100644 index 2c1f86e..0000000 --- a/Screens/CreateWorldScreen.cs +++ /dev/null @@ -1,59 +0,0 @@ -using BuildingGame.GuiElements; - -namespace BuildingGame.Screens; - -public class CreateWorldScreen : Screen -{ - public int worldIndex; - - public override void Draw() - { - ClearBackground(new Color(20, 20, 20, 255)); - // throw new NotImplementedException(); - } - - public override void Initialize() - { - var worldNameBox = new InputBox("worldNameBox", 16, 24) - { - Area = new Rectangle(Program.WIDTH / 2 - 300 / 2, Program.HEIGHT / 3, 300, 24) - }; - worldNameBox.ClientUpdate += () => worldNameBox.Area = new Rectangle(Program.WIDTH / 2 - 300 / 2, Program.HEIGHT / 3, 300, 24); - - var worldNameBoxSubtitle = new TextBlock("worldNameBoxSubtitle", "(max. 16 characters)", - new Vector2(worldNameBox.Area.x, worldNameBox.Area.y + 24), 18); - worldNameBoxSubtitle.ClientUpdate += () => worldNameBoxSubtitle.Area = new Rectangle(worldNameBox.Area.x, worldNameBox.Area.y + 18 + 5, 0, 0); - worldNameBoxSubtitle.Color = Color.WHITE; - - var createWorldButton = new HoverButton("createWorldButton", "create", - new Vector2(0, worldNameBox.Area.y + (24 + 5) * 3), 24); - createWorldButton.CenterScreen(); - createWorldButton.Color = Color.WHITE; - createWorldButton.Clicked += () => - { - File.WriteAllText("saves/" + worldIndex + "/info.txt", worldNameBox.Text); - Program.gameScreen.World.Load("saves/" + worldIndex + "/level.dat"); - Program.currentScreen = Program.gameScreen; - }; - - var backButton = new HoverButton("backButton", "back", - new Vector2(0, worldNameBox.Area.y + (24 + 5) * 4), 24); - backButton.CenterScreen(); - backButton.Color = Color.WHITE; - backButton.Clicked += () => - { - worldNameBox.Text = ""; - Program.currentScreen = Program.worldSelectScreen; - }; - - Gui.PutControl(worldNameBox, this); - Gui.PutControl(worldNameBoxSubtitle, this); - Gui.PutControl(createWorldButton, this); - Gui.PutControl(backButton, this); - } - - public override void Update() - { - // throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/Screens/GameScreen.cs b/Screens/GameScreen.cs deleted file mode 100644 index 0ae03ad..0000000 --- a/Screens/GameScreen.cs +++ /dev/null @@ -1,285 +0,0 @@ -namespace BuildingGame.Screens; - -public class GameScreen : Screen -{ - const float CAMERA_SPEED = 5; - - static byte _currentType = 1; - - public Camera2D camera; - bool _cameraRunning; - - World _world = null!; - public World World => _world; - - // toggles tile that will show when you move mouse over world - public bool showPreTile = true; - - bool flipTile = false; - float tileRot = 0; - - int mx = 0; - int my = 0; - - public override void Draw() - { - BeginMode2D(camera); - ClearBackground(Settings.SkyColor); - - DrawRectangleLinesEx( - new Rectangle(-26, -26, World.CHUNK_AREA * Chunk.SIZE * 48, World.CHUNK_AREA * Chunk.SIZE * 48), - 2f, Color.RED - ); - _world.Draw(); - if (!Gui.IsMouseOverControl && showPreTile) - Tile.GetTile(_currentType).Draw(mx, my, new TileFlags(tileRot, flipTile), new Color(255, 255, 255, 120)); - - EndMode2D(); - } - - public override void Initialize() - { - _world = new World(); - - camera = new Camera2D - { - offset = new Vector2(Program.WIDTH / 2, Program.HEIGHT / 2), - target = new Vector2(GetRandomValue(0, World.CHUNK_AREA * Chunk.SIZE * 48)), - zoom = 1, - rotation = 0 - }; - - CreateGui(); - } - - public override void Update() - { - #region Camera Movement - _cameraRunning = IsKeyDown(KeyboardKey.KEY_LEFT_SHIFT); - - float vx = IsKeyDown(KeyboardKey.KEY_D) - IsKeyDown(KeyboardKey.KEY_A); - float vy = IsKeyDown(KeyboardKey.KEY_S) - IsKeyDown(KeyboardKey.KEY_W); - - camera.target += new Vector2(vx, vy) * (_cameraRunning ? CAMERA_SPEED * 2 : CAMERA_SPEED); - #endregion - - #region Tile Placement - Vector2 wmPos = GetScreenToWorld2D(GetMousePosition(), camera); - - mx = (int)(Math.Round((float)((wmPos.X) / 48))); - my = (int)(Math.Round((float)((wmPos.Y) / 48))); - - if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_LEFT) && !Gui.IsMouseOverControl) - { - _world.PlaceTile(mx, my, new TileInfo(_currentType, new TileFlags(tileRot, flipTile))); - } - if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_RIGHT) && !Gui.IsMouseOverControl) - { - _world.PlaceTile(mx, my, 0); - } - #endregion - - #region Tile Flags Manipulation - if (IsKeyPressed(KeyboardKey.KEY_R)) - { - if (tileRot >= 360) tileRot = 0; - tileRot += 90; - } - if (IsKeyPressed(KeyboardKey.KEY_F)) - { - flipTile = !flipTile; - } - #endregion - - #region Tile Menu shortcut - if (IsKeyPressed(KeyboardKey.KEY_B) && !Gui.GetControl("pausePanel").Active) - { - var bgPanel = Gui.GetControl("bgPanel"); - bgPanel.Active = !bgPanel.Active; - } - #endregion - - #region Camera Zoom - camera.zoom += ((float)GetMouseWheelMove() * 0.05f); - - if (camera.zoom > 3.0f) camera.zoom = 3.0f; - else if (camera.zoom < 0.1f) camera.zoom = 0.1f; - #endregion - - _world.Update(); - } - - void CreateGui() - { - var bgPanel = new BackgroundBlock("bgPanel", - new GradientBrush(new Color(0, 0, 25, 100), new Color(0, 0, 0, 200)) - ) - { - Area = new Rectangle(Program.WIDTH / 2 - 340, Program.HEIGHT / 2 - 210, 680, 420), - Active = false, - ZIndex = 40 - }; - bgPanel.Adapt(windowSize => new Rectangle(windowSize.X / 2 - 340, windowSize.Y / 2 - 210, 680, 420)); - bgPanel.ClientUpdate += () => - { - if (IsKeyPressed(KeyboardKey.KEY_ESCAPE)) bgPanel.Active = false; - }; - - var pausePanel = new BackgroundBlock("pausePanel", bgPanel.Background) - { - Area = new Rectangle(0, 0, Program.WIDTH, Program.HEIGHT), - Active = false, - ZIndex = 50 - }; - pausePanel.Adapt(windowSize => new Rectangle(0, 0, windowSize.X, windowSize.Y)); - pausePanel.ClientUpdate += () => - { - if (Gui.GetControl("settingsPanel").Active && IsKeyPressed(KeyboardKey.KEY_ESCAPE)) Gui.GetControl("settingsPanel").Active = false; - else if (IsKeyPressed(KeyboardKey.KEY_ESCAPE) && !bgPanel.Active) pausePanel.Active = !pausePanel.Active; - }; - - var resumeGameButton = new HoverButton("resumeGameButton", "resume", Vector2.Zero, 24) - { - Area = new Rectangle(Program.WIDTH / 2, Program.HEIGHT / 3, 150, 24), - Color = Color.WHITE - }; - resumeGameButton.Clicked += () => - { - pausePanel.Active = false; - Gui.GetControl("settingsPanel").Active = false; - }; - resumeGameButton.CenterScreen(); - pausePanel.Children.Add(resumeGameButton); - - var menuGameButton = new HoverButton("menuGameButton", "menu", Vector2.Zero, 24) - { - Area = new Rectangle(Program.WIDTH / 2, Program.HEIGHT / 3 + 8 + 24, 150, 24), - Color = Color.WHITE - }; - menuGameButton.Clicked += () => - { - pausePanel.Active = false; - Gui.GetControl("settingsPanel").Active = false; - _world.Save(); - Program.currentScreen = Program.menuScreen; - }; - menuGameButton.CenterScreen(); - pausePanel.Children.Add(menuGameButton); - - var settingsGameButton = new HoverButton("settingsGameButton", "settings", Vector2.Zero, 24) - { - Area = new Rectangle(Program.WIDTH / 2, Program.HEIGHT / 3 + 8 + 24 + 56, 150, 24), - Color = Color.WHITE - }; - settingsGameButton.Clicked += () => - { - Gui.GetControl("settingsPanel").Active = !Gui.GetControl("settingsPanel").Active; - }; - settingsGameButton.CenterScreen(); - pausePanel.Children.Add(settingsGameButton); - - var tooltip = new Tooltip("tileTooltip"); - tooltip.Background = new GradientBrush(new Color(0, 0, 0, 50), new Color(16, 0, 16, 127)); - - #region Tile Preview (+ Tile Menu shortcut) - var texImg = new ImageArea("texImg", Program.atlas, new Rectangle(0, 0, 16, 16), new Color(255, 255, 255, 200)) - { - Area = new Rectangle(Program.WIDTH - 64 - 16, 16, 64, 64) - }; - texImg.Adapt(windowSize => new Vector2(windowSize.X - 64 - 16, 16)); - texImg.ClientUpdate += () => - { - var tile = Tile.GetTile(_currentType); - if (tile.IsUnknown) - { - texImg.ImageSourceRect = new Rectangle(0, 0, 48, 48); - texImg.Image = Tile.Unknown; - } - else - { - texImg.ImageSourceRect = new Rectangle(tile.AtlasOffset.X * 16, tile.AtlasOffset.Y * 16, 16, 16); - texImg.Image = Program.atlas; - } - }; - texImg.Clicked += () => - { - if (!pausePanel.Active) - bgPanel.Active = !bgPanel.Active; - }; - #endregion - - #region Tile Menu Generation - - - RecreateTileMenu(bgPanel); - TilePackManager.PackChanged += () => RecreateTileMenu(bgPanel); - #endregion - - Gui.PutControl(bgPanel, this); - Gui.PutControl(tooltip, this); - Gui.PutControl(texImg, this); - Gui.PutControl(pausePanel, this); - } - - private void RecreateTileMenu(BackgroundBlock bgPanel) - { - bgPanel.Children.Clear(); - - var sx = (float width) => width / 2 - 340 + 20; - var sy = (float height) => height / 2 - 210 + 20; - float x = 20; - float y = 20; - - Gui.RemoveControl("tileMenuTitle"); - var tileMenuTitle = new TextBlock("tileMenuTitle", "Select a tile", - Vector2.Zero, 32 - ); - tileMenuTitle.Adapt((windowSize) => new Vector2(bgPanel.Area.x + 250 , windowSize.Y / 2 - 210 + 6)); - tileMenuTitle.Active = true; - tileMenuTitle.Color = Color.WHITE; - tileMenuTitle.CenterScreen(); - bgPanel.Children.Add(tileMenuTitle); - - for (byte i = 0; i < Tile.DefaultTiles.Length; i++) - { - Gui.RemoveControl("tile_" + i); - var tile = Tile.DefaultTiles[i]; - byte idx = (byte)(i + 1); - var btn = new ImageArea("tile_" + i, Program.atlas, - new Rectangle(tile.AtlasOffset.X * 16, tile.AtlasOffset.Y * 16, 16, 16), Color.WHITE - ) - { - Area = new Rectangle(x, y, 48, 48), - ZIndex = 45 - }; - float lx = x; - float ly = y; - btn.Adapt((windowSize) => new Rectangle(sx.Invoke(windowSize.X) + lx, sy.Invoke(windowSize.Y) + ly, 48, 48)); - btn.ClientUpdate += () => - { - btn.Tooltip = Tile.GetTile(idx).DisplayName; - btn.Image = Program.atlas; - }; - - btn.Clicked += () => - { - _currentType = idx; - bgPanel.Active = false; - }; - - // Gui.PutControl(btn, this); - bgPanel.Children.Add(btn); - - if (x > 800 / 2 + 100) - { - x = 20; - y += 48 + 5; - continue; - } - - - - x += 48 + 5; - } - } -} \ No newline at end of file diff --git a/Screens/MenuScreen.cs b/Screens/MenuScreen.cs deleted file mode 100644 index fbf1e53..0000000 --- a/Screens/MenuScreen.cs +++ /dev/null @@ -1,144 +0,0 @@ -using System.Diagnostics; -using System.Reflection; - - -namespace BuildingGame.Screens; - -public class MenuScreen : Screen -{ - private Dictionary _localControls = new Dictionary(); - public override void Draw() - { - ClearBackground(new Color(20, 20, 20, 255)); - } - - BackgroundBlock settingsPanel = null!; - TextBlock bgColorTitle = null!; - RgbBoxLine bgColorLine = null!; - CheckBox physicsCheckBox = null!; - CheckBox enableInfectionCheckBox = null!; - - public override void Initialize() - { - // create gui elements - settingsPanel = new BackgroundBlock("settingsPanel", (ColorBrush)new Color(0, 0, 0, 100)) - { - Area = new Rectangle(50, 50, Program.WIDTH - 50 * 2, Program.HEIGHT - 50 * 2), - Active = false, - ZIndex = 100 - }; - settingsPanel.ClientUpdate += () => - { - settingsPanel.Area = new Rectangle(50, 50, Program.WIDTH - 50 * 2, Program.HEIGHT - 50 * 2); - Settings.SkyColor = bgColorLine.ExportColor(); - Settings.EnablePhysics = physicsCheckBox.Checked; - Settings.EnableInfectionBlock = enableInfectionCheckBox.Checked; - }; - - bgColorTitle = new TextBlock( - "bgColorTitle", "sky color (rgb): ", - new Vector2(settingsPanel.Area.x + 8, settingsPanel.Area.y + 16), - 18 - ); - bgColorTitle.ClientUpdate += () => - { - var point = new Vector2(settingsPanel.Area.x + 8, settingsPanel.Area.y + 16); - bgColorTitle.Area = new Rectangle( - point.X, - point.Y, - bgColorTitle.Area.width, - bgColorTitle.Area.height - ); - }; - bgColorTitle.Color = Color.WHITE; - settingsPanel.Children.Add(bgColorTitle); - - bgColorLine = new RgbBoxLine("bgColorLine", - new Vector2(bgColorTitle.Area.x + bgColorTitle.Area.width + 8, bgColorTitle.Area.y), - Color.SKYBLUE - ); - bgColorLine.ImportColor(Settings.SkyColor); - settingsPanel.Children.Add(bgColorLine); - - physicsCheckBox = new CheckBox("physicsCheckBox", "enable dynamic tiles (can cause fps drops)", - Vector2.Zero, - 18 - ); - physicsCheckBox.Adapt(_ => new Vector2(settingsPanel.Area.x + 8, settingsPanel.Area.y + 16 + 8 + 18)); - physicsCheckBox.Checked = Settings.EnablePhysics; - settingsPanel.Children.Add(physicsCheckBox); - - enableInfectionCheckBox = new CheckBox("enableInfectionCheckBox", "enable infection tiles", - Vector2.Zero, 18); - enableInfectionCheckBox.Adapt(_ => new Vector2(settingsPanel.Area.x + 8, settingsPanel.Area.y + (16 + 8 + 18) * 2)); - enableInfectionCheckBox.Checked = Settings.EnableInfectionBlock; - settingsPanel.Children.Add(enableInfectionCheckBox); - - var title = new TextBlock("title", "building game", Vector2.Zero, 36); - title.Adapt((windowSize) => new Vector2(12, CalculateYForButton(windowSize, 0))); - title.Color = Color.WHITE; - - var playButton = new HoverButton("playButton", "play", - Vector2.Zero, 24); - playButton.Adapt((windowSize) => new Vector2(12, CalculateYForButton(windowSize, 1))); - playButton.Color = Color.WHITE; - playButton.Clicked += () => - { - Program.currentScreen = Program.worldSelectScreen; - settingsPanel.Active = false; - }; - - var settingsButton = new HoverButton("settingsButton", "settings", - Vector2.Zero, 24); - settingsButton.Adapt((windowSize) => new Vector2(12, CalculateYForButton(windowSize, 2))); - settingsButton.Color = Color.WHITE; - settingsButton.Clicked += () => - { - if (!(settingsPanel.Active && CheckCollisionPointRec(GetMousePosition(), settingsPanel.Area))) - { - settingsPanel.Active = !settingsPanel.Active; - } - }; - - var packsButton = new HoverButton("packsButton", "packs", - Vector2.Zero, 24); - packsButton.Adapt((windowSize) => new Vector2(12, CalculateYForButton(windowSize, 3))); - packsButton.Color = Color.WHITE; - packsButton.Clicked += () => Program.currentScreen = Program.selectPackScreen; - - var exitButton = new HoverButton("exitButton", "exit", - Vector2.Zero, 24 - ); - exitButton.Adapt((windowSize) => new Vector2(12, CalculateYForButton(windowSize, 4))); - exitButton.Color = Color.WHITE; - exitButton.Clicked += () => - { - Program.mustClose = true; - }; - - var versionBlock = new TextBlock("versionBlock", $"v{Program.version}", - Vector2.Zero, 18 - ); - versionBlock.Adapt((windowSize) => new Vector2(8, windowSize.Y - 8 - 18)); - versionBlock.Color = Color.WHITE; - - Gui.PutControl(settingsPanel, this, true); - Gui.PutControl(settingsButton, this); - Gui.PutControl(packsButton, this); - Gui.PutControl(playButton, this); - Gui.PutControl(exitButton, this); - Gui.PutControl(title, this); - Gui.PutControl(versionBlock, this); - - } - - public override void Update() - { - - } - - private float CalculateYForButton(Vector2 windowSize, int buttonNumber) - { - return windowSize.Y / 3 + 36 + (20 + 24 / 2) * buttonNumber; - } -} \ No newline at end of file diff --git a/Screens/Screen.cs b/Screens/Screen.cs deleted file mode 100644 index 74baf54..0000000 --- a/Screens/Screen.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace BuildingGame.Screens; - -public abstract class Screen -{ - public abstract void Initialize(); - public abstract void Update(); - public abstract void Draw(); -} \ No newline at end of file diff --git a/Screens/SelectPackScreen.cs b/Screens/SelectPackScreen.cs deleted file mode 100644 index 38eae2d..0000000 --- a/Screens/SelectPackScreen.cs +++ /dev/null @@ -1,78 +0,0 @@ -using BuildingGame.GuiElements; -using BuildingGame.TilePacks; -using BuildingGame.Tiles; - -namespace BuildingGame.Screens; - -#nullable disable -public class SelectPackScreen : Screen -{ - private ListView _packListView; - private HoverButton _backButton; - private TextBlock _currentPackLabel; - - public override void Draw() - { - ClearBackground(new Color(20, 20, 20, 255)); - } - - public override void Initialize() - { - var bg = new BackgroundBlock("spsBg", (ColorBrush)new Color(20, 20, 20, 255)); - bg.Adapt((windowSize) => new Rectangle(0, windowSize.Y - 115, windowSize.X, 115)); - bg.ZIndex = 2; - _currentPackLabel = new TextBlock("currentPackLabel", "Current pack: default", Vector2.Zero, 24); - _currentPackLabel.Color = Color.WHITE; - _currentPackLabel.ZIndex = 3; - _currentPackLabel.Adapt((windowSize) => - new Vector2( - windowSize.X / 2 - MeasureTextEx(_currentPackLabel.Font, _currentPackLabel.Text, 24, 1).X / 2, - windowSize.Y - 32 - ) - ); - _currentPackLabel.ClientUpdate += () => _currentPackLabel.Text = "Current pack: " + Settings.CurrentPack; - - _packListView = new ListView("packListView"); - _packListView.PutItem("default"); - _packListView.ItemClicked += (item) => - { - item = item.Replace(" (custom map)", null); - if (item == "default") - { - TilePackManager.SetDefaultPack(); - } - else - { - TilePackManager.ApplyPack(item); - } - - Settings.CurrentPack = item; - }; - - foreach (var pack in TilePackManager.TilePacks) - { - _packListView.PutItem(pack.Name + (!pack.IsVanilla ? " (custom map)" : "")); - } - - _backButton = new HoverButton("spsBackButton", "back", Vector2.Zero, 24); - _backButton.ZIndex = 3; - _backButton.Color = Color.WHITE; - _backButton.CenterScreen(); - _backButton.Adapt(windowSize => new Vector2(_backButton.Area.x, windowSize.Y - 100)); - - _backButton.Clicked += () => - { - Program.currentScreen = Program.menuScreen; - }; - - Gui.PutControl(_packListView, this); - Gui.PutControl(bg, this); - Gui.PutControl(_backButton, this); - Gui.PutControl(_currentPackLabel, this); - } - - public override void Update() - { - - } -} \ No newline at end of file diff --git a/Screens/WorldSelectScreen.cs b/Screens/WorldSelectScreen.cs deleted file mode 100644 index 2396518..0000000 --- a/Screens/WorldSelectScreen.cs +++ /dev/null @@ -1,91 +0,0 @@ -using BuildingGame.GuiElements; - -namespace BuildingGame.Screens; - -public class WorldSelectScreen : Screen -{ - List _worldButtons = new List(); - - public override void Draw() - { - ClearBackground(new Color(20, 20, 20, 255)); - } - - public override void Initialize() - { - int y = 80; - for (int i = 0; i < 10; i++) - { - var idx = i; - var worldButton = new HoverButton("world_" + i, FetchWorldName(idx), new Vector2(0, y), 32 - ); - worldButton.Clicked += () => LoadWorld(idx); - worldButton.Color = Color.WHITE; - worldButton.CenterScreen(); - - Gui.PutControl(worldButton, this); - y += 37; - } - - var menuButton = new HoverButton("menuSelectButton", "menu", new Vector2(0, y + 60), 32); - menuButton.Clicked += () => - { - Program.currentScreen = Program.menuScreen; - }; - menuButton.Color = Color.WHITE; - menuButton.CenterScreen(); - - Gui.PutControl(menuButton, this); - } - - private string FetchWorldName(int i) - { - if (IsExistsWorld(i)) - { - if (File.Exists("saves/" + i + "/info.txt")) - { - var lines = File.ReadAllLines("saves/" + i + "/info.txt"); - if (lines.Length < 1) return "world #" + (i + 1); - return lines.First().Replace("\n", ""); - } - - else - return "world #" + (i + 1); - } - return "world #" + (i + 1) + " (new)"; - } - - private void LoadWorld(int i) - { - if (((HoverButton)Gui.GetControl("world_" + i)).Text!.EndsWith("(new)")) - { - Program.createWorldScreen.worldIndex = i; - Program.currentScreen = Program.createWorldScreen; - } - else - { - Program.gameScreen.World.Load("saves/" + i + "/level.dat"); - Program.currentScreen = Program.gameScreen; - } - - } - - private bool IsExistsWorld(int i) - { - if (!Directory.Exists("saves/" + i)) - { - Directory.CreateDirectory("saves/" + i); - } - - return File.Exists("saves/" + i + "/level.dat"); - } - - public override void Update() - { - for (int i = 0; i < 10; i++) - { - int idx = i; - ((HoverButton)Gui.GetControl("world_" + i)).Text = FetchWorldName(idx); - } - } -} \ No newline at end of file diff --git a/Screenshot.cs b/Screenshot.cs deleted file mode 100644 index 70a2fa9..0000000 --- a/Screenshot.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace BuildingGame; - -public static class Screenshot -{ - public static readonly string ScreenshotRoot = "screenshots/"; - public static void Create() - { - // create root for screenshots - if (!Directory.Exists(ScreenshotRoot)) Directory.CreateDirectory(ScreenshotRoot); - - // take screenshot - TakeScreenshot(ScreenshotRoot + DateTime.Now.ToString("yyyy_MM_dd-HH_mm_ss_fff") + ".png"); - } -} \ No newline at end of file diff --git a/Settings.cs b/Settings.cs deleted file mode 100644 index f751747..0000000 --- a/Settings.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Serialization.Metadata; - -namespace BuildingGame; - -public class Settings -{ - public static Color SkyColor = Color.SKYBLUE; - public static bool EnablePhysics = false; - public static bool EnableInfectionBlock = false; - public static string CurrentPack = "default"; - - public static void Save() - { - try - { - ConfigParser.Write("settings.txt", new Dictionary() - { - { "skyColor", ToStringColor(SkyColor) }, - { "enablePhysics", EnablePhysics.ToString() }, - { "enableInfectionBlock", EnableInfectionBlock.ToString() }, - { "currentTilePack", CurrentPack } - }); - } - catch (Exception ex) { Log.Information(ex.ToString()); } - } - public static void Load() - { - try - { - var data = ConfigParser.Parse("settings.txt"); - - if (data.TryGetValue("skyColor", out var skyColorStr) && - TryParseColor(skyColorStr, out var skyColor)) - { - SkyColor = skyColor; - } - - if (data.TryGetValue("enablePhysics", out var enablePhysicsStr) && - bool.TryParse(enablePhysicsStr, out bool enablePhysics)) - EnablePhysics = enablePhysics; - if (data.TryGetValue("enableInfectionBlock", out var enableInfectionBlockStr) && - bool.TryParse(enableInfectionBlockStr, out bool enableInfectionBlock)) - EnableInfectionBlock = enableInfectionBlock; - if (data.TryGetValue("currentTilePack", out var currentPack)) - CurrentPack = currentPack; - } - catch (Exception ex) { Log.Information(ex.ToString()); } - } - - private static bool TryParseColor(string str, out Color color) - { - var split = str.Split(','); - color = Color.WHITE; - - if (split.Length < 3) return false; - - if (byte.TryParse(split[0].Trim(), out var r) && - byte.TryParse(split[1].Trim(), out var g) && - byte.TryParse(split[2].Trim(), out var b)) - { - color = new Color(r, g, b, (byte)255); - return true; - } - - return false; - } - - private static string ToStringColor(Color color) - { - return $"{color.r},{color.g},{color.b}"; - } -} \ No newline at end of file diff --git a/TilePacks/TilePack.cs b/TilePacks/TilePack.cs deleted file mode 100644 index 6b590a6..0000000 --- a/TilePacks/TilePack.cs +++ /dev/null @@ -1,83 +0,0 @@ -namespace BuildingGame.TilePacks; - -public struct TilePack -{ - public const byte PACK_FORMAT = 0; - - public string Root { get; } = string.Empty; - public string Name { get; } = string.Empty; - public byte Version { get; } = 0; - public bool IsVanilla { get; } = true; - - public string AtlasPath { get; } = string.Empty; - public string TileAtlasPath { get; } = string.Empty; - - internal Texture2D Atlas { get; set; } - - public TilePack(string path) - { - Atlas = Program.atlas; - try - { - Root = path; - - // try to get some data from pack - if (Check(path)) - { - // parse info file - var data = ConfigParser.Parse(Path.Combine(path, "info.txt")); - - // get pack name - if (data.TryGetValue("name", out var name)) Name = name; - // if pack is vanilla, it won't use custom atlas.txt - if (data.TryGetValue("isVanilla", out var isVanillaStr) && - bool.TryParse(isVanillaStr, out var isVanilla)) IsVanilla = isVanilla; - if (data.TryGetValue("supportedVersion", out var supportedVersionStr) && - byte.TryParse(supportedVersionStr, out var supportedVersion)) - Version = supportedVersion; - } - else - { - Log.Error("invalid pack. check if pack is valid using TilePack.Check(string) before creating pack"); - return; - } - // try get atlas - if (File.Exists(Path.Combine(path, "atlas.png"))) - { - AtlasPath = Path.Combine(path, "atlas.png"); - Atlas = LoadTexture(AtlasPath); - } - // try get tile atlas or ignore if pack is vanilla - if (File.Exists(Path.Combine(path, "atlas.txt")) && !IsVanilla) - TileAtlasPath = Path.Combine(path, "atlas.txt"); - } - catch (Exception ex) { Log.Error(ex.ToString()); } - } - - public static bool Check(string path) - { - return File.Exists(Path.Combine(path, "info.txt")); - } - - public void Apply() - { - if (AtlasPath != string.Empty) - { - Program.atlas = Atlas; - } - if (TileAtlasPath != string.Empty && !IsVanilla) - { - Tile.DefaultTiles = Tile.GenerateTiles(TileAtlasPath); - } - } - - public void Unload() - { - UnloadTexture(Atlas); - } - - public override string ToString() - { - return $"Name: {Name}; IsVanilla: {IsVanilla}; PackFormat: {Version}"; - } -} \ No newline at end of file diff --git a/TilePacks/TilePackManager.cs b/TilePacks/TilePackManager.cs deleted file mode 100644 index 8ffd4a2..0000000 --- a/TilePacks/TilePackManager.cs +++ /dev/null @@ -1,47 +0,0 @@ -using BuildingGame.Tiles; - -namespace BuildingGame.TilePacks; - -public static class TilePackManager -{ - public static List TilePacks { get; } = new List(); - public static event Action? PackChanged; - - public static void LoadPacks(string root = "packs") - { - TilePacks.Clear(); - - if (!Directory.Exists(root)) - { - Directory.CreateDirectory(root); - return; - } - - foreach (var packFolder in Directory.GetDirectories(root).Where(s => TilePack.Check(s))) - { - var pack = new TilePack(packFolder); - Log.Information(pack.ToString()); - TilePacks.Add(pack); - } - } - - public static void SetDefaultPack() - { - Program.atlas = Program.origAtlas; - Tile.DefaultTiles = Tile.GenerateTiles(); - PackChanged?.Invoke(); - } - - public static void ApplyPack(string name) - { - var pack = TilePacks.Find(m => m.Name == name); - if (pack.Equals(default(TilePack))) return; - pack.Apply(); - PackChanged?.Invoke(); - } - - internal static void UnloadPacks() - { - foreach (var pack in TilePacks) pack.Unload(); - } -} \ No newline at end of file diff --git a/Tiles/Chunk.cs b/Tiles/Chunk.cs deleted file mode 100644 index 3c471a8..0000000 --- a/Tiles/Chunk.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace BuildingGame.Tiles; - -public class Chunk -{ - public const int SIZE = 16; - - public TileInfo[,] Tiles { get; } - - public Chunk() - { - Tiles = new TileInfo[SIZE, SIZE]; - - for (int x = 0; x < SIZE; x++) - { - for (int y = 0; y < SIZE; y++) - { - Tiles[x, y] = 0; - } - } - } - - public void Draw(int wx, int wy) - { - for (int x = 0; x < SIZE; x++) - { - for (int y = 0; y < SIZE; y++) - { - TileInfo tile = Tiles[x, y]; - - if (tile != null && tile > 0) - { - Tile.GetTile(tile.Type).Draw(wx + x, wy + y, tile.Flags); - } - - } - } - } - - public bool IsValidTile(int x, int y) - { - return x >= 0 && x < SIZE && y >= 0 && y < SIZE; - } -} \ No newline at end of file diff --git a/Tiles/PhysicTileType.cs b/Tiles/PhysicTileType.cs deleted file mode 100644 index feeaccf..0000000 --- a/Tiles/PhysicTileType.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace BuildingGame.Tiles; - -public enum PhysicTileType -{ - Not, - Water, - Lava, - Sand, - Obsidian, - SandCook, - Infection -} \ No newline at end of file diff --git a/Tiles/Tile.cs b/Tiles/Tile.cs deleted file mode 100644 index 24f9908..0000000 --- a/Tiles/Tile.cs +++ /dev/null @@ -1,92 +0,0 @@ -namespace BuildingGame.Tiles; - -public class Tile -{ - internal static Tile[] DefaultTiles = GenerateTiles(); - internal static readonly Texture2D Unknown = LoadTextureFromImage(GenImageChecked(48, 48, 24, 24, Color.MAGENTA, Color.BLACK)); - - public static Tile GetTile(byte type) - { - if (type - 1 > DefaultTiles.Length - 1) - { - return new Tile(Vector2.Zero, "unknown", "?") { IsUnknown = true }; - } - return DefaultTiles[type - 1]; - } - public static Tile GetTile(string id) => DefaultTiles.First(t => t.Id.ToLower() == id.ToLower()); - public static byte GetNId(string id) => (byte)((byte)Array.IndexOf(DefaultTiles, GetTile(id)) + 1); - public static string GetId(byte id) => GetTile(id).Id; - - public Vector2 AtlasOffset { get; } - public Vector2 Size { get; } - public string Id { get; } - public string DisplayName { get; } - public bool IsUnknown { get; set; } - - public Tile(Vector2 atlasOffset, string id, string displayName) - { - AtlasOffset = atlasOffset; - Size = new Vector2(1, 1); - Id = id; - DisplayName = displayName; - } - - public Tile(Vector2 atlasOffset, Vector2 size, string id, string displayName) - { - AtlasOffset = atlasOffset; - Size = size; - Id = id; - DisplayName = displayName; - } - - public void Draw(int x, int y, TileFlags flags) - { - Draw(x, y, flags, Color.WHITE); - } - - public void Draw(int x, int y, TileFlags flags, Color tint) - { - if (IsUnknown) - { - DrawTexturePro( - Unknown, - new Rectangle(0.25f, 0.25f, 48 - 0.25f, 48 - 0.25f), - new Rectangle(x * 48, y * 48, Size.X * 48, Size.Y * 48), - new Vector2(24, 24), - flags.Rotation, - tint - ); - return; - } - DrawTexturePro( - Program.atlas, - new Rectangle(AtlasOffset.X * 16 + 0.25f, AtlasOffset.Y * 16 + 0.25f, Size.X * 16 - 0.25f, Size.Y * 16 - 0.25f), - new Rectangle(x * 48, y * 48, Size.X * 48, Size.Y * 48), - new Vector2(24, 24), - flags.Rotation, - tint - ); - } - - internal static Tile[] GenerateTiles(string atlasText = "assets/atlas.txt") - { - List tiles = new List(); - var ids = ConfigParser.ParseFourth(atlasText); - - for (int i = 0; i < ids.Count; i++) - { - var id = ids.Keys.ToArray()[i]; - var kv = ids[id]; - var coords = ConfigParser.ToVector2i(kv.left); - var size = ConfigParser.ToVector2i(kv.middle); - var dn = kv.right; - - tiles.Add(new Tile(coords, size, id, dn)); - } - - return tiles.ToArray(); - } - - public static implicit operator Tile(string id) => Tile.GetTile(id); - public static implicit operator Tile(byte nid) => Tile.GetTile(nid); -} \ No newline at end of file diff --git a/Tiles/TileFlags.cs b/Tiles/TileFlags.cs deleted file mode 100644 index b2cb02d..0000000 --- a/Tiles/TileFlags.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace BuildingGame.Tiles; - -public struct TileFlags -{ - public static TileFlags Default => new TileFlags(0, false); - public float Rotation { get; set; } - public bool Flip { get; set; } - - public TileFlags(float rotation, bool flip) - { - Rotation = rotation; - Flip = flip; - } -} \ No newline at end of file diff --git a/Tiles/TileInfo.cs b/Tiles/TileInfo.cs deleted file mode 100644 index 7f81ab6..0000000 --- a/Tiles/TileInfo.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace BuildingGame.Tiles; - -public class TileInfo -{ - public byte Type { get; } - public TileFlags Flags { get; } - - public TileInfo(byte type, TileFlags flags) - { - Type = type; - Flags = flags; - } - - public static implicit operator byte(TileInfo info) => info.Type; - public static implicit operator string(TileInfo info) - { - if (info.Type > 0) return Tile.GetId(info.Type); - return ""; - } - public static implicit operator Tile(TileInfo info) => Tile.GetTile(info.Type); - public static implicit operator TileInfo(byte type) => new TileInfo(type, TileFlags.Default); - public static implicit operator TileInfo(string id) => new TileInfo(Tile.GetNId(id), TileFlags.Default); -} \ No newline at end of file diff --git a/Tiles/World.cs b/Tiles/World.cs deleted file mode 100644 index 4d0e8b5..0000000 --- a/Tiles/World.cs +++ /dev/null @@ -1,368 +0,0 @@ -using System.Diagnostics; -using System.IO.Compression; - -namespace BuildingGame.Tiles; - -public class World -{ - public const string WORLD_SAVE_HEADER = "BGWORLD2"; - public string WorldFile { get; set; } = "level.dat"; - public const int CHUNK_AREA = 16; - public Chunk[,] Chunks { get; private set; } = null!; - - public World() - { - FlushChunks(); - } - - public void Draw() - { - for (int cx = 0; cx < CHUNK_AREA; cx++) - { - for (int cy = 0; cy < CHUNK_AREA; cy++) - { - var chunk = Chunks[cx, cy]; - - if (chunk != null) - chunk.Draw(cx * 16, cy * 16); - } - } - } - - List<(int x, int y)> liquidBlocks = new List<(int x, int y)>(); - private void UpdateLiqiud(string id) - { - - for (int x = 0; x < CHUNK_AREA * Chunk.SIZE; x++) - { - for (int y = 0; y < CHUNK_AREA * Chunk.SIZE; y++) - { - if (IsTileA(x, y, id)) - { - liquidBlocks.Add((x, y)); - } - } - } - - foreach (var liquidBlock in liquidBlocks) - { - int x = liquidBlock.x; - int y = liquidBlock.y; - - if (IsTileA(x - 1, y, 0) && !IsTileAOrAir(x, y + 1, id)) - PlaceTile(x - 1, y, id); - else if (IsTileA(x + 1, y, 0) && !IsTileAOrAir(x, y + 1, id)) - PlaceTile(x + 1, y, id); - else if (IsTileA(x, y + 1, 0)) - PlaceTile(x, y + 1, id); - } - - liquidBlocks.Clear(); - } - - List<(int x, int y)> lavaBlocks = new List<(int x, int y)>(); - - public void UpdateObsidian() - { - - for (int x = 0; x < CHUNK_AREA * Chunk.SIZE; x++) - { - for (int y = 0; y < CHUNK_AREA * Chunk.SIZE; y++) - { - if (IsTileA(x, y, "lava")) - { - lavaBlocks.Add((x, y)); - } - } - } - - foreach (var lavaBlock in lavaBlocks) - { - int x = lavaBlock.x; - int y = lavaBlock.y; - - if (CanBeCooked(x, y, "water", "lava")) - PlaceTile(x, y, "obsidian"); - } - - lavaBlocks.Clear(); - } - - List<(int x, int y)> sandBlocks = new List<(int x, int y)>(); - - public void UpdateSand() - { - - for (int x = 0; x < CHUNK_AREA * Chunk.SIZE; x++) - { - for (int y = 0; y < CHUNK_AREA * Chunk.SIZE; y++) - { - if (IsTileA(x, y, "sand")) - { - sandBlocks.Add((x, y)); - } - } - } - - foreach (var sandBlock in sandBlocks) - { - int x = sandBlock.x; - int y = sandBlock.y; - - if (IsTileAOrAir(x, y + 1, "water")) - { - PlaceTile(x, y + 1, Tile.GetNId("sand")); - PlaceTile(x, y, 0); - } - if (CanBeCooked(x, y, "lava", "sand")) - { - PlaceTile(x, y, Tile.GetNId("glass")); - } - } - - sandBlocks.Clear(); - } - - List<(int x, int y)> infectionBlocks = new List<(int x, int y)>(); - - public void UpdateInfection() - { - for (int x = 0; x < CHUNK_AREA * Chunk.SIZE; x++) - { - for (int y = 0; y < CHUNK_AREA * Chunk.SIZE; y++) - { - if (IsTileA(x, y, "infection_block")) - { - infectionBlocks.Add((x, y)); - } - } - } - - foreach (var infectionBlock in infectionBlocks) - { - int x = infectionBlock.x; - int y = infectionBlock.y; - - if (!IsTileAOrAir(x - 1, y, "infection_block")) - PlaceTile(x - 1, y, Tile.GetNId("infection_block")); - if (!IsTileAOrAir(x + 1, y, "infection_block")) - PlaceTile(x + 1, y, Tile.GetNId("infection_block")); - if (!IsTileAOrAir(x, y - 1, "infection_block")) - PlaceTile(x, y - 1, Tile.GetNId("infection_block")); - if (!IsTileAOrAir(x, y + 1, "infection_block")) - PlaceTile(x, y + 1, Tile.GetNId("infection_block")); - } - - infectionBlocks.Clear(); - } - - private bool CanBeCooked(int x, int y, string idSecond, string idMain) - { - if (((IsTileA(x - 1, y, idSecond) || IsTileA(x + 1, y, idSecond)) || - (IsTileA(x, y - 1, idSecond) || IsTileA(x, y + 1, idSecond))) && - IsTileA(x, y, idMain)) - return true; - return false; - } - - byte tick = 0; - - public void Update() - { - if (tick >= 20) tick = 0; - tick++; - - if (!Settings.EnablePhysics) return; - - if (tick == 7) UpdateObsidian(); - if (tick == 9 && Settings.EnableInfectionBlock) UpdateInfection(); - if (tick == 15) UpdateSand(); - if (tick == 10) UpdateLiqiud("water"); - if (tick == 20) UpdateLiqiud("lava"); - } - - public bool IsTileA(int x, int y, string id) - { - return IsValidTile(x, y) && GetTile(x, y) == id; - } - - public bool IsTileA(int x, int y, byte nid) - { - return IsValidTile(x, y) && GetTile(x, y) == nid; - } - - public bool IsTileAOrAir(int x, int y, string id) - { - return IsValidTile(x, y) && (GetTile(x, y) == id || GetTile(x, y) == 0); - } - - public bool IsTileAOrAir(int x, int y, byte nid) - { - return IsValidTile(x, y) && (GetTile(x, y) == nid || GetTile(x, y) == 0); - } - - public void PlaceTile(int x, int y, TileInfo tile) - { - var area = GetChunkArea(x, y); - var chunk = Chunks[area.cx, area.cy]; - - if (chunk != null) - { - chunk.Tiles[area.lcx, area.lcy] = tile; - } - - } - - public void PlaceTile(int cx, int cy, int x, int y, TileInfo tile) - { - var chunk = Chunks[cx, cy]; - - if (chunk != null) - { - chunk.Tiles[x, y] = tile; - } - - } - - public TileInfo GetTile(int x, int y) - { - var area = GetChunkArea(x, y); - var chunk = Chunks[area.cx, area.cy]; - - if (chunk != null) - return chunk.Tiles[area.lcx, area.lcy]; - return 0; - } - - public bool IsValidTile(int x, int y) - { - if (x < 0 || x >= CHUNK_AREA * Chunk.SIZE || y < 0 || y >= CHUNK_AREA * Chunk.SIZE) - return false; - return true; - } - - public TileInfo GetTile(int cx, int cy, int x, int y) - { - var chunk = Chunks[cx, cy]; - if (chunk != null) - return chunk.Tiles[x, y]; - return 0; - } - - public (int cx, int cy, int lcx, int lcy) GetChunkArea(int wx, int wy) - { - - int cx = Math.Clamp((int)(wx / Chunk.SIZE), 0, CHUNK_AREA - 1); - int cy = Math.Clamp((int)(wy / Chunk.SIZE), 0, CHUNK_AREA - 1); - - int lcx = Math.Clamp((wx - Chunk.SIZE * cx), 0, Chunk.SIZE - 1); - int lcy = Math.Clamp((wy - Chunk.SIZE * cy), 0, Chunk.SIZE - 1); - - return (cx, cy, lcx, lcy); - } - - public void Save() - { - try - { - using FileStream fs = File.OpenWrite(WorldFile); - using GZipStream gs = new GZipStream(fs, CompressionMode.Compress); - using BinaryWriter bw = new BinaryWriter(gs); - - bw.Write(WORLD_SAVE_HEADER); - - bw.Write(Program.gameScreen.camera.target.X); - bw.Write(Program.gameScreen.camera.target.Y); - - for (int x = 0; x < World.CHUNK_AREA * Chunk.SIZE; x++) - { - for (int y = 0; y < World.CHUNK_AREA * Chunk.SIZE; y++) - { - WriteTile(bw, GetTile(x, y)); - } - } - } - catch (Exception ex) { Log.Information(ex.ToString()); } - } - - private void FlushChunks() - { - Chunks = new Chunk[CHUNK_AREA, CHUNK_AREA]; - - for (int x = 0; x < CHUNK_AREA; x++) - { - for (int y = 0; y < CHUNK_AREA; y++) - { - Chunks[x, y] = new Chunk(); - } - } - } - - public void Load(string path = "level.dat") - { - try - { - WorldFile = path; - - FlushChunks(); - if (!File.Exists(path)) return; - - using FileStream fs = File.OpenRead(path); - using GZipStream gs = new GZipStream(fs, CompressionMode.Decompress); - using BinaryReader br = new BinaryReader(gs); - string header = br.ReadString(); - // throw new Exception("test"); - - if (header == "LVL") - { - Log.Information("world using old format, reading it using it"); - Log.Information("creating backup"); - - using FileStream backupFs = File.OpenWrite(path + ".old"); - using BinaryWriter backupBw = new BinaryWriter(backupFs); - backupBw.Write("LVL"); - - Log.Information("reading world"); - - for (int x = 0; x < World.CHUNK_AREA * Chunk.SIZE; x++) - { - for (int y = 0; y < World.CHUNK_AREA * Chunk.SIZE; y++) - { - byte tile = br.ReadByte(); - PlaceTile(x, y, tile); - backupBw.Write(tile); - } - } - - Log.Information("success"); - } - else if (header != WORLD_SAVE_HEADER) throw new IOException("world header is invalid"); - else - { - Program.gameScreen.camera.target = new Vector2(br.ReadSingle(), br.ReadSingle()); - for (int x = 0; x < World.CHUNK_AREA * Chunk.SIZE; x++) - { - for (int y = 0; y < World.CHUNK_AREA * Chunk.SIZE; y++) - { - PlaceTile(x, y, ReadTile(br)); - } - } - } - - } - catch (IOException ex) { Log.Information("bad world file\n" + ex); } - catch (Exception ex) { Log.Information(ex.ToString()); } - } - - private void WriteTile(BinaryWriter bw, TileInfo tile) - { - bw.Write(tile.Type); - bw.Write(tile.Flags.Rotation); - bw.Write(tile.Flags.Flip); - } - - private TileInfo ReadTile(BinaryReader br) - { - return new TileInfo(br.ReadByte(), new TileFlags(br.ReadSingle(), br.ReadBoolean())); - } -} \ No newline at end of file diff --git a/assets/atlas.png b/assets/atlas.png deleted file mode 100644 index 30e5ffc17614bea439808d2b8c79fef3c7f30e90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8474 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 Ml2endmNpIgKUy@Tg#Z8m diff --git a/assets/atlas.txt b/assets/atlas.txt deleted file mode 100644 index fb1c98d..0000000 --- a/assets/atlas.txt +++ /dev/null @@ -1,41 +0,0 @@ -smooth_stone:0,0:1,1:Smooth Stone -wooden_planks:1,0:1,1:Wooden Planks -dirt:2,0:1,1:Dirt -grass_block:3,0:1,1:Grass Block -grass:4,0:1,1:Grass -sand:5,0:1,1:Sand -water:6,0:1,1:Water -lava:7,0:1,1:Lava -obsidian:8,0:1,1:Obsidian -door:9,0:1,2:Door -nature_stone:0,1:1,1:Nature Stone -white_plate:1,1:1,1:White Plate -green_plate:2,1:1,1:Green Plate -red_plate:3,1:1,1:Red Plate -blue_plate:4,1:1,1:Blue Plate -chamomile:5,1:1,1:Chamomile -red_tulip:6,1:1,1:Red Tulip -chamomile_pot:7,1:1,1:Chamomile in a Pot -red_tulip_pot:8,1:1,1:Red Tulip in a Pot -wooden_stairs:0,2:1,1:Wooden Stairs -wooden_slab:1,2:1,1:Wooden Slab -stone_stairs:2,2:1,1:Stone Stairs -stone_slab:3,2:1,1:Stone Slab -wooden_pole:4,2:1,1:Wooden Pole -wooden_pole_handle:5,2:1,1:Wooden Pole Handle -stone_pole:6,2:1,1:Stone Pole -stone_pole_handle:7,2:1,1:Stone Pole Handle -log:8,2:1,1:Log -log_top:9,2:1,1:Log Top -foliage:0,3:1,1:Foliage -glass:1,3:1,1:Glass -white_wool:2,3:1,1:White Wool -red_wool:3,3:1,1:Red Wool -green_wool:4,3:1,1:Green Wool -blue_wool:5,3:1,1:Blue Wool -yellow_wool:6,3:1,1:Yellow Wool -black_wool:7,3:1,1:Black Wool -dark_gray_wool:8,3:1,1:Dark Gray Wool -gray_wool:9,3:1,1:Gray Wool -sponge:0,4:1,1:Sponge -infection_block:1,4:1,1:Infection \ No newline at end of file diff --git a/assets/check.png b/assets/check.png deleted file mode 100644 index 2847e9988ba18412b232ad24d20c36838bd6389c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+3?vf;>QaFeV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G}E0G|-o`uchxQ~c~fejvqE666>BpW*3t11}(tv%n*=n1O-sFbFdq&tH)O z6m;@*aSYK2o_pq?AcF!2v*U~XnFl2VK7Y15ChK1OvipFVdQ&MBb@0MZ*lKmY&$ diff --git a/assets/font.ttf b/assets/font.ttf deleted file mode 100644 index cc6e69692e285819f0d1384c24eb22ffb38a9e1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18704 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%0AIVr`NexLS2LP2~`i|LCI6-+UDz}vIg$W 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 G2JXKZX7#rK diff --git a/assets/icon.ico b/assets/icon.ico deleted file mode 100644 index 9a4df4d1914b9fd6af563b05ffafa4fdda64cb3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 95415 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 diff --git a/assets/icon.png b/assets/icon.png deleted file mode 100644 index 7189c629cbffe43990e7108878a458b6227e698b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 301 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G|m0G|-o|NsB1sj019yY}+s%PUr_m^W`;Q&W?zIK#w=6Q|iQ)EhHoYcV9N zF_h~vM5_SxFid6iUjw8BN`m}?fqIbv!vp15NuV5Ofk$L90|Vb-5N14{zaj-FnC0o> z7@`sE+r!OwK!L-VvHi^7J^ypV8GC!Ben%~Mr=(H;(P+y34?(8{Q%sk1OlG)oaFLY< zQ%T6yrZa7luOl6qCTvZM5m(s#?s&&@j!)up)enw2{yVt);M~ft3Hv9uGi;hKrM&z5 d(%J9-vcKo%e6~K@EFWkqgQu&X%Q~loCIA?Ob6@}f From a3b51f0a9558babf353e5edaaaccf5aeb91690d1 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Wed, 18 Oct 2023 10:35:37 +0300 Subject: [PATCH 002/107] initial commit --- Assets/Atlas.json | 0 Assets/Atlas.png | Bin 0 -> 8474 bytes Assets/Checkmark.png | Bin 0 -> 205 bytes Assets/Font.ttf | Bin 0 -> 18704 bytes Assets/Icon.ico | Bin 0 -> 95415 bytes Assets/Icon.png | Bin 0 -> 301 bytes Assets/atlas.txt | 41 +++++++++++++++++++++++ Chunk.cs | 26 +++++++++++++++ Player.cs | 78 +++++++++++++++++++++++++++++++++++++++++++ Program.cs | 33 ++++++++++++++++++ Resources.cs | 6 ++++ Tile.cs | 26 +++++++++++++++ TileKind.cs | 8 +++++ Tiles.cs | 15 +++++++++ World.cs | 31 +++++++++++++++++ 15 files changed, 264 insertions(+) create mode 100644 Assets/Atlas.json create mode 100644 Assets/Atlas.png create mode 100644 Assets/Checkmark.png create mode 100644 Assets/Font.ttf create mode 100644 Assets/Icon.ico create mode 100644 Assets/Icon.png create mode 100644 Assets/atlas.txt create mode 100644 Chunk.cs create mode 100644 Player.cs create mode 100644 Program.cs create mode 100644 Resources.cs create mode 100644 Tile.cs create mode 100644 TileKind.cs create mode 100644 Tiles.cs create mode 100644 World.cs diff --git a/Assets/Atlas.json b/Assets/Atlas.json new file mode 100644 index 0000000..e69de29 diff --git a/Assets/Atlas.png b/Assets/Atlas.png new file mode 100644 index 0000000000000000000000000000000000000000..30e5ffc17614bea439808d2b8c79fef3c7f30e90 GIT binary patch literal 8474 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 Ml2endmNpIgKUy@Tg#Z8m literal 0 HcmV?d00001 diff --git a/Assets/Checkmark.png b/Assets/Checkmark.png new file mode 100644 index 0000000000000000000000000000000000000000..2847e9988ba18412b232ad24d20c36838bd6389c GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+3?vf;>QaFeV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G}E0G|-o`uchxQ~c~fejvqE666>BpW*3t11}(tv%n*=n1O-sFbFdq&tH)O z6m;@*aSYK2o_pq?AcF!2v*U~XnFl2VK7Y15ChK1OvipFVdQ&MBb@0MZ*lKmY&$ literal 0 HcmV?d00001 diff --git a/Assets/Font.ttf b/Assets/Font.ttf new file mode 100644 index 0000000000000000000000000000000000000000..cc6e69692e285819f0d1384c24eb22ffb38a9e1d GIT binary patch literal 18704 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%0AIVr`NexLS2LP2~`i|LCI6-+UDz}vIg$W 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 literal 0 HcmV?d00001 diff --git a/Assets/Icon.png b/Assets/Icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7189c629cbffe43990e7108878a458b6227e698b GIT binary patch literal 301 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G|m0G|-o|NsB1sj019yY}+s%PUr_m^W`;Q&W?zIK#w=6Q|iQ)EhHoYcV9N zF_h~vM5_SxFid6iUjw8BN`m}?fqIbv!vp15NuV5Ofk$L90|Vb-5N14{zaj-FnC0o> z7@`sE+r!OwK!L-VvHi^7J^ypV8GC!Ben%~Mr=(H;(P+y34?(8{Q%sk1OlG)oaFLY< zQ%T6yrZa7luOl6qCTvZM5m(s#?s&&@j!)up)enw2{yVt);M~ft3Hv9uGi;hKrM&z5 d(%J9-vcKo%e6~K@EFWkqgQu&X%Q~loCIA?Ob6@}f literal 0 HcmV?d00001 diff --git a/Assets/atlas.txt b/Assets/atlas.txt new file mode 100644 index 0000000..fb1c98d --- /dev/null +++ b/Assets/atlas.txt @@ -0,0 +1,41 @@ +smooth_stone:0,0:1,1:Smooth Stone +wooden_planks:1,0:1,1:Wooden Planks +dirt:2,0:1,1:Dirt +grass_block:3,0:1,1:Grass Block +grass:4,0:1,1:Grass +sand:5,0:1,1:Sand +water:6,0:1,1:Water +lava:7,0:1,1:Lava +obsidian:8,0:1,1:Obsidian +door:9,0:1,2:Door +nature_stone:0,1:1,1:Nature Stone +white_plate:1,1:1,1:White Plate +green_plate:2,1:1,1:Green Plate +red_plate:3,1:1,1:Red Plate +blue_plate:4,1:1,1:Blue Plate +chamomile:5,1:1,1:Chamomile +red_tulip:6,1:1,1:Red Tulip +chamomile_pot:7,1:1,1:Chamomile in a Pot +red_tulip_pot:8,1:1,1:Red Tulip in a Pot +wooden_stairs:0,2:1,1:Wooden Stairs +wooden_slab:1,2:1,1:Wooden Slab +stone_stairs:2,2:1,1:Stone Stairs +stone_slab:3,2:1,1:Stone Slab +wooden_pole:4,2:1,1:Wooden Pole +wooden_pole_handle:5,2:1,1:Wooden Pole Handle +stone_pole:6,2:1,1:Stone Pole +stone_pole_handle:7,2:1,1:Stone Pole Handle +log:8,2:1,1:Log +log_top:9,2:1,1:Log Top +foliage:0,3:1,1:Foliage +glass:1,3:1,1:Glass +white_wool:2,3:1,1:White Wool +red_wool:3,3:1,1:Red Wool +green_wool:4,3:1,1:Green Wool +blue_wool:5,3:1,1:Blue Wool +yellow_wool:6,3:1,1:Yellow Wool +black_wool:7,3:1,1:Black Wool +dark_gray_wool:8,3:1,1:Dark Gray Wool +gray_wool:9,3:1,1:Gray Wool +sponge:0,4:1,1:Sponge +infection_block:1,4:1,1:Infection \ No newline at end of file diff --git a/Chunk.cs b/Chunk.cs new file mode 100644 index 0000000..302808d --- /dev/null +++ b/Chunk.cs @@ -0,0 +1,26 @@ +namespace BuildingGame; + +public struct Chunk +{ + public const int Size = 16; + + public World World; + public readonly int X, Y; + + public Chunk(World world, int x, int y) + { + World = world; + X = x; + Y = y; + } + + public void Update() + { + + } + + public void Draw() + { + + } +} \ No newline at end of file diff --git a/Player.cs b/Player.cs new file mode 100644 index 0000000..19207cd --- /dev/null +++ b/Player.cs @@ -0,0 +1,78 @@ +using System.Numerics; +using ZeroElectric.Vinculum; + +namespace BuildingGame; + +public class Player +{ + public Camera2D Camera; + public float Speed; + public float LerpSpeed; + + private Vector2 _targetPosition; + private float _targetZoom; + + public Player(Vector2 position, float speed, float lerpSpeed) + { + Camera = new Camera2D + { + offset = new Vector2(GetScreenWidth(), GetScreenHeight()) / 2, + target = position, + zoom = 1.0f + }; + _targetPosition = position; + _targetZoom = 1.0f; + Speed = speed; + LerpSpeed = lerpSpeed; + } + + public void Update() + { + Camera.target = Vector2.Lerp(Camera.target, _targetPosition, LerpSpeed); // lerp camera position to target position + Camera.zoom = (Camera.zoom * (1.0f - LerpSpeed)) + (_targetZoom * LerpSpeed); // lerp camera zoom to target zoom + + // zoom in/zoom out camera + float scrollDelta = GetMouseWheelMove(); + if (scrollDelta < 0) ZoomOut(Speed * 0.1f); + if (scrollDelta > 0) ZoomIn(Speed * 0.1f); + + // get speed depending if user is sprinting or not + float speed = IsKeyDown(KeyboardKey.KEY_LEFT_CONTROL) || IsKeyDown(KeyboardKey.KEY_LEFT_SHIFT) + ? Speed * 1.25f + : Speed * 0.5f; + + // move camera + if (IsKeyDown(KeyboardKey.KEY_W)) Move(0, -speed); + if (IsKeyDown(KeyboardKey.KEY_S)) Move(0, speed); + if (IsKeyDown(KeyboardKey.KEY_A)) Move(-speed, 0); + if (IsKeyDown(KeyboardKey.KEY_D)) Move(speed, 0); + + // adapt camera center when windows is resized + if (IsWindowResized()) + { + Camera.offset = new Vector2(GetScreenWidth(), GetScreenHeight()) / 2; + } + } + + public void ZoomIn(float a) + { + _targetZoom += a * GetFrameTime(); + } + + public void ZoomOut(float a) + { + _targetZoom -= a * GetFrameTime(); + // clamp zoom, so camera wont get inverted + if (_targetZoom < 0.01f) _targetZoom = 0.01f; + } + + public void MoveTo(float x, float y) + { + _targetPosition = new Vector2(x, y); + } + + public void Move(float x, float y) + { + _targetPosition += new Vector2(x, y) * Speed * GetFrameTime(); + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..a5fa458 --- /dev/null +++ b/Program.cs @@ -0,0 +1,33 @@ +global using static ZeroElectric.Vinculum.Raylib; +global using ZeroElectric.Vinculum; +using System.Numerics; +using BuildingGame; + +SetConfigFlags(ConfigFlags.FLAG_VSYNC_HINT); +SetConfigFlags(ConfigFlags.FLAG_WINDOW_RESIZABLE); +InitWindow(1024, 768, "building game"); + +// set window icon +Image icon = LoadImage("Assets/Icon.png"); +SetWindowIcon(icon); +UnloadImage(icon); + +Player player = new Player(new Vector2(0), 50, 0.1f); + +while (!WindowShouldClose()) +{ + player.Update(); + + BeginDrawing(); + ClearBackground(SKYBLUE); + + BeginMode2D(player.Camera); + { + DrawRectangle(0, 0, 128, 128, RED); + } + EndMode2D(); + + EndDrawing(); +} + +CloseWindow(); \ No newline at end of file diff --git a/Resources.cs b/Resources.cs new file mode 100644 index 0000000..5bdd79d --- /dev/null +++ b/Resources.cs @@ -0,0 +1,6 @@ +namespace BuildingGame; + +public static class Resources +{ + +} \ No newline at end of file diff --git a/Tile.cs b/Tile.cs new file mode 100644 index 0000000..c38187b --- /dev/null +++ b/Tile.cs @@ -0,0 +1,26 @@ +using System.Numerics; + +namespace BuildingGame; + +public class Tile +{ + public readonly Vector2 TexCoord; + + public Tile() + { + TexCoord = Vector2.Zero; + } + + public Tile(Vector2 texCoord) + { + TexCoord = texCoord; + } + + public virtual void Update(World world, int x, int y) {} + + public virtual void Draw(World world, int x, int y) + { + DrawTexturePro( + ); + } +} \ No newline at end of file diff --git a/TileKind.cs b/TileKind.cs new file mode 100644 index 0000000..531e035 --- /dev/null +++ b/TileKind.cs @@ -0,0 +1,8 @@ +namespace BuildingGame; + +public enum TileKind +{ + Air, + Grass, + Dirt +} \ No newline at end of file diff --git a/Tiles.cs b/Tiles.cs new file mode 100644 index 0000000..96a0dd4 --- /dev/null +++ b/Tiles.cs @@ -0,0 +1,15 @@ +namespace BuildingGame; + +public static class Tiles +{ + private static Dictionary _tiles = new Dictionary() + { + { TileKind.Dirt, new Tile() } + }; + + public static Tile GetTile(TileKind kind) + { + if (kind == TileKind.Air) throw new ArgumentException("TileKind could not be an Air", nameof(kind)); + return _tiles[kind]; + } +} \ No newline at end of file diff --git a/World.cs b/World.cs new file mode 100644 index 0000000..e7b9b71 --- /dev/null +++ b/World.cs @@ -0,0 +1,31 @@ +namespace BuildingGame; + +public struct World +{ + public readonly int Width; + public readonly int Height; + public readonly int ChunkWidth; + public readonly int ChunkHeight; + + private Chunk[][] _chunks; + + public World(int width, int height) + { + Width = width; + Height = height; + ChunkWidth = width / Chunk.Size; + ChunkHeight = height / Chunk.Size; + + _chunks = new Chunk[ChunkWidth][]; + for (int x = 0; x < ChunkWidth; x++) + { + _chunks[x] = new Chunk[ChunkHeight]; + for (int y = 0; y < ChunkHeight; y++) + { + _chunks[x][y] = new Chunk(); + } + } + } + + +} \ No newline at end of file From d2993363a4866a3214ea5eb2bbe903a6f9088dec Mon Sep 17 00:00:00 2001 From: danilwhale Date: Wed, 18 Oct 2023 10:36:49 +0300 Subject: [PATCH 003/107] update packages --- BuildingGame.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BuildingGame.csproj b/BuildingGame.csproj index 553143f..72032a9 100644 --- a/BuildingGame.csproj +++ b/BuildingGame.csproj @@ -26,10 +26,10 @@ - - - - + + + + From f7c578e48349844d9395d617db905fc059b276fc Mon Sep 17 00:00:00 2001 From: Danil <61111955+danilwhale@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:54:10 +0300 Subject: [PATCH 004/107] Create README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..4849ea1 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# BuildingGame +game where you can just place tiles +> Warning: this is temporairy branch and maybe will become main after 21 years From 05bd1b45daab902fcf3ed854f7c89eb2039b4767 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Wed, 18 Oct 2023 19:41:50 +0300 Subject: [PATCH 005/107] implement basic tile --- Program.cs | 1 + Resources.cs | 21 ++++++++++++++++++++- Tile.cs | 28 ++++++++++++++++++++++++---- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/Program.cs b/Program.cs index a5fa458..fbe9dea 100644 --- a/Program.cs +++ b/Program.cs @@ -30,4 +30,5 @@ EndDrawing(); } +Resources.Free(); CloseWindow(); \ No newline at end of file diff --git a/Resources.cs b/Resources.cs index 5bdd79d..425adc9 100644 --- a/Resources.cs +++ b/Resources.cs @@ -2,5 +2,24 @@ namespace BuildingGame; public static class Resources { - + private static Dictionary _textures = new Dictionary(); + + public static Texture GetTexture(string key) + { + key = key.ToLower(); + if (_textures.TryGetValue(key, out var texture)) return texture; + + texture = LoadTexture("Assets/" + key); + _textures[key] = texture; + return texture; + } + + public static void Free() + { + foreach (var texture in _textures) + { + UnloadTexture(texture.Value); + } + _textures.Clear(); + } } \ No newline at end of file diff --git a/Tile.cs b/Tile.cs index c38187b..f5533e8 100644 --- a/Tile.cs +++ b/Tile.cs @@ -4,23 +4,43 @@ namespace BuildingGame; public class Tile { + public const int TileSize = 16; + public const float TileUpscale = 3; + public const float AtlasFraction = 0.25f; + public readonly Vector2 TexCoord; public Tile() { TexCoord = Vector2.Zero; } - + public Tile(Vector2 texCoord) { TexCoord = texCoord; } - public virtual void Update(World world, int x, int y) {} + public virtual void Update(World world, int x, int y) + { + } public virtual void Draw(World world, int x, int y) { - DrawTexturePro( - ); + DrawTexturePro(Resources.GetTexture("Atlas.png"), + // we add a fraction to the source rectangle, so we wont see flickering parts of atlas + new Rectangle( + TexCoord.X * TileSize + AtlasFraction, + TexCoord.Y * TileSize + AtlasFraction, + TileSize - AtlasFraction, + TileSize - AtlasFraction + ), + new Rectangle( + x * TileSize * TileUpscale, + y * TileSize * TileUpscale, + TileSize * TileUpscale, + TileSize * TileUpscale + ), + Vector2.Zero, 0, WHITE + ); } } \ No newline at end of file From 73b8862e01929bbb6f4b6e8d6c5d3bb66a96dfa2 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Wed, 18 Oct 2023 21:04:12 +0300 Subject: [PATCH 006/107] move all tiles --- Player.cs | 2 ++ Program.cs | 7 ++++++- Tile.cs | 5 +++++ TileKind.cs | 43 +++++++++++++++++++++++++++++++++++++++++-- Tiles.cs | 45 +++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 97 insertions(+), 5 deletions(-) diff --git a/Player.cs b/Player.cs index 19207cd..eb7432c 100644 --- a/Player.cs +++ b/Player.cs @@ -40,6 +40,8 @@ public void Update() float speed = IsKeyDown(KeyboardKey.KEY_LEFT_CONTROL) || IsKeyDown(KeyboardKey.KEY_LEFT_SHIFT) ? Speed * 1.25f : Speed * 0.5f; + speed /= Camera.zoom; + speed = Math.Clamp(speed, 0, Speed * 2); // move camera if (IsKeyDown(KeyboardKey.KEY_W)) Move(0, -speed); diff --git a/Program.cs b/Program.cs index fbe9dea..a42d40c 100644 --- a/Program.cs +++ b/Program.cs @@ -13,6 +13,8 @@ UnloadImage(icon); Player player = new Player(new Vector2(0), 50, 0.1f); +World world = new World(256, 256); +TileKind[] tiles = Enum.GetValues(); while (!WindowShouldClose()) { @@ -23,7 +25,10 @@ BeginMode2D(player.Camera); { - DrawRectangle(0, 0, 128, 128, RED); + for (int i = 1; i < tiles.Length; i++) + { + Tiles.GetTile(tiles[i]).Draw(world, i, 0); + } } EndMode2D(); diff --git a/Tile.cs b/Tile.cs index f5533e8..1ad8cae 100644 --- a/Tile.cs +++ b/Tile.cs @@ -20,6 +20,11 @@ public Tile(Vector2 texCoord) TexCoord = texCoord; } + public Tile(float tx, float ty) + { + TexCoord = new Vector2(tx, ty); + } + public virtual void Update(World world, int x, int y) { } diff --git a/TileKind.cs b/TileKind.cs index 531e035..a32b5ef 100644 --- a/TileKind.cs +++ b/TileKind.cs @@ -1,8 +1,47 @@ namespace BuildingGame; -public enum TileKind +public enum TileKind : byte { Air, + SmoothStone, + Planks, + Dirt, + GrassBlock, Grass, - Dirt + Sand, + Water, + Lava, + Obsidian, + Door, + Stone, + WhitePlate, + GreenPlate, + RedPlate, + BluePlate, + Chamomile, + RedTulip, + ChamomilePot, + RedTulipPot, + WoodenStairs, + WoodenSlab, + StoneStairs, + StoneSlab, + WoodenPole, + WoodenPoleHandle, + StonePole, + StonePoleHandle, + Log, + LogTop, + Leaves, + Glass, + WhiteWool, + RedWool, + GreenWool, + BlueWool, + YellowWool, + BlackWool, + DarkGrayWool, + GrayWool, + Sponge, + InfectionBlock } \ No newline at end of file diff --git a/Tiles.cs b/Tiles.cs index 96a0dd4..11863cf 100644 --- a/Tiles.cs +++ b/Tiles.cs @@ -2,9 +2,50 @@ namespace BuildingGame; public static class Tiles { - private static Dictionary _tiles = new Dictionary() + // this wont be for long because i'll implement tile loading from atlas.json lmao + private static readonly Dictionary _tiles = new Dictionary() { - { TileKind.Dirt, new Tile() } + { TileKind.SmoothStone, new Tile(0, 0) }, + { TileKind.Planks, new Tile(1, 0) }, + { TileKind.Dirt, new Tile(2, 0) }, + { TileKind.GrassBlock, new Tile(3, 0) }, + { TileKind.Grass, new Tile(4, 0) }, + { TileKind.Sand, new Tile(5, 0) }, + { TileKind.Water, new Tile(6, 0) }, + { TileKind.Lava, new Tile(7, 0) }, + { TileKind.Obsidian, new Tile(8, 0) }, + { TileKind.Door, new Tile(9, 0) }, // atm it will be built from 1 tile + { TileKind.Stone, new Tile(0, 1) }, + { TileKind.WhitePlate, new Tile(1, 1) }, + { TileKind.GreenPlate, new Tile(2, 1) }, + { TileKind.RedPlate, new Tile(3, 1) }, + { TileKind.BluePlate, new Tile(4, 1) }, + { TileKind.Chamomile, new Tile(5, 1) }, + { TileKind.RedTulip, new Tile(6, 1) }, + { TileKind.ChamomilePot, new Tile(7, 1) }, + { TileKind.RedTulipPot, new Tile(8, 1) }, + { TileKind.WoodenStairs, new Tile(0, 2) }, + { TileKind.WoodenSlab, new Tile(1, 2) }, + { TileKind.StoneStairs, new Tile(2, 2) }, + { TileKind.StoneSlab, new Tile(3, 2) }, + { TileKind.WoodenPole, new Tile(4, 2) }, + { TileKind.WoodenPoleHandle, new Tile(5, 2) }, + { TileKind.StonePole, new Tile(6, 2) }, + { TileKind.StonePoleHandle, new Tile(7, 2) }, + { TileKind.Log, new Tile(8, 2) }, + { TileKind.LogTop, new Tile(9, 2) }, + { TileKind.Leaves, new Tile(0, 3) }, + { TileKind.Glass, new Tile(1, 3) }, + { TileKind.WhiteWool, new Tile(2, 3) }, + { TileKind.RedWool, new Tile(3, 3) }, + { TileKind.GreenWool, new Tile(4, 3) }, + { TileKind.BlueWool, new Tile(5, 3) }, + { TileKind.YellowWool, new Tile(6, 3) }, + { TileKind.BlackWool, new Tile(7, 3) }, + { TileKind.DarkGrayWool, new Tile(8, 3) }, + { TileKind.GrayWool, new Tile(9, 3) }, + { TileKind.Sponge, new Tile(0, 4) }, + { TileKind.InfectionBlock, new Tile(1, 4) } }; public static Tile GetTile(TileKind kind) From dfa92861b73cb1b6fd9238a30a482501024e8ab0 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Wed, 18 Oct 2023 22:47:16 +0300 Subject: [PATCH 007/107] implement basic world --- Chunk.cs | 45 ++++++++++++++++++++++++++++++++-- ChunkPosition.cs | 17 +++++++++++++ Player.cs | 12 +++++++-- Program.cs | 15 ++++++++---- World.cs | 63 +++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 139 insertions(+), 13 deletions(-) create mode 100644 ChunkPosition.cs diff --git a/Chunk.cs b/Chunk.cs index 302808d..255ebec 100644 --- a/Chunk.cs +++ b/Chunk.cs @@ -3,24 +3,65 @@ namespace BuildingGame; public struct Chunk { public const int Size = 16; + public const float ViewSize = Size * Tile.TileSize * Tile.TileUpscale; public World World; public readonly int X, Y; + private TileKind[][] _tiles; + public Chunk(World world, int x, int y) { World = world; X = x; Y = y; + + _tiles = new TileKind[Size][]; + for (int i = 0; i < Size; i++) + { + _tiles[i] = new TileKind[Size]; + } } public void Update() { - + for (int x = 0; x < Size; x++) + { + for (int y = 0; y < Size; y++) + { + TileKind tile = _tiles[x][y]; + if (tile == TileKind.Air) continue; + Tiles.GetTile(tile).Update(World, X * Size + x, Y * Size + y); + } + } } public void Draw() { - + for (int x = 0; x < Size; x++) + { + for (int y = 0; y < Size; y++) + { + TileKind tile = _tiles[x][y]; + if (tile == TileKind.Air) continue; + Tiles.GetTile(tile).Draw(World, X * Size + x, Y * Size + y); + } + } + } + + public TileKind this[int x, int y] + { + get + { + if (x < 0 || x >= Size || y < 0 || y >= Size) + return TileKind.Air; + return _tiles[x][y]; + } + set + { + if (x < 0 || x >= Size || y < 0 || y >= Size) + return; + _tiles[x][y] = value; + } } } \ No newline at end of file diff --git a/ChunkPosition.cs b/ChunkPosition.cs new file mode 100644 index 0000000..056923a --- /dev/null +++ b/ChunkPosition.cs @@ -0,0 +1,17 @@ +namespace BuildingGame; + +public record ChunkPosition(int X, int Y) +{ + /// + /// Calculates local to chunk position from world position + /// + /// World X + /// World Y + /// Output tile X position + /// Output tile Y position + public void WorldToTile(int x, int y, out int tx, out int ty) + { + tx = x - X * Chunk.Size; + ty = y - Y * Chunk.Size; + } +} \ No newline at end of file diff --git a/Player.cs b/Player.cs index eb7432c..530e473 100644 --- a/Player.cs +++ b/Player.cs @@ -33,8 +33,8 @@ public void Update() // zoom in/zoom out camera float scrollDelta = GetMouseWheelMove(); - if (scrollDelta < 0) ZoomOut(Speed * 0.1f); - if (scrollDelta > 0) ZoomIn(Speed * 0.1f); + if (scrollDelta < 0) ZoomOut(Speed * 0.075f); + if (scrollDelta > 0) ZoomIn(Speed * 0.075f); // get speed depending if user is sprinting or not float speed = IsKeyDown(KeyboardKey.KEY_LEFT_CONTROL) || IsKeyDown(KeyboardKey.KEY_LEFT_SHIFT) @@ -77,4 +77,12 @@ public void Move(float x, float y) { _targetPosition += new Vector2(x, y) * Speed * GetFrameTime(); } + + public Rectangle GetViewRectangle() + { + Vector2 min = GetScreenToWorld2D(new Vector2(0, 0), Camera); + Vector2 max = GetScreenToWorld2D(new Vector2(GetScreenWidth(), GetScreenHeight()), Camera); + + return new Rectangle(min.X, min.Y, max.X - min.X, max.Y - min.Y); + } } \ No newline at end of file diff --git a/Program.cs b/Program.cs index a42d40c..37e3a43 100644 --- a/Program.cs +++ b/Program.cs @@ -14,21 +14,26 @@ Player player = new Player(new Vector2(0), 50, 0.1f); World world = new World(256, 256); -TileKind[] tiles = Enum.GetValues(); + +for (int x = 0; x < world.Width; x++) +{ + for (int y = 0; y < world.Height; y++) + { + world[x, y] = (TileKind)Random.Shared.Next(41); + } +} while (!WindowShouldClose()) { player.Update(); + world.Update(); BeginDrawing(); ClearBackground(SKYBLUE); BeginMode2D(player.Camera); { - for (int i = 1; i < tiles.Length; i++) - { - Tiles.GetTile(tiles[i]).Draw(world, i, 0); - } + world.Draw(player); } EndMode2D(); diff --git a/World.cs b/World.cs index e7b9b71..b2ce9c5 100644 --- a/World.cs +++ b/World.cs @@ -6,7 +6,7 @@ public struct World public readonly int Height; public readonly int ChunkWidth; public readonly int ChunkHeight; - + private Chunk[][] _chunks; public World(int width, int height) @@ -22,10 +22,65 @@ public World(int width, int height) _chunks[x] = new Chunk[ChunkHeight]; for (int y = 0; y < ChunkHeight; y++) { - _chunks[x][y] = new Chunk(); + _chunks[x][y] = new Chunk(this, x, y); + } + } + } + + public void Update() + { + for (int x = 0; x < ChunkWidth; x++) + { + for (int y = 0; y < ChunkHeight; y++) + { + _chunks[x][y].Update(); } } } - - + + public void Draw(Player player) + { + Rectangle view = player.GetViewRectangle(); + + for (int x = 0; x < ChunkWidth; x++) + { + for (int y = 0; y < ChunkHeight; y++) + { + if (CheckCollisionRecs(new Rectangle(x * Chunk.ViewSize, y * Chunk.ViewSize, Chunk.ViewSize, Chunk.ViewSize), view)) + _chunks[x][y].Draw(); + } + } + } + + public ChunkPosition WorldToChunk(int x, int y) + { + int cx = x / Chunk.Size; + int cy = y / Chunk.Size; + + return new ChunkPosition(cx, cy); + } + + public TileKind this[int x, int y] + { + get + { + if (x < 0 || x >= Width || y < 0 || y >= Height) + return TileKind.Air; + + ChunkPosition pos = WorldToChunk(x, y); + pos.WorldToTile(x, y, out int tx, out int ty); + + return _chunks[pos.X][pos.Y][tx, ty]; + } + set + { + if (x < 0 || x >= Width || y < 0 || y >= Height) + return; + + ChunkPosition pos = WorldToChunk(x, y); + pos.WorldToTile(x, y, out int tx, out int ty); + + _chunks[pos.X][pos.Y][tx, ty] = value; + } + } } \ No newline at end of file From 41b448fae2d70a97257e1ed7602797d3ad31aa2a Mon Sep 17 00:00:00 2001 From: danilwhale Date: Thu, 19 Oct 2023 10:46:04 +0300 Subject: [PATCH 008/107] added ability to place tiles --- Chunk.cs | 2 +- Player.cs | 26 +++++++++++++++++++++++++- Program.cs | 10 +--------- Tile.cs | 21 +++++++++++++++++++++ 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/Chunk.cs b/Chunk.cs index 255ebec..0475821 100644 --- a/Chunk.cs +++ b/Chunk.cs @@ -3,7 +3,7 @@ namespace BuildingGame; public struct Chunk { public const int Size = 16; - public const float ViewSize = Size * Tile.TileSize * Tile.TileUpscale; + public const float ViewSize = Size * Tile.RealTileSize; public World World; public readonly int X, Y; diff --git a/Player.cs b/Player.cs index 530e473..80f594d 100644 --- a/Player.cs +++ b/Player.cs @@ -6,14 +6,18 @@ namespace BuildingGame; public class Player { public Camera2D Camera; + public World World; public float Speed; public float LerpSpeed; private Vector2 _targetPosition; private float _targetZoom; - public Player(Vector2 position, float speed, float lerpSpeed) + private TileKind _currentTile = TileKind.Stone; + + public Player(World world, Vector2 position, float speed, float lerpSpeed) { + World = world; Camera = new Camera2D { offset = new Vector2(GetScreenWidth(), GetScreenHeight()) / 2, @@ -54,6 +58,26 @@ public void Update() { Camera.offset = new Vector2(GetScreenWidth(), GetScreenHeight()) / 2; } + + UpdateTileControls(); + } + + private void UpdateTileControls() + { + Vector2 worldMousePos = GetScreenToWorld2D(GetMousePosition(), Camera); + + int tx = (int)(worldMousePos.X / Tile.RealTileSize); + int ty = (int)(worldMousePos.Y / Tile.RealTileSize); + + if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_LEFT)) + { + World[tx, ty] = _currentTile; + } + + if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_RIGHT)) + { + World[tx, ty] = TileKind.Air; + } } public void ZoomIn(float a) diff --git a/Program.cs b/Program.cs index 37e3a43..7280158 100644 --- a/Program.cs +++ b/Program.cs @@ -12,16 +12,8 @@ SetWindowIcon(icon); UnloadImage(icon); -Player player = new Player(new Vector2(0), 50, 0.1f); World world = new World(256, 256); - -for (int x = 0; x < world.Width; x++) -{ - for (int y = 0; y < world.Height; y++) - { - world[x, y] = (TileKind)Random.Shared.Next(41); - } -} +Player player = new Player(world, new Vector2(0), 50, 0.1f); while (!WindowShouldClose()) { diff --git a/Tile.cs b/Tile.cs index 1ad8cae..574dcbc 100644 --- a/Tile.cs +++ b/Tile.cs @@ -6,6 +6,7 @@ public class Tile { public const int TileSize = 16; public const float TileUpscale = 3; + public const float RealTileSize = TileSize * TileUpscale; public const float AtlasFraction = 0.25f; public readonly Vector2 TexCoord; @@ -48,4 +49,24 @@ public virtual void Draw(World world, int x, int y) Vector2.Zero, 0, WHITE ); } + + public virtual void DrawPreview(float x, float y) + { + DrawTexturePro(Resources.GetTexture("Atlas.png"), + // we add a fraction to the source rectangle, so we wont see flickering parts of atlas + new Rectangle( + TexCoord.X * TileSize + AtlasFraction, + TexCoord.Y * TileSize + AtlasFraction, + TileSize - AtlasFraction, + TileSize - AtlasFraction + ), + new Rectangle( + x * TileSize * TileUpscale, + y * TileSize * TileUpscale, + TileSize * TileUpscale, + TileSize * TileUpscale + ), + Vector2.Zero, 0, new Color(255, 255, 255, 120) + ); + } } \ No newline at end of file From 4e8d1858cfe3f57e5c17d75b258e27939ee7a414 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Thu, 19 Oct 2023 12:48:53 +0300 Subject: [PATCH 009/107] implement tile loading from json --- Assets/Atlas.json | 252 ++++++++++++++++++++++++++++++++++++++++++ Assets/atlas.txt | 41 ------- Atlas/AtlasLoader.cs | 33 ++++++ Atlas/AtlasTile.cs | 16 +++ Atlas/AtlasTileKey.cs | 13 +++ Atlas/JsonVec2.cs | 11 ++ BuildingGame.csproj | 1 + Chunk.cs | 18 +-- Player.cs | 4 +- Program.cs | 3 + Tile.cs | 15 ++- TileKind.cs | 47 -------- Tiles.cs | 74 +++++-------- World.cs | 4 +- 14 files changed, 380 insertions(+), 152 deletions(-) delete mode 100644 Assets/atlas.txt create mode 100644 Atlas/AtlasLoader.cs create mode 100644 Atlas/AtlasTile.cs create mode 100644 Atlas/AtlasTileKey.cs create mode 100644 Atlas/JsonVec2.cs delete mode 100644 TileKind.cs diff --git a/Assets/Atlas.json b/Assets/Atlas.json index e69de29..2e4e9fb 100644 --- a/Assets/Atlas.json +++ b/Assets/Atlas.json @@ -0,0 +1,252 @@ +{ + "smooth_stone": { + "AtlasOffset": { + "X": 0, + "Y": 0 + } + }, + "wooden_planks": { + "AtlasOffset": { + "X": 1, + "Y": 0 + } + }, + "dirt": { + "AtlasOffset": { + "X": 2, + "Y": 0 + } + }, + "grass_block": { + "AtlasOffset": { + "X": 3, + "Y": 0 + } + }, + "grass": { + "AtlasOffset": { + "X": 4, + "Y": 0 + } + }, + "sand": { + "AtlasOffset": { + "X": 5, + "Y": 0 + } + }, + "water": { + "AtlasOffset": { + "X": 6, + "Y": 0 + } + }, + "lava": { + "AtlasOffset": { + "X": 7, + "Y": 0 + } + }, + "obsidian": { + "AtlasOffset": { + "X": 8, + "Y": 0 + } + }, + "door": { + "AtlasOffset": { + "X": 9, + "Y": 0 + }, + "Size": { + "X": 1, + "Y": 2 + } + }, + "nature_stone": { + "AtlasOffset": { + "X": 0, + "Y": 1 + } + }, + "white_plate": { + "AtlasOffset": { + "X": 1, + "Y": 1 + } + }, + "green_plate": { + "AtlasOffset": { + "X": 2, + "Y": 1 + } + }, + "red_plate": { + "AtlasOffset": { + "X": 3, + "Y": 1 + } + }, + "blue_plate": { + "AtlasOffset": { + "X": 4, + "Y": 1 + } + }, + "chamomile": { + "AtlasOffset": { + "X": 5, + "Y": 1 + } + }, + "red_tulip": { + "AtlasOffset": { + "X": 6, + "Y": 1 + } + }, + "chamomile_pot": { + "AtlasOffset": { + "X": 7, + "Y": 1 + } + }, + "red_tulip_pot": { + "AtlasOffset": { + "X": 8, + "Y": 1 + } + }, + "wooden_stairs": { + "AtlasOffset": { + "X": 0, + "Y": 2 + } + }, + "wooden_slab": { + "AtlasOffset": { + "X": 1, + "Y": 2 + } + }, + "stone_stairs": { + "AtlasOffset": { + "X": 2, + "Y": 2 + } + }, + "stone_slab": { + "AtlasOffset": { + "X": 3, + "Y": 2 + } + }, + "wooden_pole": { + "AtlasOffset": { + "X": 4, + "Y": 2 + } + }, + "wooden_pole_handle": { + "AtlasOffset": { + "X": 5, + "Y": 2 + } + }, + "stone_pole": { + "AtlasOffset": { + "X": 6, + "Y": 2 + } + }, + "stone_pole_handle": { + "AtlasOffset": { + "X": 7, + "Y": 2 + } + }, + "log": { + "AtlasOffset": { + "X": 8, + "Y": 2 + } + }, + "log_top": { + "AtlasOffset": { + "X": 9, + "Y": 2 + } + }, + "foliage": { + "AtlasOffset": { + "X": 0, + "Y": 3 + } + }, + "glass": { + "AtlasOffset": { + "X": 1, + "Y": 3 + } + }, + "white_wool": { + "AtlasOffset": { + "X": 2, + "Y": 3 + } + }, + "red_wool": { + "AtlasOffset": { + "X": 3, + "Y": 3 + } + }, + "green_wool": { + "AtlasOffset": { + "X": 4, + "Y": 3 + } + }, + "blue_wool": { + "AtlasOffset": { + "X": 5, + "Y": 3 + } + }, + "yellow_wool": { + "AtlasOffset": { + "X": 6, + "Y": 3 + } + }, + "black_wool": { + "AtlasOffset": { + "X": 7, + "Y": 3 + } + }, + "dark_gray_wool": { + "AtlasOffset": { + "X": 8, + "Y": 3 + } + }, + "gray_wool": { + "AtlasOffset": { + "X": 9, + "Y": 3 + } + }, + "sponge": { + "AtlasOffset": { + "X": 0, + "Y": 4 + } + }, + "infection_block": { + "AtlasOffset": { + "X": 1, + "Y": 4 + } + } +} diff --git a/Assets/atlas.txt b/Assets/atlas.txt deleted file mode 100644 index fb1c98d..0000000 --- a/Assets/atlas.txt +++ /dev/null @@ -1,41 +0,0 @@ -smooth_stone:0,0:1,1:Smooth Stone -wooden_planks:1,0:1,1:Wooden Planks -dirt:2,0:1,1:Dirt -grass_block:3,0:1,1:Grass Block -grass:4,0:1,1:Grass -sand:5,0:1,1:Sand -water:6,0:1,1:Water -lava:7,0:1,1:Lava -obsidian:8,0:1,1:Obsidian -door:9,0:1,2:Door -nature_stone:0,1:1,1:Nature Stone -white_plate:1,1:1,1:White Plate -green_plate:2,1:1,1:Green Plate -red_plate:3,1:1,1:Red Plate -blue_plate:4,1:1,1:Blue Plate -chamomile:5,1:1,1:Chamomile -red_tulip:6,1:1,1:Red Tulip -chamomile_pot:7,1:1,1:Chamomile in a Pot -red_tulip_pot:8,1:1,1:Red Tulip in a Pot -wooden_stairs:0,2:1,1:Wooden Stairs -wooden_slab:1,2:1,1:Wooden Slab -stone_stairs:2,2:1,1:Stone Stairs -stone_slab:3,2:1,1:Stone Slab -wooden_pole:4,2:1,1:Wooden Pole -wooden_pole_handle:5,2:1,1:Wooden Pole Handle -stone_pole:6,2:1,1:Stone Pole -stone_pole_handle:7,2:1,1:Stone Pole Handle -log:8,2:1,1:Log -log_top:9,2:1,1:Log Top -foliage:0,3:1,1:Foliage -glass:1,3:1,1:Glass -white_wool:2,3:1,1:White Wool -red_wool:3,3:1,1:Red Wool -green_wool:4,3:1,1:Green Wool -blue_wool:5,3:1,1:Blue Wool -yellow_wool:6,3:1,1:Yellow Wool -black_wool:7,3:1,1:Black Wool -dark_gray_wool:8,3:1,1:Dark Gray Wool -gray_wool:9,3:1,1:Gray Wool -sponge:0,4:1,1:Sponge -infection_block:1,4:1,1:Infection \ No newline at end of file diff --git a/Atlas/AtlasLoader.cs b/Atlas/AtlasLoader.cs new file mode 100644 index 0000000..44d1797 --- /dev/null +++ b/Atlas/AtlasLoader.cs @@ -0,0 +1,33 @@ +using Newtonsoft.Json; + +namespace BuildingGame.Atlas; + +public static class AtlasLoader +{ + public const string AtlasFile = "Assets/Atlas.json"; + + public static Dictionary LoadTiles() + { + if (!File.Exists(AtlasFile)) + throw new InvalidOperationException("Can't load Atlas.json because it doesn't exists"); + + string json = File.ReadAllText(AtlasFile); + + return JsonConvert.DeserializeObject>(json) ?? + throw new InvalidOperationException("Atlas.json is empty"); + } + + public static Dictionary ConvertTiles(Dictionary tiles) + { + byte i = 1; + Dictionary flatTiles = new Dictionary(); + + foreach (var kv in tiles) + { + flatTiles.Add(new AtlasTileKey(kv.Key, i), new Tile(kv.Value.AtlasOffset, kv.Value.Size)); + i++; + } + + return flatTiles; + } +} \ No newline at end of file diff --git a/Atlas/AtlasTile.cs b/Atlas/AtlasTile.cs new file mode 100644 index 0000000..8723c9e --- /dev/null +++ b/Atlas/AtlasTile.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace BuildingGame.Atlas; + +public struct AtlasTile +{ + public JsonVec2 AtlasOffset { get; set; } + public JsonVec2 Size { get; set; } + + [JsonConstructor] + AtlasTile(JsonVec2 AtlasOffset, JsonVec2? Size) + { + this.AtlasOffset = AtlasOffset; + this.Size = Size ?? new JsonVec2() { X = 1, Y = 1 }; + } +} \ No newline at end of file diff --git a/Atlas/AtlasTileKey.cs b/Atlas/AtlasTileKey.cs new file mode 100644 index 0000000..c945c8c --- /dev/null +++ b/Atlas/AtlasTileKey.cs @@ -0,0 +1,13 @@ +namespace BuildingGame.Atlas; + +public struct AtlasTileKey +{ + public string Name; + public byte Id; + + public AtlasTileKey(string name, byte id) + { + Name = name; + Id = id; + } +} \ No newline at end of file diff --git a/Atlas/JsonVec2.cs b/Atlas/JsonVec2.cs new file mode 100644 index 0000000..3c59c01 --- /dev/null +++ b/Atlas/JsonVec2.cs @@ -0,0 +1,11 @@ +using System.Numerics; + +namespace BuildingGame.Atlas; + +public struct JsonVec2 +{ + public float X { get; set; } + public float Y { get; set; } + + public static implicit operator Vector2(JsonVec2 vec) => new Vector2(vec.X, vec.Y); +} \ No newline at end of file diff --git a/BuildingGame.csproj b/BuildingGame.csproj index 72032a9..e1171dc 100644 --- a/BuildingGame.csproj +++ b/BuildingGame.csproj @@ -26,6 +26,7 @@ + diff --git a/Chunk.cs b/Chunk.cs index 0475821..102878e 100644 --- a/Chunk.cs +++ b/Chunk.cs @@ -8,7 +8,7 @@ public struct Chunk public World World; public readonly int X, Y; - private TileKind[][] _tiles; + private byte[][] _tiles; public Chunk(World world, int x, int y) { @@ -16,10 +16,10 @@ public Chunk(World world, int x, int y) X = x; Y = y; - _tiles = new TileKind[Size][]; + _tiles = new byte[Size][]; for (int i = 0; i < Size; i++) { - _tiles[i] = new TileKind[Size]; + _tiles[i] = new byte[Size]; } } @@ -29,8 +29,8 @@ public void Update() { for (int y = 0; y < Size; y++) { - TileKind tile = _tiles[x][y]; - if (tile == TileKind.Air) continue; + byte tile = _tiles[x][y]; + if (tile == 0) continue; Tiles.GetTile(tile).Update(World, X * Size + x, Y * Size + y); } } @@ -42,19 +42,19 @@ public void Draw() { for (int y = 0; y < Size; y++) { - TileKind tile = _tiles[x][y]; - if (tile == TileKind.Air) continue; + byte tile = _tiles[x][y]; + if (tile == 0) continue; Tiles.GetTile(tile).Draw(World, X * Size + x, Y * Size + y); } } } - public TileKind this[int x, int y] + public byte this[int x, int y] { get { if (x < 0 || x >= Size || y < 0 || y >= Size) - return TileKind.Air; + return 0; return _tiles[x][y]; } set diff --git a/Player.cs b/Player.cs index 80f594d..f09fe09 100644 --- a/Player.cs +++ b/Player.cs @@ -13,7 +13,7 @@ public class Player private Vector2 _targetPosition; private float _targetZoom; - private TileKind _currentTile = TileKind.Stone; + private byte _currentTile = 2; public Player(World world, Vector2 position, float speed, float lerpSpeed) { @@ -76,7 +76,7 @@ private void UpdateTileControls() if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_RIGHT)) { - World[tx, ty] = TileKind.Air; + World[tx, ty] = 0; } } diff --git a/Program.cs b/Program.cs index 7280158..26f3137 100644 --- a/Program.cs +++ b/Program.cs @@ -17,6 +17,9 @@ while (!WindowShouldClose()) { + if (IsKeyPressed(KeyboardKey.KEY_R)) + Tiles.Reload(); + player.Update(); world.Update(); diff --git a/Tile.cs b/Tile.cs index 574dcbc..6322b66 100644 --- a/Tile.cs +++ b/Tile.cs @@ -10,6 +10,7 @@ public class Tile public const float AtlasFraction = 0.25f; public readonly Vector2 TexCoord; + public readonly Vector2 Size = Vector2.One; public Tile() { @@ -21,6 +22,12 @@ public Tile(Vector2 texCoord) TexCoord = texCoord; } + public Tile(Vector2 texCoord, Vector2 size) + { + TexCoord = texCoord; + Size = size; + } + public Tile(float tx, float ty) { TexCoord = new Vector2(tx, ty); @@ -37,14 +44,14 @@ public virtual void Draw(World world, int x, int y) new Rectangle( TexCoord.X * TileSize + AtlasFraction, TexCoord.Y * TileSize + AtlasFraction, - TileSize - AtlasFraction, - TileSize - AtlasFraction + Size.X * TileSize - AtlasFraction, + Size.Y * TileSize - AtlasFraction ), new Rectangle( x * TileSize * TileUpscale, y * TileSize * TileUpscale, - TileSize * TileUpscale, - TileSize * TileUpscale + Size.X * TileSize * TileUpscale, + Size.Y * TileSize * TileUpscale ), Vector2.Zero, 0, WHITE ); diff --git a/TileKind.cs b/TileKind.cs deleted file mode 100644 index a32b5ef..0000000 --- a/TileKind.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace BuildingGame; - -public enum TileKind : byte -{ - Air, - SmoothStone, - Planks, - Dirt, - GrassBlock, - Grass, - Sand, - Water, - Lava, - Obsidian, - Door, - Stone, - WhitePlate, - GreenPlate, - RedPlate, - BluePlate, - Chamomile, - RedTulip, - ChamomilePot, - RedTulipPot, - WoodenStairs, - WoodenSlab, - StoneStairs, - StoneSlab, - WoodenPole, - WoodenPoleHandle, - StonePole, - StonePoleHandle, - Log, - LogTop, - Leaves, - Glass, - WhiteWool, - RedWool, - GreenWool, - BlueWool, - YellowWool, - BlackWool, - DarkGrayWool, - GrayWool, - Sponge, - InfectionBlock -} \ No newline at end of file diff --git a/Tiles.cs b/Tiles.cs index 11863cf..79bfc8a 100644 --- a/Tiles.cs +++ b/Tiles.cs @@ -1,56 +1,36 @@ +using BuildingGame.Atlas; + namespace BuildingGame; public static class Tiles { - // this wont be for long because i'll implement tile loading from atlas.json lmao - private static readonly Dictionary _tiles = new Dictionary() + private static Dictionary _Tiles = AtlasLoader.ConvertTiles(AtlasLoader.LoadTiles()); + + public static void Reload() + { + _Tiles = AtlasLoader.ConvertTiles(AtlasLoader.LoadTiles()); + } + + public static Tile GetTile(byte id) + { + if (id < 1) throw new ArgumentException("Id mustn't be an air (0)", nameof(id)); + return _Tiles.First(kv => kv.Key.Id == id).Value; + } + + public static Tile GetTile(string name) + { + return _Tiles.First(kv => string.Equals(kv.Key.Name, name, StringComparison.CurrentCultureIgnoreCase)).Value; + } + + public static void RegisterCustomTile(string name, T tile) where T : Tile { - { TileKind.SmoothStone, new Tile(0, 0) }, - { TileKind.Planks, new Tile(1, 0) }, - { TileKind.Dirt, new Tile(2, 0) }, - { TileKind.GrassBlock, new Tile(3, 0) }, - { TileKind.Grass, new Tile(4, 0) }, - { TileKind.Sand, new Tile(5, 0) }, - { TileKind.Water, new Tile(6, 0) }, - { TileKind.Lava, new Tile(7, 0) }, - { TileKind.Obsidian, new Tile(8, 0) }, - { TileKind.Door, new Tile(9, 0) }, // atm it will be built from 1 tile - { TileKind.Stone, new Tile(0, 1) }, - { TileKind.WhitePlate, new Tile(1, 1) }, - { TileKind.GreenPlate, new Tile(2, 1) }, - { TileKind.RedPlate, new Tile(3, 1) }, - { TileKind.BluePlate, new Tile(4, 1) }, - { TileKind.Chamomile, new Tile(5, 1) }, - { TileKind.RedTulip, new Tile(6, 1) }, - { TileKind.ChamomilePot, new Tile(7, 1) }, - { TileKind.RedTulipPot, new Tile(8, 1) }, - { TileKind.WoodenStairs, new Tile(0, 2) }, - { TileKind.WoodenSlab, new Tile(1, 2) }, - { TileKind.StoneStairs, new Tile(2, 2) }, - { TileKind.StoneSlab, new Tile(3, 2) }, - { TileKind.WoodenPole, new Tile(4, 2) }, - { TileKind.WoodenPoleHandle, new Tile(5, 2) }, - { TileKind.StonePole, new Tile(6, 2) }, - { TileKind.StonePoleHandle, new Tile(7, 2) }, - { TileKind.Log, new Tile(8, 2) }, - { TileKind.LogTop, new Tile(9, 2) }, - { TileKind.Leaves, new Tile(0, 3) }, - { TileKind.Glass, new Tile(1, 3) }, - { TileKind.WhiteWool, new Tile(2, 3) }, - { TileKind.RedWool, new Tile(3, 3) }, - { TileKind.GreenWool, new Tile(4, 3) }, - { TileKind.BlueWool, new Tile(5, 3) }, - { TileKind.YellowWool, new Tile(6, 3) }, - { TileKind.BlackWool, new Tile(7, 3) }, - { TileKind.DarkGrayWool, new Tile(8, 3) }, - { TileKind.GrayWool, new Tile(9, 3) }, - { TileKind.Sponge, new Tile(0, 4) }, - { TileKind.InfectionBlock, new Tile(1, 4) } - }; + var key = _Tiles.Keys.First(k => string.Equals(k.Name, name, StringComparison.CurrentCultureIgnoreCase)); + _Tiles[key] = tile; + } - public static Tile GetTile(TileKind kind) + public static void RegisterCustomTile(byte id, T tile) where T : Tile { - if (kind == TileKind.Air) throw new ArgumentException("TileKind could not be an Air", nameof(kind)); - return _tiles[kind]; + var key = _Tiles.Keys.First(k => k.Id == id); + _Tiles[key] = tile; } } \ No newline at end of file diff --git a/World.cs b/World.cs index b2ce9c5..98b271e 100644 --- a/World.cs +++ b/World.cs @@ -60,12 +60,12 @@ public ChunkPosition WorldToChunk(int x, int y) return new ChunkPosition(cx, cy); } - public TileKind this[int x, int y] + public byte this[int x, int y] { get { if (x < 0 || x >= Width || y < 0 || y >= Height) - return TileKind.Air; + return 0; ChunkPosition pos = WorldToChunk(x, y); pos.WorldToTile(x, y, out int tx, out int ty); From 90e61fbd3a5a642d8e8568764a2c931498531894 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Thu, 19 Oct 2023 20:32:22 +0300 Subject: [PATCH 010/107] implement world io (saving/loading) --- Chunk.cs | 18 +++++---- IO/BGWorld2IO.cs | 82 ++++++++++++++++++++++++++++++++++++++ IO/IWorldDeserializer.cs | 10 +++++ IO/IWorldSerializer.cs | 8 ++++ IO/LvlIO.cs | 38 ++++++++++++++++++ IO/WorldIO.cs | 85 ++++++++++++++++++++++++++++++++++++++++ Player.cs | 5 +++ Program.cs | 11 +++++- Tile.cs | 4 +- TileFlags.cs | 7 ++++ TileInfo.cs | 7 ++++ World.cs | 34 +++++++++++++++- 12 files changed, 298 insertions(+), 11 deletions(-) create mode 100644 IO/BGWorld2IO.cs create mode 100644 IO/IWorldDeserializer.cs create mode 100644 IO/IWorldSerializer.cs create mode 100644 IO/LvlIO.cs create mode 100644 IO/WorldIO.cs create mode 100644 TileFlags.cs create mode 100644 TileInfo.cs diff --git a/Chunk.cs b/Chunk.cs index 102878e..ac1460a 100644 --- a/Chunk.cs +++ b/Chunk.cs @@ -8,7 +8,7 @@ public struct Chunk public World World; public readonly int X, Y; - private byte[][] _tiles; + private TileInfo[][] _tiles; public Chunk(World world, int x, int y) { @@ -16,10 +16,14 @@ public Chunk(World world, int x, int y) X = x; Y = y; - _tiles = new byte[Size][]; + _tiles = new TileInfo[Size][]; for (int i = 0; i < Size; i++) { - _tiles[i] = new byte[Size]; + _tiles[i] = new TileInfo[Size]; + for (int j = 0; j < Size; j++) + { + _tiles[i][j] = 0; + } } } @@ -29,9 +33,9 @@ public void Update() { for (int y = 0; y < Size; y++) { - byte tile = _tiles[x][y]; + TileInfo tile = _tiles[x][y]; if (tile == 0) continue; - Tiles.GetTile(tile).Update(World, X * Size + x, Y * Size + y); + Tiles.GetTile(tile).Update(World, tile, X * Size + x, Y * Size + y); } } } @@ -44,12 +48,12 @@ public void Draw() { byte tile = _tiles[x][y]; if (tile == 0) continue; - Tiles.GetTile(tile).Draw(World, X * Size + x, Y * Size + y); + Tiles.GetTile(tile).Draw(World, tile, X * Size + x, Y * Size + y); } } } - public byte this[int x, int y] + public TileInfo this[int x, int y] { get { diff --git a/IO/BGWorld2IO.cs b/IO/BGWorld2IO.cs new file mode 100644 index 0000000..1836cbe --- /dev/null +++ b/IO/BGWorld2IO.cs @@ -0,0 +1,82 @@ +using System.Diagnostics.CodeAnalysis; +using System.Numerics; + +namespace BuildingGame.IO; + +/* Latest world format (BGWorld2) + * + * Reading order: + * 1. (float) Last Camera X + * 2. (float) Last Camera Y + * + * Per each tile in world file (256x256 tiles): + * 1. (byte) Tile Id + * 2. (float) Tile Flags: Rotation + * 3. (bool) Tile Flags: Flip + */ +public static class BGWorld2IO +{ + public const string Header = "BGWORLD2"; + + public class Serializer : IWorldSerializer + { + public string Header => BGWorld2IO.Header; + + public bool TrySerialize(BinaryWriter writer, World world, out string? log) + { + writer.Write(world.PlayerPosition.X); + writer.Write(world.PlayerPosition.Y); + + for (int x = 0; x < world.Width; x++) + { + for (int y = 0; y < world.Height; y++) + { + PushTile(writer, world[x, y]); + } + } + + log = null; + return true; + } + } + + public class Deserializer : IWorldDeserializer + { + public string Header => BGWorld2IO.Header; + + public bool TryDeserialize(BinaryReader reader, out World world, out string? log) + { + world = new World(); + world!.PlayerPosition = new Vector2(reader.ReadSingle(), reader.ReadSingle()); + + for (int x = 0; x < world.Width; x++) + { + for (int y = 0; y < world.Height; y++) + { + world[x, y] = PopTile(reader); + } + } + + log = null; + return true; + } + } + + public static void Register() + { + WorldIO.RegisterSerializer(new Serializer()); + WorldIO.RegisterDeserializer(new Deserializer()); + } + + private static void PushTile(BinaryWriter bw, TileInfo tile) + { + bw.Write(tile.Id); + bw.Write(tile.Flags.Rotation); + bw.Write(tile.Flags.Flip); + } + + private static TileInfo PopTile(BinaryReader br) + { + return new TileInfo(br.ReadByte(), new TileFlags(br.ReadSingle(), br.ReadBoolean())); + } +} \ No newline at end of file diff --git a/IO/IWorldDeserializer.cs b/IO/IWorldDeserializer.cs new file mode 100644 index 0000000..335d07d --- /dev/null +++ b/IO/IWorldDeserializer.cs @@ -0,0 +1,10 @@ +using System.Diagnostics.CodeAnalysis; + +namespace BuildingGame.IO; + +public interface IWorldDeserializer +{ + string Header { get; } + + bool TryDeserialize(BinaryReader reader, out World world, out string? log); +} \ No newline at end of file diff --git a/IO/IWorldSerializer.cs b/IO/IWorldSerializer.cs new file mode 100644 index 0000000..cb545a8 --- /dev/null +++ b/IO/IWorldSerializer.cs @@ -0,0 +1,8 @@ +namespace BuildingGame.IO; + +public interface IWorldSerializer +{ + string Header { get; } + + bool TrySerialize(BinaryWriter writer, World world, out string? log); +} \ No newline at end of file diff --git a/IO/LvlIO.cs b/IO/LvlIO.cs new file mode 100644 index 0000000..a5cd745 --- /dev/null +++ b/IO/LvlIO.cs @@ -0,0 +1,38 @@ +namespace BuildingGame.IO; + +/// +/// WARNING: There's no implemented conversion for LVL format +/// +public static class LvlIO +{ + public const string Header = "LVL"; + + public class Serializer : IWorldSerializer + { + public string Header => LvlIO.Header; + + public bool TrySerialize(BinaryWriter writer, World world, out string? log) + { + log = "PRE-ALPHA 0.1.0 LEVEL FORMAT IS CURRENTLY NOT SUPPORTED"; + return false; + } + } + + public class Deserializer : IWorldDeserializer + { + public string Header => LvlIO.Header; + + public bool TryDeserialize(BinaryReader reader, out World world, out string? log) + { + world = new World(); + log = "PRE-ALPHA 0.1.0 LEVEL FORMAT IS CURRENTLY NOT SUPPORTED"; + return false; + } + } + + public static void Register() + { + WorldIO.RegisterSerializer(new Serializer()); + WorldIO.RegisterDeserializer(new Deserializer()); + } +} \ No newline at end of file diff --git a/IO/WorldIO.cs b/IO/WorldIO.cs new file mode 100644 index 0000000..ce8c0f3 --- /dev/null +++ b/IO/WorldIO.cs @@ -0,0 +1,85 @@ +using System.Diagnostics.CodeAnalysis; +using System.IO.Compression; + +namespace BuildingGame.IO; + +public static class WorldIO +{ + private static List _deserializers = new List(); + private static List _serializers = new List(); + + public static void RegisterDeserializer(T deserializer) where T : IWorldDeserializer + { + if (_deserializers.Find(m => m.GetType() == typeof(T)) != null) + throw new InvalidOperationException($"Deserializer of type {typeof(T)} is already registered"); + _deserializers.Add(deserializer); + } + + public static void RegisterSerializer(T serializer) where T : IWorldSerializer + { + if (_serializers.Find(m => m.GetType() == typeof(T)) != null) + throw new InvalidOperationException($"Serializer of type {typeof(T)} is already registered"); + _serializers.Add(serializer); + } + + public static bool TryDeserializeWorld(string path, [NotNullWhen(true)] out World? world) + { + world = null; + if (!File.Exists(path)) return false; + + try + { + using var fileStream = File.OpenRead(path); + using var gzipStream = new GZipStream(fileStream, CompressionMode.Decompress); + using var reader = new BinaryReader(gzipStream); + + string header = reader.ReadString(); + IWorldDeserializer deserializer = + _deserializers.Find(d => string.Equals(d.Header, header, StringComparison.CurrentCultureIgnoreCase)) + ?? throw new IOException("Unknown or corrupted world header: " + header); + + if (deserializer.TryDeserialize(reader, out var outWorld, out var log)) + { + world = outWorld; + return true; + } + + // TODO: print log from deserializer + return false; + } + catch (Exception ex) + { + // TODO: implement exception logging + return false; + } + } + + public static bool TrySerializeWorld(string path, World world) where TSerializer : IWorldSerializer + { + try + { + using var fileStream = File.OpenWrite(path); + using var gzipStream = new GZipStream(fileStream, CompressionMode.Compress); + using var writer = new BinaryWriter(gzipStream); + + IWorldSerializer serializer = + _serializers.Find(d => d.GetType() == typeof(TSerializer)) + ?? throw new IOException("Unable to find serializer of type " + typeof(TSerializer)); + + writer.Write(serializer.Header); + + if (serializer.TrySerialize(writer, world, out var log)) + { + return true; + } + + // TODO: print log from serializer + return false; + } + catch (Exception ex) + { + // TODO: implement exception logging + return false; + } + } +} \ No newline at end of file diff --git a/Player.cs b/Player.cs index f09fe09..4a6a8a3 100644 --- a/Player.cs +++ b/Player.cs @@ -102,6 +102,11 @@ public void Move(float x, float y) _targetPosition += new Vector2(x, y) * Speed * GetFrameTime(); } + public void PushCameraPosition() + { + World.PlayerPosition = Camera.target; + } + public Rectangle GetViewRectangle() { Vector2 min = GetScreenToWorld2D(new Vector2(0, 0), Camera); diff --git a/Program.cs b/Program.cs index 26f3137..3d7bf88 100644 --- a/Program.cs +++ b/Program.cs @@ -2,6 +2,7 @@ global using ZeroElectric.Vinculum; using System.Numerics; using BuildingGame; +using BuildingGame.IO; SetConfigFlags(ConfigFlags.FLAG_VSYNC_HINT); SetConfigFlags(ConfigFlags.FLAG_WINDOW_RESIZABLE); @@ -12,8 +13,13 @@ SetWindowIcon(icon); UnloadImage(icon); +BGWorld2IO.Register(); +LvlIO.Register(); + World world = new World(256, 256); -Player player = new Player(world, new Vector2(0), 50, 0.1f); +world.Load(); + +Player player = new Player(world, world.PlayerPosition, 50, 0.1f); while (!WindowShouldClose()) { @@ -35,5 +41,8 @@ EndDrawing(); } +player.PushCameraPosition(); +world.Save(); + Resources.Free(); CloseWindow(); \ No newline at end of file diff --git a/Tile.cs b/Tile.cs index 6322b66..25d337d 100644 --- a/Tile.cs +++ b/Tile.cs @@ -33,11 +33,11 @@ public Tile(float tx, float ty) TexCoord = new Vector2(tx, ty); } - public virtual void Update(World world, int x, int y) + public virtual void Update(World world, TileInfo info, int x, int y) { } - public virtual void Draw(World world, int x, int y) + public virtual void Draw(World world, TileInfo info, int x, int y) { DrawTexturePro(Resources.GetTexture("Atlas.png"), // we add a fraction to the source rectangle, so we wont see flickering parts of atlas diff --git a/TileFlags.cs b/TileFlags.cs new file mode 100644 index 0000000..93f16c8 --- /dev/null +++ b/TileFlags.cs @@ -0,0 +1,7 @@ +namespace BuildingGame; + +// TODO: implement rotation enum instead of storing 32-bit floating point, because there are only 0, 90, 180, 270 degrees rotations available in-game +public record TileFlags(float Rotation, bool Flip) +{ + public static TileFlags Default => new TileFlags(0, false); +} \ No newline at end of file diff --git a/TileInfo.cs b/TileInfo.cs new file mode 100644 index 0000000..d20cff7 --- /dev/null +++ b/TileInfo.cs @@ -0,0 +1,7 @@ +namespace BuildingGame; + +public record TileInfo(byte Id, TileFlags Flags) +{ + public static implicit operator TileInfo(byte id) => new TileInfo(id, TileFlags.Default); + public static implicit operator byte(TileInfo info) => info.Id; +} \ No newline at end of file diff --git a/World.cs b/World.cs index 98b271e..4bc80a4 100644 --- a/World.cs +++ b/World.cs @@ -1,14 +1,27 @@ +using System.Numerics; +using BuildingGame.IO; + namespace BuildingGame; public struct World { + public const int DefaultSize = 256; + public readonly int Width; public readonly int Height; public readonly int ChunkWidth; public readonly int ChunkHeight; + public Vector2 PlayerPosition; + private Chunk[][] _chunks; + public World() + : this(DefaultSize, DefaultSize) + { + + } + public World(int width, int height) { Width = width; @@ -60,7 +73,26 @@ public ChunkPosition WorldToChunk(int x, int y) return new ChunkPosition(cx, cy); } - public byte this[int x, int y] + public void Load() + { + if (!WorldIO.TryDeserializeWorld("level.dat", out var world)) return; + if (Width != world.Value.Width || Height != world.Value.Height) return; + + for (int x = 0; x < Width; x++) + { + for (int y = 0; y < Height; y++) + { + this[x, y] = world.Value[x, y]; + } + } + } + + public void Save() + { + WorldIO.TrySerializeWorld("level.dat", this); + } + + public TileInfo this[int x, int y] { get { From c768f4f0c40a8356b4ba8a9bb29c90f43ae7a4b0 Mon Sep 17 00:00:00 2001 From: Danil <61111955+danilwhale@users.noreply.github.com> Date: Thu, 19 Oct 2023 20:34:31 +0300 Subject: [PATCH 011/107] grammar --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4849ea1..70cee3c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # BuildingGame game where you can just place tiles -> Warning: this is temporairy branch and maybe will become main after 21 years +> Warning: this is temporairy branch and may become main after 21 years From 37d75e8c0fa9bcd11e46e5655267e7f73d0a1153 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Thu, 19 Oct 2023 20:49:37 +0300 Subject: [PATCH 012/107] renames, structuring --- Player.cs | 1 + Program.cs | 7 ++++--- {Atlas => Tiles/Atlas}/AtlasLoader.cs | 2 +- {Atlas => Tiles/Atlas}/AtlasTile.cs | 2 +- {Atlas => Tiles/Atlas}/AtlasTileKey.cs | 2 +- {Atlas => Tiles/Atlas}/JsonVec2.cs | 2 +- Chunk.cs => Tiles/Chunk.cs | 4 +++- ChunkPosition.cs => Tiles/Data/ChunkPosition.cs | 2 +- TileFlags.cs => Tiles/Data/TileFlags.cs | 2 +- TileInfo.cs => Tiles/Data/TileInfo.cs | 2 +- IO/BGWorld2IO.cs => Tiles/IO/BGWorld2Format.cs | 10 +++++----- {IO => Tiles/IO}/IWorldDeserializer.cs | 4 +--- {IO => Tiles/IO}/IWorldSerializer.cs | 2 +- IO/LvlIO.cs => Tiles/IO/LvlFormat.cs | 8 ++++---- {IO => Tiles/IO}/WorldIO.cs | 2 +- Tile.cs => Tiles/Tile.cs | 3 ++- Tiles.cs => Tiles/Tiles.cs | 4 ++-- World.cs => Tiles/World.cs | 7 ++++--- 18 files changed, 35 insertions(+), 31 deletions(-) rename {Atlas => Tiles/Atlas}/AtlasLoader.cs (96%) rename {Atlas => Tiles/Atlas}/AtlasTile.cs (90%) rename {Atlas => Tiles/Atlas}/AtlasTileKey.cs (82%) rename {Atlas => Tiles/Atlas}/JsonVec2.cs (85%) rename Chunk.cs => Tiles/Chunk.cs (96%) rename ChunkPosition.cs => Tiles/Data/ChunkPosition.cs (93%) rename TileFlags.cs => Tiles/Data/TileFlags.cs (88%) rename TileInfo.cs => Tiles/Data/TileInfo.cs (86%) rename IO/BGWorld2IO.cs => Tiles/IO/BGWorld2Format.cs (90%) rename {IO => Tiles/IO}/IWorldDeserializer.cs (69%) rename {IO => Tiles/IO}/IWorldSerializer.cs (81%) rename IO/LvlIO.cs => Tiles/IO/LvlFormat.cs (84%) rename {IO => Tiles/IO}/WorldIO.cs (98%) rename Tile.cs => Tiles/Tile.cs (97%) rename Tiles.cs => Tiles/Tiles.cs (94%) rename World.cs => Tiles/World.cs (94%) diff --git a/Player.cs b/Player.cs index 4a6a8a3..b4a7959 100644 --- a/Player.cs +++ b/Player.cs @@ -1,4 +1,5 @@ using System.Numerics; +using BuildingGame.Tiles; using ZeroElectric.Vinculum; namespace BuildingGame; diff --git a/Program.cs b/Program.cs index 3d7bf88..f99f126 100644 --- a/Program.cs +++ b/Program.cs @@ -2,7 +2,8 @@ global using ZeroElectric.Vinculum; using System.Numerics; using BuildingGame; -using BuildingGame.IO; +using BuildingGame.Tiles; +using BuildingGame.Tiles.IO; SetConfigFlags(ConfigFlags.FLAG_VSYNC_HINT); SetConfigFlags(ConfigFlags.FLAG_WINDOW_RESIZABLE); @@ -13,8 +14,8 @@ SetWindowIcon(icon); UnloadImage(icon); -BGWorld2IO.Register(); -LvlIO.Register(); +BGWorld2Format.Register(); +LvlFormat.Register(); World world = new World(256, 256); world.Load(); diff --git a/Atlas/AtlasLoader.cs b/Tiles/Atlas/AtlasLoader.cs similarity index 96% rename from Atlas/AtlasLoader.cs rename to Tiles/Atlas/AtlasLoader.cs index 44d1797..5124f0d 100644 --- a/Atlas/AtlasLoader.cs +++ b/Tiles/Atlas/AtlasLoader.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace BuildingGame.Atlas; +namespace BuildingGame.Tiles.Atlas; public static class AtlasLoader { diff --git a/Atlas/AtlasTile.cs b/Tiles/Atlas/AtlasTile.cs similarity index 90% rename from Atlas/AtlasTile.cs rename to Tiles/Atlas/AtlasTile.cs index 8723c9e..309178e 100644 --- a/Atlas/AtlasTile.cs +++ b/Tiles/Atlas/AtlasTile.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace BuildingGame.Atlas; +namespace BuildingGame.Tiles.Atlas; public struct AtlasTile { diff --git a/Atlas/AtlasTileKey.cs b/Tiles/Atlas/AtlasTileKey.cs similarity index 82% rename from Atlas/AtlasTileKey.cs rename to Tiles/Atlas/AtlasTileKey.cs index c945c8c..63f88a2 100644 --- a/Atlas/AtlasTileKey.cs +++ b/Tiles/Atlas/AtlasTileKey.cs @@ -1,4 +1,4 @@ -namespace BuildingGame.Atlas; +namespace BuildingGame.Tiles.Atlas; public struct AtlasTileKey { diff --git a/Atlas/JsonVec2.cs b/Tiles/Atlas/JsonVec2.cs similarity index 85% rename from Atlas/JsonVec2.cs rename to Tiles/Atlas/JsonVec2.cs index 3c59c01..9a8e313 100644 --- a/Atlas/JsonVec2.cs +++ b/Tiles/Atlas/JsonVec2.cs @@ -1,6 +1,6 @@ using System.Numerics; -namespace BuildingGame.Atlas; +namespace BuildingGame.Tiles.Atlas; public struct JsonVec2 { diff --git a/Chunk.cs b/Tiles/Chunk.cs similarity index 96% rename from Chunk.cs rename to Tiles/Chunk.cs index ac1460a..7fdacc1 100644 --- a/Chunk.cs +++ b/Tiles/Chunk.cs @@ -1,4 +1,6 @@ -namespace BuildingGame; +using BuildingGame.Tiles.Data; + +namespace BuildingGame.Tiles; public struct Chunk { diff --git a/ChunkPosition.cs b/Tiles/Data/ChunkPosition.cs similarity index 93% rename from ChunkPosition.cs rename to Tiles/Data/ChunkPosition.cs index 056923a..6d24ba4 100644 --- a/ChunkPosition.cs +++ b/Tiles/Data/ChunkPosition.cs @@ -1,4 +1,4 @@ -namespace BuildingGame; +namespace BuildingGame.Tiles.Data; public record ChunkPosition(int X, int Y) { diff --git a/TileFlags.cs b/Tiles/Data/TileFlags.cs similarity index 88% rename from TileFlags.cs rename to Tiles/Data/TileFlags.cs index 93f16c8..d406f17 100644 --- a/TileFlags.cs +++ b/Tiles/Data/TileFlags.cs @@ -1,4 +1,4 @@ -namespace BuildingGame; +namespace BuildingGame.Tiles.Data; // TODO: implement rotation enum instead of storing 32-bit floating point, because there are only 0, 90, 180, 270 degrees rotations available in-game public record TileFlags(float Rotation, bool Flip) diff --git a/TileInfo.cs b/Tiles/Data/TileInfo.cs similarity index 86% rename from TileInfo.cs rename to Tiles/Data/TileInfo.cs index d20cff7..cafd7b6 100644 --- a/TileInfo.cs +++ b/Tiles/Data/TileInfo.cs @@ -1,4 +1,4 @@ -namespace BuildingGame; +namespace BuildingGame.Tiles.Data; public record TileInfo(byte Id, TileFlags Flags) { diff --git a/IO/BGWorld2IO.cs b/Tiles/IO/BGWorld2Format.cs similarity index 90% rename from IO/BGWorld2IO.cs rename to Tiles/IO/BGWorld2Format.cs index 1836cbe..dc919e8 100644 --- a/IO/BGWorld2IO.cs +++ b/Tiles/IO/BGWorld2Format.cs @@ -1,7 +1,7 @@ -using System.Diagnostics.CodeAnalysis; using System.Numerics; +using BuildingGame.Tiles.Data; -namespace BuildingGame.IO; +namespace BuildingGame.Tiles.IO; /* Latest world format (BGWorld2) * @@ -14,13 +14,13 @@ namespace BuildingGame.IO; * 2. (float) Tile Flags: Rotation * 3. (bool) Tile Flags: Flip */ -public static class BGWorld2IO +public static class BGWorld2Format { public const string Header = "BGWORLD2"; public class Serializer : IWorldSerializer { - public string Header => BGWorld2IO.Header; + public string Header => BGWorld2Format.Header; public bool TrySerialize(BinaryWriter writer, World world, out string? log) { @@ -42,7 +42,7 @@ public bool TrySerialize(BinaryWriter writer, World world, out string? log) public class Deserializer : IWorldDeserializer { - public string Header => BGWorld2IO.Header; + public string Header => BGWorld2Format.Header; public bool TryDeserialize(BinaryReader reader, out World world, out string? log) { diff --git a/IO/IWorldDeserializer.cs b/Tiles/IO/IWorldDeserializer.cs similarity index 69% rename from IO/IWorldDeserializer.cs rename to Tiles/IO/IWorldDeserializer.cs index 335d07d..19ebb43 100644 --- a/IO/IWorldDeserializer.cs +++ b/Tiles/IO/IWorldDeserializer.cs @@ -1,6 +1,4 @@ -using System.Diagnostics.CodeAnalysis; - -namespace BuildingGame.IO; +namespace BuildingGame.Tiles.IO; public interface IWorldDeserializer { diff --git a/IO/IWorldSerializer.cs b/Tiles/IO/IWorldSerializer.cs similarity index 81% rename from IO/IWorldSerializer.cs rename to Tiles/IO/IWorldSerializer.cs index cb545a8..7788423 100644 --- a/IO/IWorldSerializer.cs +++ b/Tiles/IO/IWorldSerializer.cs @@ -1,4 +1,4 @@ -namespace BuildingGame.IO; +namespace BuildingGame.Tiles.IO; public interface IWorldSerializer { diff --git a/IO/LvlIO.cs b/Tiles/IO/LvlFormat.cs similarity index 84% rename from IO/LvlIO.cs rename to Tiles/IO/LvlFormat.cs index a5cd745..5d124bd 100644 --- a/IO/LvlIO.cs +++ b/Tiles/IO/LvlFormat.cs @@ -1,15 +1,15 @@ -namespace BuildingGame.IO; +namespace BuildingGame.Tiles.IO; /// /// WARNING: There's no implemented conversion for LVL format /// -public static class LvlIO +public static class LvlFormat { public const string Header = "LVL"; public class Serializer : IWorldSerializer { - public string Header => LvlIO.Header; + public string Header => LvlFormat.Header; public bool TrySerialize(BinaryWriter writer, World world, out string? log) { @@ -20,7 +20,7 @@ public bool TrySerialize(BinaryWriter writer, World world, out string? log) public class Deserializer : IWorldDeserializer { - public string Header => LvlIO.Header; + public string Header => LvlFormat.Header; public bool TryDeserialize(BinaryReader reader, out World world, out string? log) { diff --git a/IO/WorldIO.cs b/Tiles/IO/WorldIO.cs similarity index 98% rename from IO/WorldIO.cs rename to Tiles/IO/WorldIO.cs index ce8c0f3..f1a997d 100644 --- a/IO/WorldIO.cs +++ b/Tiles/IO/WorldIO.cs @@ -1,7 +1,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO.Compression; -namespace BuildingGame.IO; +namespace BuildingGame.Tiles.IO; public static class WorldIO { diff --git a/Tile.cs b/Tiles/Tile.cs similarity index 97% rename from Tile.cs rename to Tiles/Tile.cs index 25d337d..3b70bea 100644 --- a/Tile.cs +++ b/Tiles/Tile.cs @@ -1,6 +1,7 @@ using System.Numerics; +using BuildingGame.Tiles.Data; -namespace BuildingGame; +namespace BuildingGame.Tiles; public class Tile { diff --git a/Tiles.cs b/Tiles/Tiles.cs similarity index 94% rename from Tiles.cs rename to Tiles/Tiles.cs index 79bfc8a..10e6e5d 100644 --- a/Tiles.cs +++ b/Tiles/Tiles.cs @@ -1,6 +1,6 @@ -using BuildingGame.Atlas; +using BuildingGame.Tiles.Atlas; -namespace BuildingGame; +namespace BuildingGame.Tiles; public static class Tiles { diff --git a/World.cs b/Tiles/World.cs similarity index 94% rename from World.cs rename to Tiles/World.cs index 4bc80a4..323816b 100644 --- a/World.cs +++ b/Tiles/World.cs @@ -1,7 +1,8 @@ using System.Numerics; -using BuildingGame.IO; +using BuildingGame.Tiles.Data; +using BuildingGame.Tiles.IO; -namespace BuildingGame; +namespace BuildingGame.Tiles; public struct World { @@ -89,7 +90,7 @@ public void Load() public void Save() { - WorldIO.TrySerializeWorld("level.dat", this); + WorldIO.TrySerializeWorld("level.dat", this); } public TileInfo this[int x, int y] From 8d8d829a84d120143109494b3ab1dabca02791dd Mon Sep 17 00:00:00 2001 From: danilwhale Date: Sat, 21 Oct 2023 14:19:13 +0300 Subject: [PATCH 013/107] reimplement gui --- Player.cs | 15 ++-- Program.cs | 6 ++ UI/Alignment.cs | 14 ++++ UI/Brushes/GradientBrush.cs | 33 +++++++++ UI/Brushes/GradientDirection.cs | 7 ++ UI/Brushes/IBrush.cs | 6 ++ UI/Brushes/LineBrush.cs | 17 +++++ UI/Brushes/OutlineBrush.cs | 20 ++++++ UI/Brushes/SolidBrush.cs | 17 +++++ UI/Brushes/TextureBrush.cs | 21 ++++++ UI/Element.cs | 120 ++++++++++++++++++++++++++++++++ UI/Elements/Button.cs | 29 ++++++++ UI/Elements/CheckBox.cs | 47 +++++++++++++ UI/Elements/ListBox.cs | 80 +++++++++++++++++++++ UI/Elements/Panel.cs | 17 +++++ UI/Elements/TextBox.cs | 45 ++++++++++++ UI/Elements/TextElement.cs | 50 +++++++++++++ UI/Elements/Tooltip.cs | 30 ++++++++ UI/GuiManager.cs | 88 +++++++++++++++++++++++ 19 files changed, 655 insertions(+), 7 deletions(-) create mode 100644 UI/Alignment.cs create mode 100644 UI/Brushes/GradientBrush.cs create mode 100644 UI/Brushes/GradientDirection.cs create mode 100644 UI/Brushes/IBrush.cs create mode 100644 UI/Brushes/LineBrush.cs create mode 100644 UI/Brushes/OutlineBrush.cs create mode 100644 UI/Brushes/SolidBrush.cs create mode 100644 UI/Brushes/TextureBrush.cs create mode 100644 UI/Element.cs create mode 100644 UI/Elements/Button.cs create mode 100644 UI/Elements/CheckBox.cs create mode 100644 UI/Elements/ListBox.cs create mode 100644 UI/Elements/Panel.cs create mode 100644 UI/Elements/TextBox.cs create mode 100644 UI/Elements/TextElement.cs create mode 100644 UI/Elements/Tooltip.cs create mode 100644 UI/GuiManager.cs diff --git a/Player.cs b/Player.cs index b4a7959..2a12560 100644 --- a/Player.cs +++ b/Player.cs @@ -1,5 +1,6 @@ using System.Numerics; using BuildingGame.Tiles; +using BuildingGame.UI; using ZeroElectric.Vinculum; namespace BuildingGame; @@ -37,7 +38,7 @@ public void Update() Camera.zoom = (Camera.zoom * (1.0f - LerpSpeed)) + (_targetZoom * LerpSpeed); // lerp camera zoom to target zoom // zoom in/zoom out camera - float scrollDelta = GetMouseWheelMove(); + float scrollDelta = GetMouseWheelMove() * (GuiManager.IsMouseOverElement() ? 0 : 1); if (scrollDelta < 0) ZoomOut(Speed * 0.075f); if (scrollDelta > 0) ZoomIn(Speed * 0.075f); @@ -49,10 +50,10 @@ public void Update() speed = Math.Clamp(speed, 0, Speed * 2); // move camera - if (IsKeyDown(KeyboardKey.KEY_W)) Move(0, -speed); - if (IsKeyDown(KeyboardKey.KEY_S)) Move(0, speed); - if (IsKeyDown(KeyboardKey.KEY_A)) Move(-speed, 0); - if (IsKeyDown(KeyboardKey.KEY_D)) Move(speed, 0); + if (IsKeyDown(KeyboardKey.KEY_W) && !GuiManager.IsFocused) Move(0, -speed); + if (IsKeyDown(KeyboardKey.KEY_S) && !GuiManager.IsFocused) Move(0, speed); + if (IsKeyDown(KeyboardKey.KEY_A) && !GuiManager.IsFocused) Move(-speed, 0); + if (IsKeyDown(KeyboardKey.KEY_D) && !GuiManager.IsFocused) Move(speed, 0); // adapt camera center when windows is resized if (IsWindowResized()) @@ -70,12 +71,12 @@ private void UpdateTileControls() int tx = (int)(worldMousePos.X / Tile.RealTileSize); int ty = (int)(worldMousePos.Y / Tile.RealTileSize); - if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_LEFT)) + if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_LEFT) && !GuiManager.IsMouseOverElement()) { World[tx, ty] = _currentTile; } - if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_RIGHT)) + if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_RIGHT) && !GuiManager.IsMouseOverElement()) { World[tx, ty] = 0; } diff --git a/Program.cs b/Program.cs index f99f126..a6a9eeb 100644 --- a/Program.cs +++ b/Program.cs @@ -4,6 +4,9 @@ using BuildingGame; using BuildingGame.Tiles; using BuildingGame.Tiles.IO; +using BuildingGame.UI; +using BuildingGame.UI.Brushes; +using BuildingGame.UI.Elements; SetConfigFlags(ConfigFlags.FLAG_VSYNC_HINT); SetConfigFlags(ConfigFlags.FLAG_WINDOW_RESIZABLE); @@ -29,6 +32,7 @@ player.Update(); world.Update(); + GuiManager.Update(); BeginDrawing(); ClearBackground(SKYBLUE); @@ -39,6 +43,8 @@ } EndMode2D(); + GuiManager.Draw(); + EndDrawing(); } diff --git a/UI/Alignment.cs b/UI/Alignment.cs new file mode 100644 index 0000000..057d094 --- /dev/null +++ b/UI/Alignment.cs @@ -0,0 +1,14 @@ +namespace BuildingGame.UI; + +public enum Alignment +{ + TopLeft, + TopRight, + TopCenter, + CenterLeft, + CenterRight, + Center, + BottomLeft, + BottomRight, + BottomCenter +} \ No newline at end of file diff --git a/UI/Brushes/GradientBrush.cs b/UI/Brushes/GradientBrush.cs new file mode 100644 index 0000000..1076ebc --- /dev/null +++ b/UI/Brushes/GradientBrush.cs @@ -0,0 +1,33 @@ +namespace BuildingGame.UI.Brushes; + +public class GradientBrush : IBrush +{ + public Color ColorA; + public Color ColorB; + public GradientDirection Direction; + + public GradientBrush(Color colorA, Color colorB, GradientDirection direction = GradientDirection.Vertical) + { + ColorA = colorA; + ColorB = colorB; + Direction = direction; + } + + public void FillArea(Rectangle area) + { + int x = (int)area.x; + int y = (int)area.y; + int width = (int)area.width; + int height = (int)area.height; + + switch (Direction) + { + case GradientDirection.Vertical: + DrawRectangleGradientV(x, y, width, height, ColorA, ColorB); + break; + case GradientDirection.Horizontal: + DrawRectangleGradientH(x, y, width, height, ColorA, ColorB); + break; + } + } +} \ No newline at end of file diff --git a/UI/Brushes/GradientDirection.cs b/UI/Brushes/GradientDirection.cs new file mode 100644 index 0000000..2a1a876 --- /dev/null +++ b/UI/Brushes/GradientDirection.cs @@ -0,0 +1,7 @@ +namespace BuildingGame.UI.Brushes; + +public enum GradientDirection +{ + Vertical, + Horizontal +} \ No newline at end of file diff --git a/UI/Brushes/IBrush.cs b/UI/Brushes/IBrush.cs new file mode 100644 index 0000000..04b24ef --- /dev/null +++ b/UI/Brushes/IBrush.cs @@ -0,0 +1,6 @@ +namespace BuildingGame.UI.Brushes; + +public interface IBrush +{ + void FillArea(Rectangle area); +} \ No newline at end of file diff --git a/UI/Brushes/LineBrush.cs b/UI/Brushes/LineBrush.cs new file mode 100644 index 0000000..133b36f --- /dev/null +++ b/UI/Brushes/LineBrush.cs @@ -0,0 +1,17 @@ +namespace BuildingGame.UI.Brushes; + +public class LineBrush : IBrush +{ + public Color Color; + public float LineThick = 1; + + public LineBrush(Color color) + { + Color = color; + } + + public void FillArea(Rectangle area) + { + DrawRectangleLinesEx(area, LineThick, Color); + } +} \ No newline at end of file diff --git a/UI/Brushes/OutlineBrush.cs b/UI/Brushes/OutlineBrush.cs new file mode 100644 index 0000000..cdfc51c --- /dev/null +++ b/UI/Brushes/OutlineBrush.cs @@ -0,0 +1,20 @@ +namespace BuildingGame.UI.Brushes; + +public class OutlineBrush : IBrush +{ + public Color LineColor; + public Color FillColor; + public float LineThick = 1; + + public OutlineBrush(Color lineColor, Color fillColor) + { + LineColor = lineColor; + FillColor = fillColor; + } + + public void FillArea(Rectangle area) + { + DrawRectangleRec(area, FillColor); + DrawRectangleLinesEx(area, LineThick, LineColor); + } +} \ No newline at end of file diff --git a/UI/Brushes/SolidBrush.cs b/UI/Brushes/SolidBrush.cs new file mode 100644 index 0000000..a8632f3 --- /dev/null +++ b/UI/Brushes/SolidBrush.cs @@ -0,0 +1,17 @@ +namespace BuildingGame.UI.Brushes; + +public class SolidBrush : IBrush +{ + public Color Color; + + public SolidBrush(Color color) + { + Color = color; + } + + public void FillArea(Rectangle area) + { + RlGl.rlSetBlendMode(0); + DrawRectangleRec(area, Color); + } +} \ No newline at end of file diff --git a/UI/Brushes/TextureBrush.cs b/UI/Brushes/TextureBrush.cs new file mode 100644 index 0000000..36b3992 --- /dev/null +++ b/UI/Brushes/TextureBrush.cs @@ -0,0 +1,21 @@ +using System.Numerics; + +namespace BuildingGame.UI.Brushes; + +public class TextureBrush : IBrush +{ + public Texture Texture; + public Color Tint = WHITE; + public Rectangle CropArea; + + public TextureBrush(Texture texture) + { + Texture = texture; + CropArea = new Rectangle(0, 0, texture.width, texture.height); + } + + public void FillArea(Rectangle area) + { + DrawTexturePro(Texture, CropArea, area, Vector2.Zero, 0, Tint); + } +} \ No newline at end of file diff --git a/UI/Element.cs b/UI/Element.cs new file mode 100644 index 0000000..a12d806 --- /dev/null +++ b/UI/Element.cs @@ -0,0 +1,120 @@ +using System.Numerics; + +namespace BuildingGame.UI; + +public class Element : IDisposable +{ + private Rectangle _Area; + + public Rectangle Area + { + get => _Area; + set + { + _Area = value; + + UnloadRenderTexture(_controlTexture); + _controlTexture = LoadRenderTexture((int)value.width, (int)value.height); + } + } + + public Vector2 Position + { + get => new Vector2(_Area.x, _Area.y); + set => _Area = new Rectangle(value.X, value.Y, _Area.width, _Area.height); + } + + public Vector2 Size + { + get => new Vector2(_Area.width, _Area.height); + set => Area = new Rectangle(_Area.x, _Area.y, value.X, value.Y); + } + + public string Name; + public byte ZIndex; + + public bool Active = true; + public bool Visible = true; + + public Alignment Origin = Alignment.TopLeft; + public float Rotation = 0; + public string TooltipText = string.Empty; + + private RenderTexture _controlTexture; + + public Element(string name) + { + Name = name; + Area = new Rectangle(0, 0, 128, 128); + GuiManager.Add(this); + } + + public virtual void Update() + { + } + + public void Draw() + { + BeginTextureMode(_controlTexture); + + RlGl.rlPushMatrix(); + RlGl.rlTranslatef(-Area.x, -Area.y, 0); + + ClearBackground(BLANK); + Render(); + + RlGl.rlPopMatrix(); + + EndTextureMode(); + + Vector2 offset = Origin switch + { + Alignment.TopLeft => new Vector2(0, 0), + Alignment.TopRight => new Vector2(_Area.width, 0), + Alignment.TopCenter => new Vector2(_Area.width / 2, 0), + Alignment.CenterLeft => new Vector2(0, _Area.height / 2), + Alignment.CenterRight => new Vector2(_Area.width, _Area.height / 2), + Alignment.Center => new Vector2(_Area.width / 2, _Area.height / 2), + Alignment.BottomLeft => new Vector2(0, _Area.height), + Alignment.BottomRight => new Vector2(_Area.width, _Area.height), + Alignment.BottomCenter => new Vector2(_Area.width / 2, _Area.height), + _ => new Vector2(0, 0) + }; + + DrawTexturePro( + _controlTexture.texture, + new Rectangle( + 0, 0, + _Area.width, -_Area.height // we need to negate render texture height because opengl uses bottom-left instead of top-left + ), + _Area, offset, Rotation, + WHITE + ); + } + + protected virtual void Render() + { + ClearBackground(BLACK); + DrawText(":(", 0, 0, 16, WHITE); + } + + public bool IsHovered() + { + return CheckCollisionPointRec(GetMousePosition(), Area); + } + + public bool IsClicked() + { + return IsHovered() && IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT); + } + + public bool IsPressed() + { + return IsHovered() && IsMouseButtonDown(MouseButton.MOUSE_BUTTON_LEFT); + } + + public void Dispose() + { + UnloadRenderTexture(_controlTexture); + } +} \ No newline at end of file diff --git a/UI/Elements/Button.cs b/UI/Elements/Button.cs new file mode 100644 index 0000000..8028297 --- /dev/null +++ b/UI/Elements/Button.cs @@ -0,0 +1,29 @@ +namespace BuildingGame.UI.Elements; + +public class Button : TextElement +{ + public const string HoverText = "> "; + + public event Action? OnClick; + + public Button(string name) : base(name) + { + } + + public override void Update() + { + if (IsClicked()) + { + OnClick?.Invoke(); + } + + if (IsHovered() && !Text.StartsWith(HoverText)) + { + Text = HoverText + Text; + } + else if (!IsHovered() && Text.StartsWith(HoverText)) + { + Text = Text.Replace(HoverText, null); + } + } +} \ No newline at end of file diff --git a/UI/Elements/CheckBox.cs b/UI/Elements/CheckBox.cs new file mode 100644 index 0000000..9e6d9a2 --- /dev/null +++ b/UI/Elements/CheckBox.cs @@ -0,0 +1,47 @@ +using System.Numerics; +using BuildingGame.UI.Brushes; + +namespace BuildingGame.UI.Elements; + +public class CheckBox : Element +{ + public bool Checked; + + public IBrush? CheckBoxBrush = new OutlineBrush(GRAY, LIGHTGRAY); + public float BoxScale = 1f; + + public string Text = string.Empty; + public float TextSize = 12; + public Color TextColor = WHITE; + + + public CheckBox(string name) : base(name) + { + } + + public override void Update() + { + if (IsClicked()) Checked = !Checked; + } + + protected override void Render() + { + Rectangle boxArea = new Rectangle( + Area.x, + Area.y + Area.height / 2 - 18 * BoxScale / 2, + 18 * BoxScale, + 18 * BoxScale + ); + CheckBoxBrush?.FillArea(boxArea); + if (Checked) + { + DrawTexturePro( + Resources.GetTexture("Checkmark.png"), + new Rectangle(0, 0, 18, 18), + boxArea, + Vector2.Zero, 0, WHITE); + } + + DrawText(Text, Area.x + 8 + 18 * BoxScale, Area.y + Area.height / 2 - TextSize / 2f, TextSize, TextColor); + } +} \ No newline at end of file diff --git a/UI/Elements/ListBox.cs b/UI/Elements/ListBox.cs new file mode 100644 index 0000000..378a74a --- /dev/null +++ b/UI/Elements/ListBox.cs @@ -0,0 +1,80 @@ +using BuildingGame.UI.Brushes; + +namespace BuildingGame.UI.Elements; + +public class ListBox : Element +{ + public const float ScrollSpeed = 1000; + + public List Items = new List(); + public event Action? OnItemSelect; + + public IBrush? BackgroundBrush = new SolidBrush(WHITE); + public IBrush? HighlightBrush = new SolidBrush(new Color(212, 245, 255, 255)); + public IBrush? SelectionBrush = new SolidBrush(new Color(122, 214, 255, 255)); + + public float ItemTextSize = 12; + public float ItemPadding = 4; + public Color ItemColor = WHITE; + + private float _scroll = 0; + private int _highlightIndex = -1; + private int _selectedIndex = -1; + + public ListBox(string name) : base(name) + { + } + + public override void Update() + { + if (IsHovered()) + { + // finding index for highlight + float localMouseY = GetMousePosition().Y - Position.Y; + int index = (int)((localMouseY - _scroll) / ItemTextSize); + _highlightIndex = index; + + // list scrolling + float boxHeight = Items.Count * ItemTextSize - Area.height + ItemPadding; + float wheel = GetMouseWheelMove(); + float wheelAxis = wheel * ScrollSpeed * GetFrameTime(); + + _scroll += wheelAxis; + if (_scroll > 0) _scroll = 0; + if (_scroll <= -boxHeight) _scroll = -boxHeight; + } + + if (IsClicked()) + { + if (_highlightIndex > 0) + { + _selectedIndex = _highlightIndex; + OnItemSelect?.Invoke(Items[_selectedIndex]); + } + } + } + + protected override void Render() + { + BackgroundBrush?.FillArea(Area); + for (int i = 0; i < Items.Count; i++) + { + Rectangle area = new Rectangle( + Area.x + ItemPadding, + Area.y + i * ItemTextSize + ItemPadding + _scroll, + Area.width, + ItemTextSize + ); + if (i == _selectedIndex) + { + SelectionBrush?.FillArea(area); + } + else if (i == _highlightIndex) + { + HighlightBrush?.FillArea(area); + } + + DrawText(Items[i], area.x, area.y, ItemTextSize, ItemColor); + } + } +} \ No newline at end of file diff --git a/UI/Elements/Panel.cs b/UI/Elements/Panel.cs new file mode 100644 index 0000000..ae5e739 --- /dev/null +++ b/UI/Elements/Panel.cs @@ -0,0 +1,17 @@ +using BuildingGame.UI.Brushes; + +namespace BuildingGame.UI.Elements; + +public class Panel : Element +{ + public IBrush? Brush; + + public Panel(string name) : base(name) + { + } + + protected override void Render() + { + Brush?.FillArea(Area); + } +} \ No newline at end of file diff --git a/UI/Elements/TextBox.cs b/UI/Elements/TextBox.cs new file mode 100644 index 0000000..bb9b858 --- /dev/null +++ b/UI/Elements/TextBox.cs @@ -0,0 +1,45 @@ +using BuildingGame.UI.Brushes; + +namespace BuildingGame.UI.Elements; + +public class TextBox : TextElement +{ + public int MaxCharacters = 16; + + private bool _focused; + private OutlineBrush _brush; + + public TextBox(string name) : base(name) + { + _brush = new OutlineBrush(BLACK, LIGHTGRAY); + TextColor = BLACK; + } + + public override void Update() + { + if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT)) + { + _focused = IsHovered(); + _brush.LineColor = _focused ? GRAY : BLACK; + _brush.LineThick = _focused ? 1.5f : 1; + + GuiManager.IsFocused = _focused; + } + + BackgroundBrush = _brush; + + GatherInput(); + } + + private void GatherInput() + { + if (!_focused) return; + + int c = GetCharPressed(); + if (c is >= 32 and <= 125 && Text.Length < MaxCharacters) + Text += char.ConvertFromUtf32(c); + + if (IsKeyPressed(KeyboardKey.KEY_BACKSPACE) && Text.Length > 0) + Text = Text.Remove(Text.Length - 1); + } +} \ No newline at end of file diff --git a/UI/Elements/TextElement.cs b/UI/Elements/TextElement.cs new file mode 100644 index 0000000..a7a5a99 --- /dev/null +++ b/UI/Elements/TextElement.cs @@ -0,0 +1,50 @@ +using System.Numerics; +using BuildingGame.UI.Brushes; + +namespace BuildingGame.UI.Elements; + +public class TextElement : Element +{ + public IBrush? BackgroundBrush; + + public Color TextColor = WHITE; + public string Text = string.Empty; + public float TextSize = 10; + public Alignment TextAlignment = Alignment.TopLeft; + + public float Padding = 8f; + + public TextElement(string name) : base(name) + { + } + + protected override void Render() + { + Vector2 fontMeasure = MeasureTextEx(GuiManager.Font, Text, TextSize, TextSize / GuiManager.FontSize); + float width = MathF.Max(Area.width, fontMeasure.X) + Padding; + float height = MathF.Max(Area.height, fontMeasure.Y) + Padding; + + float xLeft = Area.x + Padding; + float xRight = Area.x + Area.width - fontMeasure.X - Padding * 2; + float xCenter = Area.x + Area.width / 2 - fontMeasure.X / 2; + float yTop = Area.y + Padding; + float yBottom = Area.y + Area.height - fontMeasure.Y - Padding * 2; + float yCenter = Area.y + Area.height / 2 - fontMeasure.Y / 2; + + Vector2 xy = TextAlignment switch + { + Alignment.TopLeft => new Vector2(xLeft, yTop), + Alignment.TopRight => new Vector2(xRight, yTop), + Alignment.TopCenter => new Vector2(xCenter, yTop), + Alignment.CenterLeft => new Vector2(xLeft, yCenter), + Alignment.CenterRight => new Vector2(xRight, yCenter), + Alignment.Center => new Vector2(xCenter, yCenter), + Alignment.BottomLeft => new Vector2(xLeft, yBottom), + Alignment.BottomRight => new Vector2(xRight, yBottom), + Alignment.BottomCenter => new Vector2(xCenter, yBottom) + }; + + BackgroundBrush?.FillArea(new Rectangle(Area.x - Padding, Area.y - Padding, width, height)); + DrawText(Text, xy.X, xy.Y, TextSize, TextColor); + } +} \ No newline at end of file diff --git a/UI/Elements/Tooltip.cs b/UI/Elements/Tooltip.cs new file mode 100644 index 0000000..6d4ef8b --- /dev/null +++ b/UI/Elements/Tooltip.cs @@ -0,0 +1,30 @@ +using System.Numerics; + +namespace BuildingGame.UI.Elements; + +public class Tooltip : TextElement +{ + public Tooltip(string name) : base(name) + { + Visible = false; + TextAlignment = Alignment.CenterLeft; + } + + public override void Update() + { + Element? el = GuiManager.GetElementUnderMouse(); + + if (el != null && el.TooltipText != string.Empty) + { + Text = el.TooltipText; + Visible = true; + + Vector2 measure = MeasureTextEx(GuiManager.Font, Text, TextSize, TextSize / GuiManager.FontSize); + Vector2 size = measure + new Vector2(Padding * 4, Padding * 2); + if (Size != size) Size = size; + } + else Visible = false; + + Position = GetMousePosition() + new Vector2(16); + } +} \ No newline at end of file diff --git a/UI/GuiManager.cs b/UI/GuiManager.cs new file mode 100644 index 0000000..882af95 --- /dev/null +++ b/UI/GuiManager.cs @@ -0,0 +1,88 @@ +namespace BuildingGame.UI; + +public static class GuiManager +{ + private static List _elements = new List(); + + public static bool IsFocused = false; + + public static readonly Font Font = GetFontDefault(); + public static readonly int FontSize = 10; + + public static void Add(Element element) + { + _elements.Add(element); + } + + public static void Remove(Element element) + { + _elements.Remove(element); + } + + public static void Remove(string name) + { + int index = _elements.FindIndex(e => string.Equals(e.Name, name, StringComparison.CurrentCultureIgnoreCase)); + if (index < 0) return; + _elements.RemoveAt(index); + } + + public static Element? Get(string name) + { + int index = _elements.FindIndex(e => string.Equals(e.Name, name, StringComparison.CurrentCultureIgnoreCase)); + if (index < 0) return null; + return _elements[index]; + } + + public static TElement? GetAs(string name) where TElement : Element + { + int index = _elements.FindIndex(e => + e.GetType() == typeof(TElement) && string.Equals(e.Name, name, StringComparison.CurrentCultureIgnoreCase)); + if (index < 0) return null; + return _elements[index] as TElement; + } + + public static bool IsMouseOverElement() + { + var elements = _elements; + foreach (var el in elements) + { + if (el.IsHovered()) return true; + } + + return false; + } + + public static Element? GetElementUnderMouse() + { + var elements = _elements; + foreach (var el in elements) + { + if (el.IsHovered()) return el; + } + + return null; + } + + public static void Update() + { + var elements = _elements; + + foreach (var el in elements) + { + if (!el.Active) continue; + el.Update(); + } + } + + public static void Draw() + { + var elements = _elements; + elements.Sort((e1, e2) => e1.ZIndex.CompareTo(e1.ZIndex)); + foreach (var el in elements) + { + if (!el.Active) continue; + if (!el.Visible) continue; + el.Draw(); + } + } +} \ No newline at end of file From 96d8574397d1c5c7be8d6ea03e0ec148353b1fb3 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Sat, 21 Oct 2023 15:29:05 +0300 Subject: [PATCH 014/107] use yaml instead of json --- Assets/Atlas.json | 252 ------------------------------------- Assets/Atlas.yaml | 212 +++++++++++++++++++++++++++++++ BuildingGame.csproj | 2 +- Tiles/Atlas/AtlasLoader.cs | 18 ++- Tiles/Atlas/AtlasTile.cs | 16 +-- Tiles/Atlas/AtlasVec2.cs | 17 +++ Tiles/Atlas/JsonVec2.cs | 11 -- 7 files changed, 250 insertions(+), 278 deletions(-) delete mode 100644 Assets/Atlas.json create mode 100644 Assets/Atlas.yaml create mode 100644 Tiles/Atlas/AtlasVec2.cs delete mode 100644 Tiles/Atlas/JsonVec2.cs diff --git a/Assets/Atlas.json b/Assets/Atlas.json deleted file mode 100644 index 2e4e9fb..0000000 --- a/Assets/Atlas.json +++ /dev/null @@ -1,252 +0,0 @@ -{ - "smooth_stone": { - "AtlasOffset": { - "X": 0, - "Y": 0 - } - }, - "wooden_planks": { - "AtlasOffset": { - "X": 1, - "Y": 0 - } - }, - "dirt": { - "AtlasOffset": { - "X": 2, - "Y": 0 - } - }, - "grass_block": { - "AtlasOffset": { - "X": 3, - "Y": 0 - } - }, - "grass": { - "AtlasOffset": { - "X": 4, - "Y": 0 - } - }, - "sand": { - "AtlasOffset": { - "X": 5, - "Y": 0 - } - }, - "water": { - "AtlasOffset": { - "X": 6, - "Y": 0 - } - }, - "lava": { - "AtlasOffset": { - "X": 7, - "Y": 0 - } - }, - "obsidian": { - "AtlasOffset": { - "X": 8, - "Y": 0 - } - }, - "door": { - "AtlasOffset": { - "X": 9, - "Y": 0 - }, - "Size": { - "X": 1, - "Y": 2 - } - }, - "nature_stone": { - "AtlasOffset": { - "X": 0, - "Y": 1 - } - }, - "white_plate": { - "AtlasOffset": { - "X": 1, - "Y": 1 - } - }, - "green_plate": { - "AtlasOffset": { - "X": 2, - "Y": 1 - } - }, - "red_plate": { - "AtlasOffset": { - "X": 3, - "Y": 1 - } - }, - "blue_plate": { - "AtlasOffset": { - "X": 4, - "Y": 1 - } - }, - "chamomile": { - "AtlasOffset": { - "X": 5, - "Y": 1 - } - }, - "red_tulip": { - "AtlasOffset": { - "X": 6, - "Y": 1 - } - }, - "chamomile_pot": { - "AtlasOffset": { - "X": 7, - "Y": 1 - } - }, - "red_tulip_pot": { - "AtlasOffset": { - "X": 8, - "Y": 1 - } - }, - "wooden_stairs": { - "AtlasOffset": { - "X": 0, - "Y": 2 - } - }, - "wooden_slab": { - "AtlasOffset": { - "X": 1, - "Y": 2 - } - }, - "stone_stairs": { - "AtlasOffset": { - "X": 2, - "Y": 2 - } - }, - "stone_slab": { - "AtlasOffset": { - "X": 3, - "Y": 2 - } - }, - "wooden_pole": { - "AtlasOffset": { - "X": 4, - "Y": 2 - } - }, - "wooden_pole_handle": { - "AtlasOffset": { - "X": 5, - "Y": 2 - } - }, - "stone_pole": { - "AtlasOffset": { - "X": 6, - "Y": 2 - } - }, - "stone_pole_handle": { - "AtlasOffset": { - "X": 7, - "Y": 2 - } - }, - "log": { - "AtlasOffset": { - "X": 8, - "Y": 2 - } - }, - "log_top": { - "AtlasOffset": { - "X": 9, - "Y": 2 - } - }, - "foliage": { - "AtlasOffset": { - "X": 0, - "Y": 3 - } - }, - "glass": { - "AtlasOffset": { - "X": 1, - "Y": 3 - } - }, - "white_wool": { - "AtlasOffset": { - "X": 2, - "Y": 3 - } - }, - "red_wool": { - "AtlasOffset": { - "X": 3, - "Y": 3 - } - }, - "green_wool": { - "AtlasOffset": { - "X": 4, - "Y": 3 - } - }, - "blue_wool": { - "AtlasOffset": { - "X": 5, - "Y": 3 - } - }, - "yellow_wool": { - "AtlasOffset": { - "X": 6, - "Y": 3 - } - }, - "black_wool": { - "AtlasOffset": { - "X": 7, - "Y": 3 - } - }, - "dark_gray_wool": { - "AtlasOffset": { - "X": 8, - "Y": 3 - } - }, - "gray_wool": { - "AtlasOffset": { - "X": 9, - "Y": 3 - } - }, - "sponge": { - "AtlasOffset": { - "X": 0, - "Y": 4 - } - }, - "infection_block": { - "AtlasOffset": { - "X": 1, - "Y": 4 - } - } -} diff --git a/Assets/Atlas.yaml b/Assets/Atlas.yaml new file mode 100644 index 0000000..80442b5 --- /dev/null +++ b/Assets/Atlas.yaml @@ -0,0 +1,212 @@ +# layer 0 (x: 0-9, y: 0) +smooth_stone: + atlas: + x: 0 + y: 0 + +wooden_planks: + atlas: + x: 1 + y: 0 + +dirt: + atlas: + x: 2 + y: 0 + +grass_block: + atlas: + x: 3 + y: 0 + +grass: + atlas: + x: 4 + y: 0 + +sand: + atlas: + x: 5 + y: 0 + +water: + atlas: + x: 6 + y: 0 + +lava: + atlas: + x: 7 + y: 0 + +obsidian: + atlas: + x: 8 + y: 0 + +door: + atlas: + x: 9 + y: 0 + size: + x: 1 + y: 2 + +# layer 1 (x: 0-8, y: 1) +nature_stone: + atlas: + x: 0 + y: 1 + +white_plate: + atlas: + x: 1 + y: 1 + +green_plate: + atlas: + x: 2 + y: 1 + +red_plate: + atlas: + x: 3 + y: 1 + +blue_plate: + atlas: + x: 4 + y: 1 + +chamomile: + atlas: + x: 5 + y: 1 + +red_tulip: + atlas: + x: 6 + y: 1 + +chamomile_pot: + atlas: + x: 7 + y: 1 + +red_tulip_pot: + atlas: + x: 8 + y: 1 + +# layer 2 (x: 0-9, y: 2) +wooden_stairs: + atlas: + x: 0 + y: 2 + +wooden_slab: + atlas: + x: 1 + y: 2 + +stone_stairs: + atlas: + x: 2 + y: 2 + +stone_slab: + atlas: + x: 3 + y: 2 + +wooden_pole: + atlas: + x: 4 + y: 2 + +wooden_pole_handle: + atlas: + x: 5 + y: 2 + +stone_pole: + atlas: + x: 6 + y: 2 + +stone_pole_handle: + atlas: + x: 7 + y: 2 + +log: + atlas: + x: 8 + y: 2 + +log_top: + atlas: + x: 9 + y: 2 + +# layer 3 (x: 0-9, y: 3) +foliage: + atlas: + x: 0 + y: 3 + +glass: + atlas: + x: 1 + y: 3 + +white_wool: + atlas: + x: 2 + y: 3 + +red_wool: + atlas: + x: 3 + y: 3 + +green_wool: + atlas: + x: 4 + y: 3 + +blue_wool: + atlas: + x: 5 + y: 3 + +yellow_wool: + atlas: + x: 6 + y: 3 + +black_wool: + atlas: + x: 7 + y: 3 + +dark_gray_wool: + atlas: + x: 8 + y: 3 + +gray_wool: + atlas: + x: 9 + y: 3 + +# layer 4 (x: 0-1, y: 4) +sponge: + atlas: + x: 0 + y: 4 + +infection_block: + atlas: + x: 1 + y: 4 \ No newline at end of file diff --git a/BuildingGame.csproj b/BuildingGame.csproj index e1171dc..eaee8b5 100644 --- a/BuildingGame.csproj +++ b/BuildingGame.csproj @@ -26,11 +26,11 @@ - + diff --git a/Tiles/Atlas/AtlasLoader.cs b/Tiles/Atlas/AtlasLoader.cs index 5124f0d..37396e1 100644 --- a/Tiles/Atlas/AtlasLoader.cs +++ b/Tiles/Atlas/AtlasLoader.cs @@ -1,20 +1,26 @@ -using Newtonsoft.Json; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; namespace BuildingGame.Tiles.Atlas; public static class AtlasLoader { - public const string AtlasFile = "Assets/Atlas.json"; + public const string AtlasFile = "Assets/Atlas.yaml"; + + private static readonly IDeserializer _yaml = new DeserializerBuilder() + .WithNamingConvention(UnderscoredNamingConvention.Instance) + .IgnoreUnmatchedProperties() + .Build(); public static Dictionary LoadTiles() { if (!File.Exists(AtlasFile)) throw new InvalidOperationException("Can't load Atlas.json because it doesn't exists"); - string json = File.ReadAllText(AtlasFile); + string yamlText = File.ReadAllText(AtlasFile); - return JsonConvert.DeserializeObject>(json) ?? - throw new InvalidOperationException("Atlas.json is empty"); + return _yaml.Deserialize>(yamlText) ?? + throw new InvalidOperationException("Atlas.yaml is empty");; } public static Dictionary ConvertTiles(Dictionary tiles) @@ -24,7 +30,7 @@ public static Dictionary ConvertTiles(Dictionary new Vector2(vec.X, vec.Y); +} \ No newline at end of file diff --git a/Tiles/Atlas/JsonVec2.cs b/Tiles/Atlas/JsonVec2.cs deleted file mode 100644 index 9a8e313..0000000 --- a/Tiles/Atlas/JsonVec2.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Numerics; - -namespace BuildingGame.Tiles.Atlas; - -public struct JsonVec2 -{ - public float X { get; set; } - public float Y { get; set; } - - public static implicit operator Vector2(JsonVec2 vec) => new Vector2(vec.X, vec.Y); -} \ No newline at end of file From 05e5a976c2ea83ede848b2d7843e3de80fccab2a Mon Sep 17 00:00:00 2001 From: danilwhale Date: Mon, 27 Nov 2023 15:54:41 +0200 Subject: [PATCH 015/107] update to raylib 5.0 --- BuildingGame.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BuildingGame.csproj b/BuildingGame.csproj index eaee8b5..1448a31 100644 --- a/BuildingGame.csproj +++ b/BuildingGame.csproj @@ -26,7 +26,7 @@ - + From 700fe1fc7941f7904fff3c858b486c78c9711b50 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Mon, 27 Nov 2023 15:54:59 +0200 Subject: [PATCH 016/107] add sln --- BuildingGame.sln | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 BuildingGame.sln diff --git a/BuildingGame.sln b/BuildingGame.sln new file mode 100644 index 0000000..4e48369 --- /dev/null +++ b/BuildingGame.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildingGame", "BuildingGame.csproj", "{602CEEA8-83AB-4D74-974F-308F1BEFB3E5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {602CEEA8-83AB-4D74-974F-308F1BEFB3E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {602CEEA8-83AB-4D74-974F-308F1BEFB3E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {602CEEA8-83AB-4D74-974F-308F1BEFB3E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {602CEEA8-83AB-4D74-974F-308F1BEFB3E5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F66DCBE7-11D8-4DE0-AE01-B1A4F0CA2304} + EndGlobalSection +EndGlobal From 54636e7f78cfd956236a200660a8040b709c5ed6 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Mon, 27 Nov 2023 15:55:09 +0200 Subject: [PATCH 017/107] use better gitignore --- .gitignore | 226 +++++++++++++++++++++-------------------------------- 1 file changed, 87 insertions(+), 139 deletions(-) diff --git a/.gitignore b/.gitignore index f1abf07..104b544 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,10 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## -<<<<<<< HEAD -<<<<<<< HEAD -======= -<<<<<<< HEAD -## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore -======= -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore ->>>>>>> 1523d8c (Initial commit) -======= ->>>>>>> c6d355b (0.0.3-prealpha) -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore -======= -## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore ->>>>>>> 009817d (0.0.3-prealpha) -<<<<<<< HEAD -======= ->>>>>>> 415de6f (0.0.3-prealpha) ->>>>>>> c6d355b (0.0.3-prealpha) +## Get latest from `dotnet new gitignore` + +# dotenv files +.env # User-specific files *.rsuser @@ -40,22 +26,7 @@ mono_crash.* [Rr]eleases/ x64/ x86/ -<<<<<<< HEAD -<<<<<<< HEAD -======= -[Ww][Ii][Nn]32/ ->>>>>>> 009817d (0.0.3-prealpha) -======= -<<<<<<< HEAD -[Ww][Ii][Nn]32/ -======= ->>>>>>> 1523d8c (Initial commit) -======= -======= [Ww][Ii][Nn]32/ ->>>>>>> 009817d (0.0.3-prealpha) ->>>>>>> 415de6f (0.0.3-prealpha) ->>>>>>> c6d355b (0.0.3-prealpha) [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ @@ -89,31 +60,17 @@ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ -# .NET Core +# .NET project.lock.json project.fragment.lock.json artifacts/ -<<<<<<< HEAD -<<<<<<< HEAD -======= -<<<<<<< HEAD -# ASP.NET Scaffolding -ScaffoldingReadMe.txt +# Tye +.tye/ -======= ->>>>>>> 1523d8c (Initial commit) -======= ->>>>>>> c6d355b (0.0.3-prealpha) -======= # ASP.NET Scaffolding ScaffoldingReadMe.txt ->>>>>>> 009817d (0.0.3-prealpha) -<<<<<<< HEAD -======= ->>>>>>> 415de6f (0.0.3-prealpha) ->>>>>>> c6d355b (0.0.3-prealpha) # StyleCop StyleCopReport.xml @@ -139,22 +96,7 @@ StyleCopReport.xml *.tmp_proj *_wpftmp.csproj *.log -<<<<<<< HEAD -<<<<<<< HEAD -======= -*.tlog ->>>>>>> 009817d (0.0.3-prealpha) -======= -<<<<<<< HEAD *.tlog -======= ->>>>>>> 1523d8c (Initial commit) -======= -======= -*.tlog ->>>>>>> 009817d (0.0.3-prealpha) ->>>>>>> 415de6f (0.0.3-prealpha) ->>>>>>> c6d355b (0.0.3-prealpha) *.vspscc *.vssscc .builds @@ -206,30 +148,11 @@ _TeamCity* .axoCover/* !.axoCover/settings.json -<<<<<<< HEAD -<<<<<<< HEAD -======= -======= -<<<<<<< HEAD -======= -======= ->>>>>>> 415de6f (0.0.3-prealpha) ->>>>>>> c6d355b (0.0.3-prealpha) # Coverlet is a free, cross platform Code Coverage Tool coverage*.json coverage*.xml coverage*.info -<<<<<<< HEAD ->>>>>>> 009817d (0.0.3-prealpha) -======= -<<<<<<< HEAD -======= ->>>>>>> 1523d8c (Initial commit) -======= ->>>>>>> 009817d (0.0.3-prealpha) ->>>>>>> 415de6f (0.0.3-prealpha) ->>>>>>> c6d355b (0.0.3-prealpha) # Visual Studio code coverage results *.coverage *.coveragexml @@ -377,15 +300,6 @@ node_modules/ # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw -<<<<<<< HEAD -<<<<<<< HEAD -======= -======= -<<<<<<< HEAD -======= -======= ->>>>>>> 415de6f (0.0.3-prealpha) ->>>>>>> c6d355b (0.0.3-prealpha) # Visual Studio 6 auto-generated project file (contains which files were open etc.) *.vbp @@ -397,16 +311,6 @@ node_modules/ *.ncb *.aps -<<<<<<< HEAD ->>>>>>> 009817d (0.0.3-prealpha) -======= -<<<<<<< HEAD -======= ->>>>>>> 1523d8c (Initial commit) -======= ->>>>>>> 009817d (0.0.3-prealpha) ->>>>>>> 415de6f (0.0.3-prealpha) ->>>>>>> c6d355b (0.0.3-prealpha) # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts @@ -463,26 +367,9 @@ ASALocalRun/ # Local History for Visual Studio .localhistory/ -<<<<<<< HEAD -<<<<<<< HEAD -======= -<<<<<<< HEAD -# Visual Studio History (VSHistory) files -.vshistory/ - -======= ->>>>>>> 1523d8c (Initial commit) -======= ->>>>>>> c6d355b (0.0.3-prealpha) -======= # Visual Studio History (VSHistory) files .vshistory/ ->>>>>>> 009817d (0.0.3-prealpha) -<<<<<<< HEAD -======= ->>>>>>> 415de6f (0.0.3-prealpha) ->>>>>>> c6d355b (0.0.3-prealpha) # BeatPulse healthcheck temp database healthchecksdb @@ -491,15 +378,6 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ -<<<<<<< HEAD -<<<<<<< HEAD -======= -======= -<<<<<<< HEAD -======= -======= ->>>>>>> 415de6f (0.0.3-prealpha) ->>>>>>> c6d355b (0.0.3-prealpha) # Fody - auto-generated XML schema FodyWeavers.xsd @@ -524,13 +402,83 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml -<<<<<<< HEAD ->>>>>>> 009817d (0.0.3-prealpha) -======= -<<<<<<< HEAD -======= ->>>>>>> 1523d8c (Initial commit) -======= ->>>>>>> 009817d (0.0.3-prealpha) ->>>>>>> 415de6f (0.0.3-prealpha) ->>>>>>> c6d355b (0.0.3-prealpha) +.idea + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp From 14403fe812ac91827d89ee28e55e6d02a3ca1411 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Mon, 27 Nov 2023 15:57:43 +0200 Subject: [PATCH 018/107] fix and update gui --- Tiles/Tiles.cs | 5 +++++ UI/Element.cs | 13 ++++--------- UI/Elements/Button.cs | 5 +++-- UI/Elements/CheckBox.cs | 6 +++--- UI/Elements/ListBox.cs | 4 ++-- UI/Elements/Panel.cs | 3 ++- UI/Elements/TextBox.cs | 2 +- UI/Elements/TextElement.cs | 20 ++++++++++---------- 8 files changed, 30 insertions(+), 28 deletions(-) diff --git a/Tiles/Tiles.cs b/Tiles/Tiles.cs index 10e6e5d..0b842bd 100644 --- a/Tiles/Tiles.cs +++ b/Tiles/Tiles.cs @@ -22,6 +22,11 @@ public static Tile GetTile(string name) return _Tiles.First(kv => string.Equals(kv.Key.Name, name, StringComparison.CurrentCultureIgnoreCase)).Value; } + public static Tile[] GetTiles() + { + return _Tiles.Values.ToArray(); + } + public static void RegisterCustomTile(string name, T tile) where T : Tile { var key = _Tiles.Keys.First(k => string.Equals(k.Name, name, StringComparison.CurrentCultureIgnoreCase)); diff --git a/UI/Element.cs b/UI/Element.cs index a12d806..61240f4 100644 --- a/UI/Element.cs +++ b/UI/Element.cs @@ -56,15 +56,10 @@ public virtual void Update() public void Draw() { BeginTextureMode(_controlTexture); - - RlGl.rlPushMatrix(); - RlGl.rlTranslatef(-Area.x, -Area.y, 0); - ClearBackground(BLANK); + Render(); - - RlGl.rlPopMatrix(); - + EndTextureMode(); Vector2 offset = Origin switch @@ -84,8 +79,8 @@ public void Draw() DrawTexturePro( _controlTexture.texture, new Rectangle( - 0, 0, - _Area.width, -_Area.height // we need to negate render texture height because opengl uses bottom-left instead of top-left + -1, 0, + _Area.width + 1, -_Area.height - 1 // we need to negate render texture height because opengl uses bottom-left instead of top-left ), _Area, offset, Rotation, WHITE diff --git a/UI/Elements/Button.cs b/UI/Elements/Button.cs index 8028297..bdc8d77 100644 --- a/UI/Elements/Button.cs +++ b/UI/Elements/Button.cs @@ -3,7 +3,8 @@ namespace BuildingGame.UI.Elements; public class Button : TextElement { public const string HoverText = "> "; - + + public bool ShowHoverText = true; public event Action? OnClick; public Button(string name) : base(name) @@ -17,7 +18,7 @@ public override void Update() OnClick?.Invoke(); } - if (IsHovered() && !Text.StartsWith(HoverText)) + if (ShowHoverText && IsHovered() && !Text.StartsWith(HoverText)) { Text = HoverText + Text; } diff --git a/UI/Elements/CheckBox.cs b/UI/Elements/CheckBox.cs index 9e6d9a2..41d7df1 100644 --- a/UI/Elements/CheckBox.cs +++ b/UI/Elements/CheckBox.cs @@ -27,8 +27,8 @@ public override void Update() protected override void Render() { Rectangle boxArea = new Rectangle( - Area.x, - Area.y + Area.height / 2 - 18 * BoxScale / 2, + 0, + 0 + Area.height / 2 - 18 * BoxScale / 2, 18 * BoxScale, 18 * BoxScale ); @@ -42,6 +42,6 @@ protected override void Render() Vector2.Zero, 0, WHITE); } - DrawText(Text, Area.x + 8 + 18 * BoxScale, Area.y + Area.height / 2 - TextSize / 2f, TextSize, TextColor); + DrawText(Text, 8 + 18 * BoxScale, Area.height / 2 - TextSize / 2f, TextSize, TextColor); } } \ No newline at end of file diff --git a/UI/Elements/ListBox.cs b/UI/Elements/ListBox.cs index 378a74a..5b28597 100644 --- a/UI/Elements/ListBox.cs +++ b/UI/Elements/ListBox.cs @@ -60,8 +60,8 @@ protected override void Render() for (int i = 0; i < Items.Count; i++) { Rectangle area = new Rectangle( - Area.x + ItemPadding, - Area.y + i * ItemTextSize + ItemPadding + _scroll, + ItemPadding, + i * ItemTextSize + ItemPadding + _scroll, Area.width, ItemTextSize ); diff --git a/UI/Elements/Panel.cs b/UI/Elements/Panel.cs index ae5e739..3bbf8aa 100644 --- a/UI/Elements/Panel.cs +++ b/UI/Elements/Panel.cs @@ -5,6 +5,7 @@ namespace BuildingGame.UI.Elements; public class Panel : Element { public IBrush? Brush; + public int Padding = 0; public Panel(string name) : base(name) { @@ -12,6 +13,6 @@ public Panel(string name) : base(name) protected override void Render() { - Brush?.FillArea(Area); + Brush?.FillArea(new Rectangle(Padding, Padding, Area.width - Padding - 1, Area.height - Padding - 1)); } } \ No newline at end of file diff --git a/UI/Elements/TextBox.cs b/UI/Elements/TextBox.cs index bb9b858..195dd66 100644 --- a/UI/Elements/TextBox.cs +++ b/UI/Elements/TextBox.cs @@ -21,7 +21,7 @@ public override void Update() { _focused = IsHovered(); _brush.LineColor = _focused ? GRAY : BLACK; - _brush.LineThick = _focused ? 1.5f : 1; + // _brush.LineThick = _focused ? 1.5f : 1; GuiManager.IsFocused = _focused; } diff --git a/UI/Elements/TextElement.cs b/UI/Elements/TextElement.cs index a7a5a99..7699b9b 100644 --- a/UI/Elements/TextElement.cs +++ b/UI/Elements/TextElement.cs @@ -12,7 +12,7 @@ public class TextElement : Element public float TextSize = 10; public Alignment TextAlignment = Alignment.TopLeft; - public float Padding = 8f; + public float Padding = 0; public TextElement(string name) : base(name) { @@ -21,15 +21,15 @@ public TextElement(string name) : base(name) protected override void Render() { Vector2 fontMeasure = MeasureTextEx(GuiManager.Font, Text, TextSize, TextSize / GuiManager.FontSize); - float width = MathF.Max(Area.width, fontMeasure.X) + Padding; - float height = MathF.Max(Area.height, fontMeasure.Y) + Padding; + float width = Area.width - Padding - 1; + float height = Area.height - Padding - 1; - float xLeft = Area.x + Padding; - float xRight = Area.x + Area.width - fontMeasure.X - Padding * 2; - float xCenter = Area.x + Area.width / 2 - fontMeasure.X / 2; - float yTop = Area.y + Padding; - float yBottom = Area.y + Area.height - fontMeasure.Y - Padding * 2; - float yCenter = Area.y + Area.height / 2 - fontMeasure.Y / 2; + float xLeft = Padding + 4; + float xRight = Area.width - fontMeasure.X - Padding * 2; + float xCenter = Area.width / 2 - fontMeasure.X / 2; + float yTop = Padding + 4; + float yBottom = Area.height - fontMeasure.Y - Padding * 2; + float yCenter = Area.height / 2 - fontMeasure.Y / 2; Vector2 xy = TextAlignment switch { @@ -44,7 +44,7 @@ protected override void Render() Alignment.BottomCenter => new Vector2(xCenter, yBottom) }; - BackgroundBrush?.FillArea(new Rectangle(Area.x - Padding, Area.y - Padding, width, height)); + BackgroundBrush?.FillArea(new Rectangle(Padding, Padding, width, height)); DrawText(Text, xy.X, xy.Y, TextSize, TextColor); } } \ No newline at end of file From 228ab74fdfb132a0261620101c65f3f1225793c5 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Mon, 27 Nov 2023 21:25:27 +0200 Subject: [PATCH 019/107] more gui fixes --- UI/Element.cs | 6 +++--- UI/Elements/TextBox.cs | 2 +- UI/GuiManager.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/UI/Element.cs b/UI/Element.cs index 61240f4..fd068fb 100644 --- a/UI/Element.cs +++ b/UI/Element.cs @@ -95,17 +95,17 @@ protected virtual void Render() public bool IsHovered() { - return CheckCollisionPointRec(GetMousePosition(), Area); + return CheckCollisionPointRec(GetMousePosition(), Area) && Visible && Active; } public bool IsClicked() { - return IsHovered() && IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT); + return IsHovered() && IsMouseButtonReleased(MouseButton.MOUSE_BUTTON_LEFT) && Visible && Active; } public bool IsPressed() { - return IsHovered() && IsMouseButtonDown(MouseButton.MOUSE_BUTTON_LEFT); + return IsHovered() && IsMouseButtonDown(MouseButton.MOUSE_BUTTON_LEFT) && Visible && Active; } public void Dispose() diff --git a/UI/Elements/TextBox.cs b/UI/Elements/TextBox.cs index 195dd66..7ebe8af 100644 --- a/UI/Elements/TextBox.cs +++ b/UI/Elements/TextBox.cs @@ -39,7 +39,7 @@ private void GatherInput() if (c is >= 32 and <= 125 && Text.Length < MaxCharacters) Text += char.ConvertFromUtf32(c); - if (IsKeyPressed(KeyboardKey.KEY_BACKSPACE) && Text.Length > 0) + if (IsKeyPressedRepeat((int)KeyboardKey.KEY_BACKSPACE) && Text.Length > 0) Text = Text.Remove(Text.Length - 1); } } \ No newline at end of file diff --git a/UI/GuiManager.cs b/UI/GuiManager.cs index 882af95..a898515 100644 --- a/UI/GuiManager.cs +++ b/UI/GuiManager.cs @@ -46,7 +46,7 @@ public static bool IsMouseOverElement() var elements = _elements; foreach (var el in elements) { - if (el.IsHovered()) return true; + if (el.Active && el.Visible && el.IsHovered()) return true; } return false; From 6aefa54c3e56c2ee5dc8f0aaca28944dc6b4ce2d Mon Sep 17 00:00:00 2001 From: danilwhale Date: Mon, 27 Nov 2023 22:14:05 +0200 Subject: [PATCH 020/107] update libraries --- BuildingGame.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BuildingGame.csproj b/BuildingGame.csproj index 1448a31..34f4834 100644 --- a/BuildingGame.csproj +++ b/BuildingGame.csproj @@ -27,9 +27,9 @@ - - - + + + From 1314218bf84cedb53f26a9a71867de83a122e082 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Mon, 27 Nov 2023 22:55:18 +0200 Subject: [PATCH 021/107] add tile equality and hashcode --- Tiles/Tile.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Tiles/Tile.cs b/Tiles/Tile.cs index 3b70bea..8ce706e 100644 --- a/Tiles/Tile.cs +++ b/Tiles/Tile.cs @@ -77,4 +77,14 @@ public virtual void DrawPreview(float x, float y) Vector2.Zero, 0, new Color(255, 255, 255, 120) ); } + + public override bool Equals(object? obj) + { + return obj is Tile t && t.TexCoord == TexCoord && t.Size == Size; + } + + public override int GetHashCode() + { + return TexCoord.GetHashCode() ^ Size.GetHashCode(); + } } \ No newline at end of file From 5849711cc6bb7c5f98b1bcf45a535fe614d0f1d8 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Mon, 27 Nov 2023 22:55:55 +0200 Subject: [PATCH 022/107] make CurrentTile public --- Player.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Player.cs b/Player.cs index 2a12560..a9c25d2 100644 --- a/Player.cs +++ b/Player.cs @@ -7,6 +7,8 @@ namespace BuildingGame; public class Player { + public static byte CurrentTile = 2; + public Camera2D Camera; public World World; public float Speed; @@ -15,7 +17,6 @@ public class Player private Vector2 _targetPosition; private float _targetZoom; - private byte _currentTile = 2; public Player(World world, Vector2 position, float speed, float lerpSpeed) { @@ -73,7 +74,7 @@ private void UpdateTileControls() if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_LEFT) && !GuiManager.IsMouseOverElement()) { - World[tx, ty] = _currentTile; + World[tx, ty] = CurrentTile; } if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_RIGHT) && !GuiManager.IsMouseOverElement()) From f1a5471ba564b25a744626feb35ea74882dff06b Mon Sep 17 00:00:00 2001 From: danilwhale Date: Mon, 27 Nov 2023 22:56:14 +0200 Subject: [PATCH 023/107] implement basic ui --- Program.cs | 9 ++ UI/Interfaces/BlockMenu.cs | 125 ++++++++++++++++++++++++++++ UI/Interfaces/GameHud.cs | 68 +++++++++++++++ UI/Interfaces/UIInterface.cs | 79 ++++++++++++++++++ UI/Interfaces/UIInterfaceManager.cs | 32 +++++++ 5 files changed, 313 insertions(+) create mode 100644 UI/Interfaces/BlockMenu.cs create mode 100644 UI/Interfaces/GameHud.cs create mode 100644 UI/Interfaces/UIInterface.cs create mode 100644 UI/Interfaces/UIInterfaceManager.cs diff --git a/Program.cs b/Program.cs index a6a9eeb..0c4c843 100644 --- a/Program.cs +++ b/Program.cs @@ -7,6 +7,7 @@ using BuildingGame.UI; using BuildingGame.UI.Brushes; using BuildingGame.UI.Elements; +using BuildingGame.UI.Interfaces; SetConfigFlags(ConfigFlags.FLAG_VSYNC_HINT); SetConfigFlags(ConfigFlags.FLAG_WINDOW_RESIZABLE); @@ -25,6 +26,11 @@ Player player = new Player(world, world.PlayerPosition, 50, 0.1f); +BlockMenu menu = new BlockMenu(); +GameHud hud = new GameHud(menu); + +UIInterfaceManager.Initialize(); + while (!WindowShouldClose()) { if (IsKeyPressed(KeyboardKey.KEY_R)) @@ -33,6 +39,7 @@ player.Update(); world.Update(); GuiManager.Update(); + UIInterfaceManager.Update(); BeginDrawing(); ClearBackground(SKYBLUE); @@ -48,6 +55,8 @@ EndDrawing(); } +UIInterfaceManager.Destroy(); + player.PushCameraPosition(); world.Save(); diff --git a/UI/Interfaces/BlockMenu.cs b/UI/Interfaces/BlockMenu.cs new file mode 100644 index 0000000..717d653 --- /dev/null +++ b/UI/Interfaces/BlockMenu.cs @@ -0,0 +1,125 @@ +using System.Numerics; +using BuildingGame.Tiles; +using BuildingGame.UI.Brushes; +using BuildingGame.UI.Elements; + +namespace BuildingGame.UI.Interfaces; + +public class BlockMenu : UIInterface +{ + private Panel _background = null!; + private TextElement _menuTitle = null!; + private Button[] _tileButtons = null!; + + public override void Initialize() + { + base.Initialize(); + + _background = new Panel("blockMenuBackground") + { + Brush = new GradientBrush(new Color(0, 0, 25, 100), new Color(0, 0, 0, 200)), + ZIndex = 10 + }; + Elements.Add(_background); + + _menuTitle = new TextElement("blockMenuTitle") + { + Text = "Select a tile", + TextColor = WHITE, + TextSize = 32, + TextAlignment = Alignment.Center + }; + Elements.Add(_menuTitle); + + // new TextBox("tv3ewds") + // { + // Position = new Vector2(86, 86), + // TextColor = BLACK, + // MaxCharacters = 128 + // }; + + Tile[] tiles = Tiles.Tiles.GetTiles(); + _tileButtons = new Button[tiles.Length]; + + for (int i = 0; i < tiles.Length; i++) + { + float aspectX = Tile.TileSize / (Tile.TileSize * tiles[i].Size.X); + float aspectY = Tile.TileSize / (Tile.TileSize * tiles[i].Size.Y); + + float ratio = aspectX < aspectY ? aspectX : aspectY; + + _tileButtons[i] = new Button("tile_" + i) + { + Size = new Vector2(1) * Tile.RealTileSize, + BackgroundBrush = new TextureBrush(Resources.GetTexture("Atlas.png")) + { + CropArea = new Rectangle( + tiles[i].TexCoord.X * Tile.TileSize, + tiles[i].TexCoord.Y * Tile.TileSize, + Tile.TileSize, + Tile.TileSize + ) + }, + ShowHoverText = false + }; + + Elements.Add(_tileButtons[i]); + } + + Visible = false; + Configure(); + } + + public override void Configure() + { + base.Configure(); + + Vector2 screenSize = new Vector2(GetScreenWidth(), GetScreenHeight()); + + _background.Size = new Vector2(680, 420); + _background.Position = screenSize / 2 - _background.Size / 2; + + _menuTitle.Position = _background.Position; + _menuTitle.Size = _background.Size with { Y = 38 }; + + float x = 20; + float y = 40; + + for (int i = 0; i < _tileButtons.Length; i++) + { + Button tileButton = _tileButtons[i]; + Tile tile = Tiles.Tiles.GetTile((byte)(i + 1)); + + tileButton.Position = _background.Position + new Vector2(x, y); + + int ii = i; + tileButton.OnClick += () => + { + Player.CurrentTile = (byte)(ii + 1); + Visible = false; + }; + + x += Tile.RealTileSize + 8; + + if (x > _background.Size.X - Tile.RealTileSize) + { + x = 20; + y += Tile.RealTileSize + 8; + } + } + } + + public override void Resized() + { + base.Resized(); + + Configure(); + } + + public override void Update() + { + base.Update(); + + if (IsKeyPressed(KeyboardKey.KEY_B)) Visible = !Visible; + } +} \ No newline at end of file diff --git a/UI/Interfaces/GameHud.cs b/UI/Interfaces/GameHud.cs new file mode 100644 index 0000000..dab3d9b --- /dev/null +++ b/UI/Interfaces/GameHud.cs @@ -0,0 +1,68 @@ +using BuildingGame.Tiles; +using BuildingGame.UI.Brushes; +using BuildingGame.UI.Elements; + +namespace BuildingGame.UI.Interfaces; + +public class GameHud : UIInterface +{ + private const float TileButtonOffset = Tile.RealTileSize / 2; + private const float TileButtonSize = Tile.RealTileSize * 2; + + private BlockMenu _menu; + + private Button _tileMenuButton = null!; + + public GameHud(BlockMenu menu) + { + _menu = menu; + } + + public override void Initialize() + { + base.Initialize(); + + _tileMenuButton = new Button("tileMenuButton") + { + BackgroundBrush = new TextureBrush(Resources.GetTexture("Atlas.png")) + { + CropArea = new Rectangle(0, 0, Tile.TileSize, Tile.TileSize) + }, + ShowHoverText = false + }; + _tileMenuButton.OnClick += () => + { + _menu.Visible = !_menu.Visible; + }; + + Elements.Add(_tileMenuButton); + + Configure(); + } + + public override void Update() + { + base.Update(); + + var brush = (TextureBrush)_tileMenuButton.BackgroundBrush!; + var tile = Tiles.Tiles.GetTile(Player.CurrentTile); + (brush.CropArea.x, brush.CropArea.y) = (tile.TexCoord.X * Tile.TileSize, tile.TexCoord.Y * Tile.TileSize); + } + + public override void Configure() + { + base.Configure(); + + _tileMenuButton.Area = new Rectangle( + GetScreenWidth() - TileButtonSize - TileButtonOffset, TileButtonOffset, + TileButtonSize, TileButtonSize + ); + } + + public override void Resized() + { + base.Resized(); + + Configure(); + } +} diff --git a/UI/Interfaces/UIInterface.cs b/UI/Interfaces/UIInterface.cs new file mode 100644 index 0000000..000b626 --- /dev/null +++ b/UI/Interfaces/UIInterface.cs @@ -0,0 +1,79 @@ +using System.Numerics; + +namespace BuildingGame.UI.Interfaces; + +public class UIInterface +{ + public bool Visible + { + get => _visible; + set + { + _visible = value; + foreach (var el in Elements) + { + el.Visible = value; + } + } + } + + public bool Active + { + get => _active; + set + { + _active = value; + foreach (var el in Elements) + { + el.Active = value; + } + } + } + + protected List Elements = new List(); + protected Vector2 Position; + private bool _visible = true; + private bool _active = true; + + public UIInterface() + { + UIInterfaceManager.Add(this); + } + + public void Reload() + { + Destroy(); + Initialize(); + } + + public virtual void Initialize() { } + + public virtual void Configure() { } + + public virtual void Update() + { + if (!_active) return; + if (IsWindowResized()) Resized(); + } + public virtual void Resized() { } + + public virtual void Destroy() + { + DestroyElements(); + } + + protected void SetRelativePosition(ref Element element, Vector2 position) + { + element.Position = Position + position; + } + + protected void DestroyElements() + { + foreach (var el in Elements) + { + GuiManager.Remove(el); + } + + Elements.Clear(); + } +} \ No newline at end of file diff --git a/UI/Interfaces/UIInterfaceManager.cs b/UI/Interfaces/UIInterfaceManager.cs new file mode 100644 index 0000000..1e1361e --- /dev/null +++ b/UI/Interfaces/UIInterfaceManager.cs @@ -0,0 +1,32 @@ +namespace BuildingGame.UI.Interfaces; + +public static class UIInterfaceManager +{ + private static List _interfaces = new List(); + + public static int Add(UIInterface uiInterface) + { + _interfaces.Add(uiInterface); + return _interfaces.Count - 1; + } + + public static void Remove(int id) + { + _interfaces.RemoveAt(id); + } + + public static void Initialize() + { + foreach (var i in _interfaces) i.Initialize(); + } + + public static void Update() + { + foreach (var i in _interfaces) i.Update(); + } + + public static void Destroy() + { + foreach (var i in _interfaces) i.Destroy(); + } +} From bbc2e55eaef9c40385d74f16ce210c4050e2af53 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Tue, 28 Nov 2023 15:04:56 +0200 Subject: [PATCH 024/107] close block menu if clicked outside panel --- UI/Interfaces/BlockMenu.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/UI/Interfaces/BlockMenu.cs b/UI/Interfaces/BlockMenu.cs index 717d653..a392b1a 100644 --- a/UI/Interfaces/BlockMenu.cs +++ b/UI/Interfaces/BlockMenu.cs @@ -120,6 +120,8 @@ public override void Update() { base.Update(); - if (IsKeyPressed(KeyboardKey.KEY_B)) Visible = !Visible; + if (IsKeyReleased(KeyboardKey.KEY_B)) Visible = !Visible; + if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT) && !_background.IsHovered()) + Visible = false; } } \ No newline at end of file From 7d595c1809a5edce9383004139dc0c983b917a4a Mon Sep 17 00:00:00 2001 From: danilwhale Date: Tue, 28 Nov 2023 16:59:12 +0200 Subject: [PATCH 025/107] implement old format backups, new bgworld 2.1 format, lvl format reading, make bgworld 2 format readonly --- Player.cs | 14 ++++--- Program.cs | 10 +++-- Tiles/Data/TileFlags.cs | 30 +++++++++++++-- Tiles/Data/TileRotation.cs | 9 +++++ Tiles/IO/BGWorld21Format.cs | 73 +++++++++++++++++++++++++++++++++++++ Tiles/IO/BGWorld2Format.cs | 17 ++------- Tiles/IO/LvlFormat.cs | 17 +++++++-- Tiles/IO/WorldIO.cs | 13 +++++++ Tiles/World.cs | 12 ++++-- 9 files changed, 161 insertions(+), 34 deletions(-) create mode 100644 Tiles/Data/TileRotation.cs create mode 100644 Tiles/IO/BGWorld21Format.cs diff --git a/Player.cs b/Player.cs index a9c25d2..78b14c3 100644 --- a/Player.cs +++ b/Player.cs @@ -1,5 +1,6 @@ using System.Numerics; using BuildingGame.Tiles; +using BuildingGame.Tiles.Data; using BuildingGame.UI; using ZeroElectric.Vinculum; @@ -7,8 +8,8 @@ namespace BuildingGame; public class Player { - public static byte CurrentTile = 2; - + public static TileInfo CurrentTile = new TileInfo(1, TileFlags.Default); + public Camera2D Camera; public World World; public float Speed; @@ -18,17 +19,17 @@ public class Player private float _targetZoom; - public Player(World world, Vector2 position, float speed, float lerpSpeed) + public Player(World world, Vector2 position, float zoom, float speed, float lerpSpeed) { World = world; Camera = new Camera2D { offset = new Vector2(GetScreenWidth(), GetScreenHeight()) / 2, target = position, - zoom = 1.0f + zoom = zoom }; _targetPosition = position; - _targetZoom = 1.0f; + _targetZoom = zoom; Speed = speed; LerpSpeed = lerpSpeed; } @@ -105,9 +106,10 @@ public void Move(float x, float y) _targetPosition += new Vector2(x, y) * Speed * GetFrameTime(); } - public void PushCameraPosition() + public void PushCameraInfo() { World.PlayerPosition = Camera.target; + World.PlayerZoom = Camera.zoom; } public Rectangle GetViewRectangle() diff --git a/Program.cs b/Program.cs index 0c4c843..a486e6e 100644 --- a/Program.cs +++ b/Program.cs @@ -18,13 +18,17 @@ SetWindowIcon(icon); UnloadImage(icon); +BGWorld21Format.Register(); BGWorld2Format.Register(); LvlFormat.Register(); -World world = new World(256, 256); +WorldIO.AddDeserializerAsBackupable(new BGWorld2Format.Deserializer()); +WorldIO.AddDeserializerAsBackupable(new LvlFormat.Deserializer()); + +World world = new World(); world.Load(); -Player player = new Player(world, world.PlayerPosition, 50, 0.1f); +Player player = new Player(world, world.PlayerPosition, world.PlayerZoom, 50, 0.1f); BlockMenu menu = new BlockMenu(); GameHud hud = new GameHud(menu); @@ -57,7 +61,7 @@ UIInterfaceManager.Destroy(); -player.PushCameraPosition(); +player.PushCameraInfo(); world.Save(); Resources.Free(); diff --git a/Tiles/Data/TileFlags.cs b/Tiles/Data/TileFlags.cs index d406f17..2c91bb7 100644 --- a/Tiles/Data/TileFlags.cs +++ b/Tiles/Data/TileFlags.cs @@ -1,7 +1,31 @@ namespace BuildingGame.Tiles.Data; -// TODO: implement rotation enum instead of storing 32-bit floating point, because there are only 0, 90, 180, 270 degrees rotations available in-game -public record TileFlags(float Rotation, bool Flip) +public record TileFlags(TileRotation Rotation, bool Flip) { - public static TileFlags Default => new TileFlags(0, false); + public static TileFlags Default => new TileFlags(TileRotation.Up, false); + + public TileFlags(float rotation, bool flip) + : this(FloatAsRotation(rotation), flip) + { + } + + public float RotationAsFloat() + { + return Rotation switch + { + TileRotation.Up => 0, + TileRotation.Left => 90, + TileRotation.Down => 180, + TileRotation.Right => 270 + }; + } + + private static TileRotation FloatAsRotation(float rotation) + { + if (rotation is > 0 and <= 90) return TileRotation.Left; + if (rotation is > 90 and <= 180) return TileRotation.Down; + if (rotation is > 180 and <= 270) return TileRotation.Right; + + return TileRotation.Up; + } } \ No newline at end of file diff --git a/Tiles/Data/TileRotation.cs b/Tiles/Data/TileRotation.cs new file mode 100644 index 0000000..1324874 --- /dev/null +++ b/Tiles/Data/TileRotation.cs @@ -0,0 +1,9 @@ +namespace BuildingGame.Tiles.Data; + +public enum TileRotation : byte +{ + Up, + Left, + Down, + Right +} \ No newline at end of file diff --git a/Tiles/IO/BGWorld21Format.cs b/Tiles/IO/BGWorld21Format.cs new file mode 100644 index 0000000..2eb194d --- /dev/null +++ b/Tiles/IO/BGWorld21Format.cs @@ -0,0 +1,73 @@ +using System.Numerics; +using BuildingGame.Tiles.Data; + +namespace BuildingGame.Tiles.IO; + +public static class BGWorld21Format +{ + public const string Header = "BGWORLD21"; + + public class Serializer : IWorldSerializer + { + public string Header => BGWorld21Format.Header; + + public bool TrySerialize(BinaryWriter writer, World world, out string? log) + { + writer.Write(world.PlayerPosition.X); + writer.Write(world.PlayerPosition.Y); + writer.Write(world.PlayerZoom); + + for (int x = 0; x < world.Width; x++) + { + for (int y = 0; y < world.Height; y++) + { + PushTile(writer, world[x, y]); + } + } + + log = null; + return true; + } + } + + public class Deserializer : IWorldDeserializer + { + public string Header => BGWorld21Format.Header; + + public bool TryDeserialize(BinaryReader reader, out World world, out string? log) + { + world = new World(); + world.PlayerPosition = new Vector2(reader.ReadSingle(), reader.ReadSingle()); + world.PlayerZoom = reader.ReadSingle(); + + for (int x = 0; x < world.Width; x++) + { + for (int y = 0; y < world.Height; y++) + { + world[x, y] = PopTile(reader); + } + } + + log = null; + return true; + } + } + + public static void Register() + { + WorldIO.RegisterSerializer(new Serializer()); + WorldIO.RegisterDeserializer(new Deserializer()); + } + + private static void PushTile(BinaryWriter bw, TileInfo tile) + { + bw.Write(tile.Id); + bw.Write((byte)tile.Flags.Rotation); + bw.Write(tile.Flags.Flip); + } + + private static TileInfo PopTile(BinaryReader br) + { + return new TileInfo(br.ReadByte(), new TileFlags((TileRotation)br.ReadByte(), br.ReadBoolean())); + } +} \ No newline at end of file diff --git a/Tiles/IO/BGWorld2Format.cs b/Tiles/IO/BGWorld2Format.cs index dc919e8..4534147 100644 --- a/Tiles/IO/BGWorld2Format.cs +++ b/Tiles/IO/BGWorld2Format.cs @@ -24,19 +24,8 @@ public class Serializer : IWorldSerializer public bool TrySerialize(BinaryWriter writer, World world, out string? log) { - writer.Write(world.PlayerPosition.X); - writer.Write(world.PlayerPosition.Y); - - for (int x = 0; x < world.Width; x++) - { - for (int y = 0; y < world.Height; y++) - { - PushTile(writer, world[x, y]); - } - } - - log = null; - return true; + log = "Serialization as BGWORLD2 is not supported anymore"; + return false; } } @@ -71,7 +60,7 @@ public static void Register() private static void PushTile(BinaryWriter bw, TileInfo tile) { bw.Write(tile.Id); - bw.Write(tile.Flags.Rotation); + bw.Write(tile.Flags.RotationAsFloat()); bw.Write(tile.Flags.Flip); } diff --git a/Tiles/IO/LvlFormat.cs b/Tiles/IO/LvlFormat.cs index 5d124bd..bc9aa90 100644 --- a/Tiles/IO/LvlFormat.cs +++ b/Tiles/IO/LvlFormat.cs @@ -10,10 +10,10 @@ public static class LvlFormat public class Serializer : IWorldSerializer { public string Header => LvlFormat.Header; - + public bool TrySerialize(BinaryWriter writer, World world, out string? log) { - log = "PRE-ALPHA 0.1.0 LEVEL FORMAT IS CURRENTLY NOT SUPPORTED"; + log = "Serialization as LVL is not supported anymore"; return false; } } @@ -25,8 +25,17 @@ public class Deserializer : IWorldDeserializer public bool TryDeserialize(BinaryReader reader, out World world, out string? log) { world = new World(); - log = "PRE-ALPHA 0.1.0 LEVEL FORMAT IS CURRENTLY NOT SUPPORTED"; - return false; + + for (int x = 0; x < world.Width; x++) + { + for (int y = 0; y < world.Height; y++) + { + world[x, y] = reader.ReadByte(); + } + } + + log = null; + return true; } } diff --git a/Tiles/IO/WorldIO.cs b/Tiles/IO/WorldIO.cs index f1a997d..b27814c 100644 --- a/Tiles/IO/WorldIO.cs +++ b/Tiles/IO/WorldIO.cs @@ -8,6 +8,8 @@ public static class WorldIO private static List _deserializers = new List(); private static List _serializers = new List(); + private static List _backupDeserializers = new List(); + public static void RegisterDeserializer(T deserializer) where T : IWorldDeserializer { if (_deserializers.Find(m => m.GetType() == typeof(T)) != null) @@ -38,6 +40,11 @@ public static bool TryDeserializeWorld(string path, [NotNullWhen(true)] out Worl _deserializers.Find(d => string.Equals(d.Header, header, StringComparison.CurrentCultureIgnoreCase)) ?? throw new IOException("Unknown or corrupted world header: " + header); + if (_backupDeserializers.FindIndex(d => d.GetType() == deserializer.GetType()) >= 0) + { + File.Copy(path, path + ".old"); + } + if (deserializer.TryDeserialize(reader, out var outWorld, out var log)) { world = outWorld; @@ -82,4 +89,10 @@ public static bool TrySerializeWorld(string path, World world) wher return false; } } + + public static void AddDeserializerAsBackupable(TDeserializer deserializer) + where TDeserializer : IWorldDeserializer + { + _backupDeserializers.Add(deserializer); + } } \ No newline at end of file diff --git a/Tiles/World.cs b/Tiles/World.cs index 323816b..b8c439c 100644 --- a/Tiles/World.cs +++ b/Tiles/World.cs @@ -4,7 +4,7 @@ namespace BuildingGame.Tiles; -public struct World +public class World { public const int DefaultSize = 256; @@ -14,6 +14,7 @@ public struct World public readonly int ChunkHeight; public Vector2 PlayerPosition; + public float PlayerZoom; private Chunk[][] _chunks; @@ -77,20 +78,23 @@ public ChunkPosition WorldToChunk(int x, int y) public void Load() { if (!WorldIO.TryDeserializeWorld("level.dat", out var world)) return; - if (Width != world.Value.Width || Height != world.Value.Height) return; + if (Width != world.Width || Height != world.Height) return; + + PlayerPosition = world.PlayerPosition; + PlayerZoom = world.PlayerZoom; for (int x = 0; x < Width; x++) { for (int y = 0; y < Height; y++) { - this[x, y] = world.Value[x, y]; + this[x, y] = world[x, y]; } } } public void Save() { - WorldIO.TrySerializeWorld("level.dat", this); + WorldIO.TrySerializeWorld("level.dat", this); } public TileInfo this[int x, int y] From 3ed0be8cb4a1255151b66b2ab099960f189c84da Mon Sep 17 00:00:00 2001 From: danilwhale Date: Tue, 28 Nov 2023 17:14:28 +0200 Subject: [PATCH 026/107] little tile update --- Tiles/Chunk.cs | 2 +- Tiles/Tile.cs | 23 ++++------------------- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/Tiles/Chunk.cs b/Tiles/Chunk.cs index 7fdacc1..ba04fef 100644 --- a/Tiles/Chunk.cs +++ b/Tiles/Chunk.cs @@ -50,7 +50,7 @@ public void Draw() { byte tile = _tiles[x][y]; if (tile == 0) continue; - Tiles.GetTile(tile).Draw(World, tile, X * Size + x, Y * Size + y); + Tiles.GetTile(tile).Draw(World, tile, X * Size + x, Y * Size + y, WHITE); } } } diff --git a/Tiles/Tile.cs b/Tiles/Tile.cs index 8ce706e..7bbb8df 100644 --- a/Tiles/Tile.cs +++ b/Tiles/Tile.cs @@ -38,7 +38,7 @@ public virtual void Update(World world, TileInfo info, int x, int y) { } - public virtual void Draw(World world, TileInfo info, int x, int y) + public virtual void Draw(World world, TileInfo info, float x, float y, Color tint) { DrawTexturePro(Resources.GetTexture("Atlas.png"), // we add a fraction to the source rectangle, so we wont see flickering parts of atlas @@ -54,28 +54,13 @@ public virtual void Draw(World world, TileInfo info, int x, int y) Size.X * TileSize * TileUpscale, Size.Y * TileSize * TileUpscale ), - Vector2.Zero, 0, WHITE + Vector2.Zero, 0, tint ); } - public virtual void DrawPreview(float x, float y) + public virtual void DrawPreview(World world, TileInfo info, float x, float y) { - DrawTexturePro(Resources.GetTexture("Atlas.png"), - // we add a fraction to the source rectangle, so we wont see flickering parts of atlas - new Rectangle( - TexCoord.X * TileSize + AtlasFraction, - TexCoord.Y * TileSize + AtlasFraction, - TileSize - AtlasFraction, - TileSize - AtlasFraction - ), - new Rectangle( - x * TileSize * TileUpscale, - y * TileSize * TileUpscale, - TileSize * TileUpscale, - TileSize * TileUpscale - ), - Vector2.Zero, 0, new Color(255, 255, 255, 120) - ); + Draw(world, info, x, y, new Color(255, 255, 255, 120)); } public override bool Equals(object? obj) From 41b2078e759369f248f9f9f66e6c065ae94017a0 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Tue, 28 Nov 2023 17:24:41 +0200 Subject: [PATCH 027/107] make some records be structs --- Tiles/Data/TileFlags.cs | 14 ++++++++++++-- Tiles/Data/TileInfo.cs | 11 ++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Tiles/Data/TileFlags.cs b/Tiles/Data/TileFlags.cs index 2c91bb7..53de40d 100644 --- a/Tiles/Data/TileFlags.cs +++ b/Tiles/Data/TileFlags.cs @@ -1,12 +1,22 @@ namespace BuildingGame.Tiles.Data; -public record TileFlags(TileRotation Rotation, bool Flip) +public struct TileFlags { public static TileFlags Default => new TileFlags(TileRotation.Up, false); + public TileRotation Rotation; + public bool Flip; + + public TileFlags(TileRotation rotation, bool flip) + { + Rotation = rotation; + Flip = flip; + } + public TileFlags(float rotation, bool flip) - : this(FloatAsRotation(rotation), flip) { + Rotation = FloatAsRotation(rotation); + Flip = flip; } public float RotationAsFloat() diff --git a/Tiles/Data/TileInfo.cs b/Tiles/Data/TileInfo.cs index cafd7b6..dc85118 100644 --- a/Tiles/Data/TileInfo.cs +++ b/Tiles/Data/TileInfo.cs @@ -1,7 +1,16 @@ namespace BuildingGame.Tiles.Data; -public record TileInfo(byte Id, TileFlags Flags) +public struct TileInfo { + public byte Id; + public TileFlags Flags; + + public TileInfo(byte id, TileFlags flags) + { + Id = id; + Flags = flags; + } + public static implicit operator TileInfo(byte id) => new TileInfo(id, TileFlags.Default); public static implicit operator byte(TileInfo info) => info.Id; } \ No newline at end of file From 5319b5ac67590baf19e0895e841bc78809567207 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Tue, 28 Nov 2023 17:28:59 +0200 Subject: [PATCH 028/107] fix Chunk.Draw losing TileInfo --- Tiles/Chunk.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tiles/Chunk.cs b/Tiles/Chunk.cs index ba04fef..43218bf 100644 --- a/Tiles/Chunk.cs +++ b/Tiles/Chunk.cs @@ -48,7 +48,7 @@ public void Draw() { for (int y = 0; y < Size; y++) { - byte tile = _tiles[x][y]; + TileInfo tile = _tiles[x][y]; if (tile == 0) continue; Tiles.GetTile(tile).Draw(World, tile, X * Size + x, Y * Size + y, WHITE); } From 143589fa64c51d951495a69347ff7c08f8d30e94 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Tue, 28 Nov 2023 17:43:16 +0200 Subject: [PATCH 029/107] remove support for flip --- Tiles/Data/TileFlags.cs | 20 ++++++++++++++------ Tiles/IO/BGWorld21Format.cs | 3 +-- Tiles/IO/BGWorld2Format.cs | 7 +++++-- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Tiles/Data/TileFlags.cs b/Tiles/Data/TileFlags.cs index 53de40d..530df84 100644 --- a/Tiles/Data/TileFlags.cs +++ b/Tiles/Data/TileFlags.cs @@ -2,21 +2,18 @@ namespace BuildingGame.Tiles.Data; public struct TileFlags { - public static TileFlags Default => new TileFlags(TileRotation.Up, false); + public static TileFlags Default => new TileFlags(TileRotation.Up); public TileRotation Rotation; - public bool Flip; - public TileFlags(TileRotation rotation, bool flip) + public TileFlags(TileRotation rotation) { Rotation = rotation; - Flip = flip; } - public TileFlags(float rotation, bool flip) + public TileFlags(float rotation) { Rotation = FloatAsRotation(rotation); - Flip = flip; } public float RotationAsFloat() @@ -30,6 +27,17 @@ public float RotationAsFloat() }; } + public void FlipRotation() + { + Rotation = Rotation switch + { + TileRotation.Up => TileRotation.Down, + TileRotation.Down => TileRotation.Up, + TileRotation.Left => TileRotation.Right, + TileRotation.Right => TileRotation.Left + }; + } + private static TileRotation FloatAsRotation(float rotation) { if (rotation is > 0 and <= 90) return TileRotation.Left; diff --git a/Tiles/IO/BGWorld21Format.cs b/Tiles/IO/BGWorld21Format.cs index 2eb194d..16dd37f 100644 --- a/Tiles/IO/BGWorld21Format.cs +++ b/Tiles/IO/BGWorld21Format.cs @@ -63,11 +63,10 @@ private static void PushTile(BinaryWriter bw, TileInfo tile) { bw.Write(tile.Id); bw.Write((byte)tile.Flags.Rotation); - bw.Write(tile.Flags.Flip); } private static TileInfo PopTile(BinaryReader br) { - return new TileInfo(br.ReadByte(), new TileFlags((TileRotation)br.ReadByte(), br.ReadBoolean())); + return new TileInfo(br.ReadByte(), new TileFlags((TileRotation)br.ReadByte())); } } \ No newline at end of file diff --git a/Tiles/IO/BGWorld2Format.cs b/Tiles/IO/BGWorld2Format.cs index 4534147..42d2a6c 100644 --- a/Tiles/IO/BGWorld2Format.cs +++ b/Tiles/IO/BGWorld2Format.cs @@ -61,11 +61,14 @@ private static void PushTile(BinaryWriter bw, TileInfo tile) { bw.Write(tile.Id); bw.Write(tile.Flags.RotationAsFloat()); - bw.Write(tile.Flags.Flip); + bw.Write(false); // we dont know if tile is flipped } private static TileInfo PopTile(BinaryReader br) { - return new TileInfo(br.ReadByte(), new TileFlags(br.ReadSingle(), br.ReadBoolean())); + TileFlags flags = new TileFlags(br.ReadSingle()); + if (br.ReadBoolean()) flags.FlipRotation(); + + return new TileInfo(br.ReadByte(), flags); } } \ No newline at end of file From ae01c326093e06f2bdab25ee72270d055ad99f3f Mon Sep 17 00:00:00 2001 From: danilwhale Date: Tue, 28 Nov 2023 17:43:45 +0200 Subject: [PATCH 030/107] add tile rotation support --- Tiles/Tile.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tiles/Tile.cs b/Tiles/Tile.cs index 7bbb8df..cccfaab 100644 --- a/Tiles/Tile.cs +++ b/Tiles/Tile.cs @@ -54,7 +54,7 @@ public virtual void Draw(World world, TileInfo info, float x, float y, Color tin Size.X * TileSize * TileUpscale, Size.Y * TileSize * TileUpscale ), - Vector2.Zero, 0, tint + new Vector2(RealTileSize / 2), info.Flags.RotationAsFloat(), tint ); } From f9562d362f2bff48d8bfe6157f26baa655e5e528 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Tue, 28 Nov 2023 17:47:16 +0200 Subject: [PATCH 031/107] add tile preview and finish tile controls --- Player.cs | 36 ++++++++++++++++++++++++++++++------ Program.cs | 1 + 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/Player.cs b/Player.cs index 78b14c3..5fcbba2 100644 --- a/Player.cs +++ b/Player.cs @@ -17,7 +17,8 @@ public class Player private Vector2 _targetPosition; private float _targetZoom; - + private int _tileX; + private int _tileY; public Player(World world, Vector2 position, float zoom, float speed, float lerpSpeed) { @@ -66,21 +67,44 @@ public void Update() UpdateTileControls(); } + public void Draw() + { + if (!GuiManager.IsMouseOverElement()) + { + Tiles.Tiles.GetTile(CurrentTile.Id).DrawPreview( + World, CurrentTile, + _tileX, _tileY + ); + } + } + private void UpdateTileControls() { - Vector2 worldMousePos = GetScreenToWorld2D(GetMousePosition(), Camera); + Vector2 worldMousePos = GetScreenToWorld2D(GetMousePosition(), Camera) + new Vector2(Tile.RealTileSize / 2); - int tx = (int)(worldMousePos.X / Tile.RealTileSize); - int ty = (int)(worldMousePos.Y / Tile.RealTileSize); + _tileX = (int)(worldMousePos.X / Tile.RealTileSize); + _tileY = (int)(worldMousePos.Y / Tile.RealTileSize); if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_LEFT) && !GuiManager.IsMouseOverElement()) { - World[tx, ty] = CurrentTile; + World[_tileX, _tileY] = CurrentTile; } if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_RIGHT) && !GuiManager.IsMouseOverElement()) { - World[tx, ty] = 0; + World[_tileX, _tileY] = 0; + } + + if (IsKeyReleased(KeyboardKey.KEY_R)) + { + CurrentTile.Flags.Rotation = (TileRotation)(CurrentTile.Flags.Rotation + 1); + if ((int)CurrentTile.Flags.Rotation > (int)TileRotation.Right) + CurrentTile.Flags.Rotation = TileRotation.Up; + } + + if (IsKeyReleased(KeyboardKey.KEY_T)) + { + CurrentTile.Flags.FlipRotation(); } } diff --git a/Program.cs b/Program.cs index a486e6e..20a7de1 100644 --- a/Program.cs +++ b/Program.cs @@ -51,6 +51,7 @@ BeginMode2D(player.Camera); { world.Draw(player); + player.Draw(); } EndMode2D(); From 9380014a5552a86f18eb665cacb9eb7d5bd57025 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Tue, 28 Nov 2023 22:07:25 +0200 Subject: [PATCH 032/107] add auto extend to TextElement --- UI/Elements/TextElement.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/UI/Elements/TextElement.cs b/UI/Elements/TextElement.cs index 7699b9b..828f2b7 100644 --- a/UI/Elements/TextElement.cs +++ b/UI/Elements/TextElement.cs @@ -11,6 +11,7 @@ public class TextElement : Element public string Text = string.Empty; public float TextSize = 10; public Alignment TextAlignment = Alignment.TopLeft; + public bool AutoExtend = true; public float Padding = 0; @@ -21,8 +22,8 @@ public TextElement(string name) : base(name) protected override void Render() { Vector2 fontMeasure = MeasureTextEx(GuiManager.Font, Text, TextSize, TextSize / GuiManager.FontSize); - float width = Area.width - Padding - 1; - float height = Area.height - Padding - 1; + float width = (AutoExtend ? MathF.Max(Area.width, fontMeasure.X) : Area.width) - Padding - 1; + float height = (AutoExtend ? MathF.Max(Area.height, fontMeasure.Y) : Area.height) - Padding - 1; float xLeft = Padding + 4; float xRight = Area.width - fontMeasure.X - Padding * 2; From c9c767643c4655311d0202cb3521a2162c3f935c Mon Sep 17 00:00:00 2001 From: danilwhale Date: Tue, 28 Nov 2023 22:17:25 +0200 Subject: [PATCH 033/107] remove unused methods --- UI/Interfaces/UIInterface.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/UI/Interfaces/UIInterface.cs b/UI/Interfaces/UIInterface.cs index 000b626..03ac162 100644 --- a/UI/Interfaces/UIInterface.cs +++ b/UI/Interfaces/UIInterface.cs @@ -40,12 +40,6 @@ public UIInterface() UIInterfaceManager.Add(this); } - public void Reload() - { - Destroy(); - Initialize(); - } - public virtual void Initialize() { } public virtual void Configure() { } @@ -61,11 +55,6 @@ public virtual void Destroy() { DestroyElements(); } - - protected void SetRelativePosition(ref Element element, Vector2 position) - { - element.Position = Position + position; - } protected void DestroyElements() { From d331dc484728ed8c98b682af8df7a45f38c79097 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Wed, 29 Nov 2023 10:33:45 +0200 Subject: [PATCH 034/107] refactor Program --- Program.cs | 120 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 45 deletions(-) diff --git a/Program.cs b/Program.cs index 20a7de1..1e6982e 100644 --- a/Program.cs +++ b/Program.cs @@ -9,61 +9,91 @@ using BuildingGame.UI.Elements; using BuildingGame.UI.Interfaces; -SetConfigFlags(ConfigFlags.FLAG_VSYNC_HINT); -SetConfigFlags(ConfigFlags.FLAG_WINDOW_RESIZABLE); -InitWindow(1024, 768, "building game"); +internal class Program +{ + private static World _world; + private static Player _player; + private static BlockMenu _menu; + private static GameHud _hud; -// set window icon -Image icon = LoadImage("Assets/Icon.png"); -SetWindowIcon(icon); -UnloadImage(icon); + public static void Main(string[] args) + { + SetConfigFlags(ConfigFlags.FLAG_VSYNC_HINT); + SetConfigFlags(ConfigFlags.FLAG_WINDOW_RESIZABLE); + InitWindow(1024, 768, "building game"); -BGWorld21Format.Register(); -BGWorld2Format.Register(); -LvlFormat.Register(); + // set window icon + Image icon = LoadImage("Assets/Icon.png"); + SetWindowIcon(icon); + UnloadImage(icon); -WorldIO.AddDeserializerAsBackupable(new BGWorld2Format.Deserializer()); -WorldIO.AddDeserializerAsBackupable(new LvlFormat.Deserializer()); + Initialize(); -World world = new World(); -world.Load(); + while (!WindowShouldClose()) + { + Update(); + Draw(); + } -Player player = new Player(world, world.PlayerPosition, world.PlayerZoom, 50, 0.1f); + Closing(); + CloseWindow(); + } -BlockMenu menu = new BlockMenu(); -GameHud hud = new GameHud(menu); + private static void Initialize() + { + BGWorld21Format.Register(); + BGWorld2Format.Register(); + LvlFormat.Register(); -UIInterfaceManager.Initialize(); + WorldIO.AddDeserializerAsBackupable(new BGWorld2Format.Deserializer()); + WorldIO.AddDeserializerAsBackupable(new LvlFormat.Deserializer()); -while (!WindowShouldClose()) -{ - if (IsKeyPressed(KeyboardKey.KEY_R)) - Tiles.Reload(); - - player.Update(); - world.Update(); - GuiManager.Update(); - UIInterfaceManager.Update(); - - BeginDrawing(); - ClearBackground(SKYBLUE); - - BeginMode2D(player.Camera); + _world = new World(); + _world.Load(); + + _player = new Player(_world, _world.PlayerPosition, _world.PlayerZoom, 50, 0.1f); + + _menu = new BlockMenu(); + _hud = new GameHud(_menu); + + UIInterfaceManager.Initialize(); + } + + private static void Update() { - world.Draw(player); - player.Draw(); + if (IsKeyPressed(KeyboardKey.KEY_R)) + Tiles.Reload(); + + _player.Update(); + _world.Update(); + GuiManager.Update(); + UIInterfaceManager.Update(); } - EndMode2D(); - - GuiManager.Draw(); - - EndDrawing(); -} -UIInterfaceManager.Destroy(); + private static void Draw() + { + BeginDrawing(); + ClearBackground(SKYBLUE); + + BeginMode2D(_player.Camera); + { + _world.Draw(_player); + _player.Draw(); + } + EndMode2D(); -player.PushCameraInfo(); -world.Save(); + GuiManager.Draw(); -Resources.Free(); -CloseWindow(); \ No newline at end of file + EndDrawing(); + } + + private static void Closing() + { + UIInterfaceManager.Destroy(); + + _player.PushCameraInfo(); + _world.Save(); + + Resources.Free(); + } +} \ No newline at end of file From 90940590fd2c97522945e2c72393bc127ceed62f Mon Sep 17 00:00:00 2001 From: danilwhale Date: Wed, 29 Nov 2023 10:34:13 +0200 Subject: [PATCH 035/107] add GetTextSize to TextElement --- UI/Elements/TextElement.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/UI/Elements/TextElement.cs b/UI/Elements/TextElement.cs index 828f2b7..a860dbc 100644 --- a/UI/Elements/TextElement.cs +++ b/UI/Elements/TextElement.cs @@ -19,18 +19,23 @@ public TextElement(string name) : base(name) { } + public Vector2 GetTextSize() + { + return MeasureTextEx(GuiManager.Font, Text, TextSize, TextSize / GuiManager.FontSize); + } + protected override void Render() { - Vector2 fontMeasure = MeasureTextEx(GuiManager.Font, Text, TextSize, TextSize / GuiManager.FontSize); - float width = (AutoExtend ? MathF.Max(Area.width, fontMeasure.X) : Area.width) - Padding - 1; - float height = (AutoExtend ? MathF.Max(Area.height, fontMeasure.Y) : Area.height) - Padding - 1; + Vector2 textSize = GetTextSize(); + float width = (AutoExtend ? MathF.Max(Area.width, textSize.X) : Area.width) - Padding - 1; + float height = (AutoExtend ? MathF.Max(Area.height, textSize.Y) : Area.height) - Padding - 1; float xLeft = Padding + 4; - float xRight = Area.width - fontMeasure.X - Padding * 2; - float xCenter = Area.width / 2 - fontMeasure.X / 2; + float xRight = Area.width - textSize.X - Padding * 2; + float xCenter = Area.width / 2 - textSize.X / 2; float yTop = Padding + 4; - float yBottom = Area.height - fontMeasure.Y - Padding * 2; - float yCenter = Area.height / 2 - fontMeasure.Y / 2; + float yBottom = Area.height - textSize.Y - Padding * 2; + float yCenter = Area.height / 2 - textSize.Y / 2; Vector2 xy = TextAlignment switch { From fedca7a249dff1aaa7b9afbd7e7992d3ee4588b8 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Wed, 29 Nov 2023 10:41:47 +0200 Subject: [PATCH 036/107] resize interface even if it's inactive --- UI/Interfaces/UIInterface.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/Interfaces/UIInterface.cs b/UI/Interfaces/UIInterface.cs index 03ac162..1e5c52d 100644 --- a/UI/Interfaces/UIInterface.cs +++ b/UI/Interfaces/UIInterface.cs @@ -46,8 +46,8 @@ public virtual void Configure() { } public virtual void Update() { - if (!_active) return; if (IsWindowResized()) Resized(); + if (!_active) return; } public virtual void Resized() { } From 08f1f3bee01ec563e3d233c691f875dd8f3d7a40 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Wed, 29 Nov 2023 10:48:53 +0200 Subject: [PATCH 037/107] refactor interfaces' element names --- UI/Interfaces/BlockMenu.cs | 6 +++--- UI/Interfaces/GameHud.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/UI/Interfaces/BlockMenu.cs b/UI/Interfaces/BlockMenu.cs index a392b1a..d0e199a 100644 --- a/UI/Interfaces/BlockMenu.cs +++ b/UI/Interfaces/BlockMenu.cs @@ -15,14 +15,14 @@ public override void Initialize() { base.Initialize(); - _background = new Panel("blockMenuBackground") + _background = new Panel("blockMenu::background") { Brush = new GradientBrush(new Color(0, 0, 25, 100), new Color(0, 0, 0, 200)), ZIndex = 10 }; Elements.Add(_background); - _menuTitle = new TextElement("blockMenuTitle") + _menuTitle = new TextElement("blockMenu::title") { Text = "Select a tile", TextColor = WHITE, @@ -48,7 +48,7 @@ public override void Initialize() float ratio = aspectX < aspectY ? aspectX : aspectY; - _tileButtons[i] = new Button("tile_" + i) + _tileButtons[i] = new Button("blockMenu::tile_" + i) { Size = new Vector2(1) * Tile.RealTileSize, BackgroundBrush = new TextureBrush(Resources.GetTexture("Atlas.png")) diff --git a/UI/Interfaces/GameHud.cs b/UI/Interfaces/GameHud.cs index dab3d9b..3d8d3b8 100644 --- a/UI/Interfaces/GameHud.cs +++ b/UI/Interfaces/GameHud.cs @@ -22,7 +22,7 @@ public override void Initialize() { base.Initialize(); - _tileMenuButton = new Button("tileMenuButton") + _tileMenuButton = new Button("gameHud::tileMenuButton") { BackgroundBrush = new TextureBrush(Resources.GetTexture("Atlas.png")) { From 69e716e43fa15593ac7a3af27ae9d23b5afa08cd Mon Sep 17 00:00:00 2001 From: danilwhale Date: Wed, 29 Nov 2023 10:51:55 +0200 Subject: [PATCH 038/107] extend ZIndex to short (-32768 <=> 32767) --- UI/Element.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/Element.cs b/UI/Element.cs index fd068fb..7fec2d9 100644 --- a/UI/Element.cs +++ b/UI/Element.cs @@ -31,7 +31,7 @@ public Vector2 Size } public string Name; - public byte ZIndex; + public short ZIndex; public bool Active = true; public bool Visible = true; From 933e0e6c1df0261f15d4891346ad80aabf1dae72 Mon Sep 17 00:00:00 2001 From: danilwhale Date: Wed, 29 Nov 2023 11:46:34 +0200 Subject: [PATCH 039/107] fix zindex sorting --- UI/GuiManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/GuiManager.cs b/UI/GuiManager.cs index a898515..8aac9ec 100644 --- a/UI/GuiManager.cs +++ b/UI/GuiManager.cs @@ -77,7 +77,7 @@ public static void Update() public static void Draw() { var elements = _elements; - elements.Sort((e1, e2) => e1.ZIndex.CompareTo(e1.ZIndex)); + elements.Sort((e1, e2) => e1.ZIndex.CompareTo(e2.ZIndex)); foreach (var el in elements) { if (!el.Active) continue; From 891a21726fb7d91a5809d2bbb32382c103af2e2a Mon Sep 17 00:00:00 2001 From: danilwhale Date: Wed, 29 Nov 2023 12:59:35 +0200 Subject: [PATCH 040/107] add pause --- Program.cs | 17 +++-- UI/Element.cs | 2 + UI/GuiManager.cs | 1 + UI/Interfaces/PauseScreen.cs | 103 ++++++++++++++++++++++++++++ UI/Interfaces/UIInterface.cs | 3 + UI/Interfaces/UIInterfaceManager.cs | 6 +- 6 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 UI/Interfaces/PauseScreen.cs diff --git a/Program.cs b/Program.cs index 1e6982e..6c41aec 100644 --- a/Program.cs +++ b/Program.cs @@ -11,16 +11,20 @@ internal class Program { + public static bool Paused = false; + private static World _world; private static Player _player; private static BlockMenu _menu; private static GameHud _hud; + private static PauseScreen _pause; public static void Main(string[] args) { SetConfigFlags(ConfigFlags.FLAG_VSYNC_HINT); SetConfigFlags(ConfigFlags.FLAG_WINDOW_RESIZABLE); InitWindow(1024, 768, "building game"); + SetExitKey(KeyboardKey.KEY_NULL); // set window icon Image icon = LoadImage("Assets/Icon.png"); @@ -55,17 +59,22 @@ private static void Initialize() _menu = new BlockMenu(); _hud = new GameHud(_menu); + _pause = new PauseScreen(); UIInterfaceManager.Initialize(); } private static void Update() { - if (IsKeyPressed(KeyboardKey.KEY_R)) - Tiles.Reload(); + if (!Paused) + { + if (IsKeyPressed(KeyboardKey.KEY_R)) + Tiles.Reload(); - _player.Update(); - _world.Update(); + _player.Update(); + _world.Update(); + } + GuiManager.Update(); UIInterfaceManager.Update(); } diff --git a/UI/Element.cs b/UI/Element.cs index 7fec2d9..cec0631 100644 --- a/UI/Element.cs +++ b/UI/Element.cs @@ -40,6 +40,8 @@ public Vector2 Size public float Rotation = 0; public string TooltipText = string.Empty; + public bool IgnorePause = false; + private RenderTexture _controlTexture; public Element(string name) diff --git a/UI/GuiManager.cs b/UI/GuiManager.cs index 8aac9ec..f5d7db4 100644 --- a/UI/GuiManager.cs +++ b/UI/GuiManager.cs @@ -69,6 +69,7 @@ public static void Update() foreach (var el in elements) { + if (!el.IgnorePause && Program.Paused) continue; if (!el.Active) continue; el.Update(); } diff --git a/UI/Interfaces/PauseScreen.cs b/UI/Interfaces/PauseScreen.cs new file mode 100644 index 0000000..c1ea0f1 --- /dev/null +++ b/UI/Interfaces/PauseScreen.cs @@ -0,0 +1,103 @@ +using System.Numerics; +using BuildingGame.UI.Brushes; +using BuildingGame.UI.Elements; + +namespace BuildingGame.UI.Interfaces; + +public class PauseScreen : UIInterface +{ + private Panel _background; + private Button _resumeButton; + private Button _menuButton; + private Button _settingsButton; + + public PauseScreen() + { + IgnorePause = true; + } + + public override void Initialize() + { + base.Initialize(); + + _background = new Panel("pauseScreen::background") + { + Brush = new GradientBrush(BLANK, BLACK), + IgnorePause = true, + ZIndex = -1 + }; + Elements.Add(_background); + + _resumeButton = new Button("pauseScreen::resumeButton") + { + Text = "resume", + TextSize = 24, + TextAlignment = Alignment.CenterLeft, + IgnorePause = true + }; + _resumeButton.OnClick += () => + { + Visible = false; + Program.Paused = false; + }; + Elements.Add(_resumeButton); + + _settingsButton = new Button("pauseScreen::settingsButton") + { + Text = "settings", + TextSize = 24, + TextAlignment = Alignment.CenterLeft, + IgnorePause = true + }; + Elements.Add(_settingsButton); + + _menuButton = new Button("pauseScreen::menuButton") + { + Text = "menu", + TextSize = 24, + TextAlignment = Alignment.CenterLeft, + IgnorePause = true + }; + Elements.Add(_menuButton); + + Configure(); + Visible = false; + } + + public override void Configure() + { + base.Configure(); + + _background.Area = new Rectangle(-1, -1, GetScreenWidth() + 2, GetScreenHeight() + 2); + + float buttonsOriginX = 16; + float buttonsOriginY = GetScreenHeight() / 2 - _resumeButton.TextSize; + + _resumeButton.Area = new Rectangle(buttonsOriginX, buttonsOriginY, 148, 24); + _settingsButton.Area = new Rectangle( + buttonsOriginX, _resumeButton.Position.Y + _resumeButton.TextSize + 16, + 148, 24 + ); + _menuButton.Area = new Rectangle( + buttonsOriginX, _settingsButton.Position.Y + _settingsButton.TextSize + 16, + 148, 24); + } + + public override void Resized() + { + base.Resized(); + + Configure(); + } + + public override void Update() + { + base.Update(); + + if (IsKeyReleased(KeyboardKey.KEY_ESCAPE)) + { + Visible = !Visible; + Program.Paused = !Program.Paused; + } + } +} \ No newline at end of file diff --git a/UI/Interfaces/UIInterface.cs b/UI/Interfaces/UIInterface.cs index 1e5c52d..43a082c 100644 --- a/UI/Interfaces/UIInterface.cs +++ b/UI/Interfaces/UIInterface.cs @@ -30,8 +30,11 @@ public bool Active } } + public bool CanIgnorePause => IgnorePause; + protected List Elements = new List(); protected Vector2 Position; + protected bool IgnorePause; private bool _visible = true; private bool _active = true; diff --git a/UI/Interfaces/UIInterfaceManager.cs b/UI/Interfaces/UIInterfaceManager.cs index 1e1361e..99dd075 100644 --- a/UI/Interfaces/UIInterfaceManager.cs +++ b/UI/Interfaces/UIInterfaceManager.cs @@ -22,7 +22,11 @@ public static void Initialize() public static void Update() { - foreach (var i in _interfaces) i.Update(); + foreach (var i in _interfaces) + { + if (!i.CanIgnorePause && Program.Paused) continue; + i.Update(); + } } public static void Destroy() From 4d5cda4036750554051db0edde519f6d76979be8 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 16:43:01 +0200 Subject: [PATCH 041/107] implement screens --- Program.cs | 44 +++---------------- UI/ElementComparer.cs | 13 ++++++ UI/GuiManager.cs | 74 ++++++++++++-------------------- UI/Interfaces/BlockMenu.cs | 2 +- UI/Interfaces/PauseScreen.cs | 11 +++-- UI/Screens/GameScreen.cs | 65 ++++++++++++++++++++++++++++ UI/Screens/Screen.cs | 82 ++++++++++++++++++++++++++++++++++++ UI/Screens/ScreenManager.cs | 28 ++++++++++++ 8 files changed, 231 insertions(+), 88 deletions(-) create mode 100644 UI/ElementComparer.cs create mode 100644 UI/Screens/GameScreen.cs create mode 100644 UI/Screens/Screen.cs create mode 100644 UI/Screens/ScreenManager.cs diff --git a/Program.cs b/Program.cs index 6c41aec..f30d727 100644 --- a/Program.cs +++ b/Program.cs @@ -8,17 +8,12 @@ using BuildingGame.UI.Brushes; using BuildingGame.UI.Elements; using BuildingGame.UI.Interfaces; +using BuildingGame.UI.Screens; internal class Program { public static bool Paused = false; - private static World _world; - private static Player _player; - private static BlockMenu _menu; - private static GameHud _hud; - private static PauseScreen _pause; - public static void Main(string[] args) { SetConfigFlags(ConfigFlags.FLAG_VSYNC_HINT); @@ -52,57 +47,32 @@ private static void Initialize() WorldIO.AddDeserializerAsBackupable(new BGWorld2Format.Deserializer()); WorldIO.AddDeserializerAsBackupable(new LvlFormat.Deserializer()); - _world = new World(); - _world.Load(); - - _player = new Player(_world, _world.PlayerPosition, _world.PlayerZoom, 50, 0.1f); - - _menu = new BlockMenu(); - _hud = new GameHud(_menu); - _pause = new PauseScreen(); - + ScreenManager.CurrentScreen = new GameScreen(); + + ScreenManager.Initialize(); UIInterfaceManager.Initialize(); } private static void Update() { - if (!Paused) - { - if (IsKeyPressed(KeyboardKey.KEY_R)) - Tiles.Reload(); - - _player.Update(); - _world.Update(); - } - - GuiManager.Update(); + ScreenManager.Update(); UIInterfaceManager.Update(); } private static void Draw() { BeginDrawing(); - ClearBackground(SKYBLUE); - - BeginMode2D(_player.Camera); - { - _world.Draw(_player); - _player.Draw(); - } - EndMode2D(); - GuiManager.Draw(); + ScreenManager.Draw(); EndDrawing(); } private static void Closing() { + ScreenManager.Free(); UIInterfaceManager.Destroy(); - _player.PushCameraInfo(); - _world.Save(); - Resources.Free(); } } \ No newline at end of file diff --git a/UI/ElementComparer.cs b/UI/ElementComparer.cs new file mode 100644 index 0000000..f89306a --- /dev/null +++ b/UI/ElementComparer.cs @@ -0,0 +1,13 @@ +namespace BuildingGame.UI; + +public class ElementComparer : IComparer +{ + public int Compare(Element? x, Element? y) + { + if (x == null && y == null) return 0; + if (x == null) return -1; + if (y == null) return 1; + + return x.ZIndex.CompareTo(y.ZIndex); + } +} \ No newline at end of file diff --git a/UI/GuiManager.cs b/UI/GuiManager.cs index f5d7db4..881dc85 100644 --- a/UI/GuiManager.cs +++ b/UI/GuiManager.cs @@ -1,9 +1,9 @@ +using BuildingGame.UI.Screens; + namespace BuildingGame.UI; public static class GuiManager { - private static List _elements = new List(); - public static bool IsFocused = false; public static readonly Font Font = GetFontDefault(); @@ -11,79 +11,61 @@ public static class GuiManager public static void Add(Element element) { - _elements.Add(element); + ScreenManager.CurrentScreen?.Elements.Add(element); } public static void Remove(Element element) { - _elements.Remove(element); + ScreenManager.CurrentScreen?.Elements.Remove(element); } public static void Remove(string name) { - int index = _elements.FindIndex(e => string.Equals(e.Name, name, StringComparison.CurrentCultureIgnoreCase)); + if (ScreenManager.CurrentScreen == null) return; + + int index = ScreenManager.CurrentScreen.Elements.FindIndex(e => string.Equals(e.Name, name, StringComparison.CurrentCultureIgnoreCase)); if (index < 0) return; - _elements.RemoveAt(index); + ScreenManager.CurrentScreen.Elements.RemoveAt(index); } public static Element? Get(string name) { - int index = _elements.FindIndex(e => string.Equals(e.Name, name, StringComparison.CurrentCultureIgnoreCase)); + if (ScreenManager.CurrentScreen == null) return null; + + int index = ScreenManager.CurrentScreen.Elements.FindIndex(e => string.Equals(e.Name, name, StringComparison.CurrentCultureIgnoreCase)); if (index < 0) return null; - return _elements[index]; + return ScreenManager.CurrentScreen.Elements[index]; } public static TElement? GetAs(string name) where TElement : Element { - int index = _elements.FindIndex(e => + if (ScreenManager.CurrentScreen == null) return default; + + int index = ScreenManager.CurrentScreen.Elements.FindIndex(e => e.GetType() == typeof(TElement) && string.Equals(e.Name, name, StringComparison.CurrentCultureIgnoreCase)); - if (index < 0) return null; - return _elements[index] as TElement; + if (index < 0) return default; + return ScreenManager.CurrentScreen.Elements[index] as TElement; } public static bool IsMouseOverElement() { - var elements = _elements; - foreach (var el in elements) - { - if (el.Active && el.Visible && el.IsHovered()) return true; - } + if (ScreenManager.CurrentScreen == null) return false; - return false; + var elements = ScreenManager.CurrentScreen.ElementsSorted; + return elements.Any(element => element.Visible && element.Active && element.IsHovered()); } public static Element? GetElementUnderMouse() { - var elements = _elements; - foreach (var el in elements) - { - if (el.IsHovered()) return el; - } + if (ScreenManager.CurrentScreen == null) return null; - return null; + var elements = ScreenManager.CurrentScreen.ElementsSorted; + return elements.FirstOrDefault(el => el.IsHovered()); } - public static void Update() - { - var elements = _elements; - - foreach (var el in elements) - { - if (!el.IgnorePause && Program.Paused) continue; - if (!el.Active) continue; - el.Update(); - } - } - - public static void Draw() - { - var elements = _elements; - elements.Sort((e1, e2) => e1.ZIndex.CompareTo(e2.ZIndex)); - foreach (var el in elements) - { - if (!el.Active) continue; - if (!el.Visible) continue; - el.Draw(); - } - } + [Obsolete("Use ScreenManager.Draw instead")] + public static void Draw() { } + + [Obsolete("Use ScreenManager.Update instead")] + public static void Update() { } } \ No newline at end of file diff --git a/UI/Interfaces/BlockMenu.cs b/UI/Interfaces/BlockMenu.cs index d0e199a..5ff24dd 100644 --- a/UI/Interfaces/BlockMenu.cs +++ b/UI/Interfaces/BlockMenu.cs @@ -18,7 +18,7 @@ public override void Initialize() _background = new Panel("blockMenu::background") { Brush = new GradientBrush(new Color(0, 0, 25, 100), new Color(0, 0, 0, 200)), - ZIndex = 10 + ZIndex = -1 }; Elements.Add(_background); diff --git a/UI/Interfaces/PauseScreen.cs b/UI/Interfaces/PauseScreen.cs index c1ea0f1..87307e0 100644 --- a/UI/Interfaces/PauseScreen.cs +++ b/UI/Interfaces/PauseScreen.cs @@ -24,7 +24,7 @@ public override void Initialize() { Brush = new GradientBrush(BLANK, BLACK), IgnorePause = true, - ZIndex = -1 + ZIndex = 100 }; Elements.Add(_background); @@ -33,7 +33,8 @@ public override void Initialize() Text = "resume", TextSize = 24, TextAlignment = Alignment.CenterLeft, - IgnorePause = true + IgnorePause = true, + ZIndex = 101 }; _resumeButton.OnClick += () => { @@ -47,7 +48,8 @@ public override void Initialize() Text = "settings", TextSize = 24, TextAlignment = Alignment.CenterLeft, - IgnorePause = true + IgnorePause = true, + ZIndex = 101 }; Elements.Add(_settingsButton); @@ -56,7 +58,8 @@ public override void Initialize() Text = "menu", TextSize = 24, TextAlignment = Alignment.CenterLeft, - IgnorePause = true + IgnorePause = true, + ZIndex = 101 }; Elements.Add(_menuButton); diff --git a/UI/Screens/GameScreen.cs b/UI/Screens/GameScreen.cs new file mode 100644 index 0000000..f139fee --- /dev/null +++ b/UI/Screens/GameScreen.cs @@ -0,0 +1,65 @@ +using BuildingGame.Tiles; +using BuildingGame.UI.Interfaces; + +namespace BuildingGame.UI.Screens; + +public class GameScreen : Screen +{ + private World _world; + private Player _player; + private BlockMenu _menu; + private GameHud _hud; + private PauseScreen _pause; + + public override void Initialize() + { + base.Initialize(); + + _world = new World(); + _world.Load(); + + _player = new Player(_world, _world.PlayerPosition, _world.PlayerZoom, 50, 0.1f); + + _menu = new BlockMenu(); + _hud = new GameHud(_menu); + _pause = new PauseScreen(); + } + + public override void Update() + { + base.Update(); + + if (IsKeyPressed(KeyboardKey.KEY_R)) + Tiles.Tiles.Reload(); + + if (!Program.Paused) + { + _player.Update(); + _world.Update(); + } + } + + public override void Draw() + { + ClearBackground(SKYBLUE); + + BeginMode2D(_player.Camera); + { + _world.Draw(_player); + _player.Draw(); + } + EndMode2D(); + + base.Draw(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (!disposing) return; + + _player.PushCameraInfo(); + _world.Save(); + } +} \ No newline at end of file diff --git a/UI/Screens/Screen.cs b/UI/Screens/Screen.cs new file mode 100644 index 0000000..b95eb3d --- /dev/null +++ b/UI/Screens/Screen.cs @@ -0,0 +1,82 @@ +using BuildingGame.UI.Interfaces; + +namespace BuildingGame.UI.Screens; + +public class Screen : IDisposable +{ + public static readonly ElementComparer Comparer = new ElementComparer(); + + public bool IsCurrent + { + get => ReferenceEquals(this, ScreenManager.CurrentScreen); + set => ScreenManager.CurrentScreen = this; + } + + public List Elements = new List(); + public IOrderedEnumerable ElementsSorted => Elements.OrderBy(e => e, Comparer); + + public List Interfaces = new List(); + + public virtual void Initialize() + { + + } + + public virtual void Update() + { + for (int i = 0; i < Elements.Count; i++) + { + // handle list modifying + if (i >= Elements.Count) break; + + var element = Elements[i]; + if (!element.Active) continue; + + element.Update(); + } + + for (int i = 0; i < Interfaces.Count; i++) + { + // handle list modifying + if (i >= Interfaces.Count) break; + + Interfaces[i].Update(); + } + } + + public virtual void Draw() + { + foreach (var el in ElementsSorted) + { + if (!el.Active || !el.Visible) continue; + el.Draw(); + } + } + + protected virtual void Dispose(bool disposing) + { + + } + + public void Dispose() + { + for (int i = 0; i < Elements.Count; i++) + { + // handle list modifying + if (i >= Elements.Count) break; + + Elements[i].Dispose(); + } + + for (int i = 0; i < Interfaces.Count; i++) + { + // handle list modifying + if (i >= Interfaces.Count) break; + + Interfaces[i].Destroy(); + } + + Dispose(true); + GC.SuppressFinalize(this); + } +} \ No newline at end of file diff --git a/UI/Screens/ScreenManager.cs b/UI/Screens/ScreenManager.cs new file mode 100644 index 0000000..d29c627 --- /dev/null +++ b/UI/Screens/ScreenManager.cs @@ -0,0 +1,28 @@ +namespace BuildingGame.UI.Screens; + +public static class ScreenManager +{ + public static Screen? CurrentScreen; + + public static void Initialize() + { + CurrentScreen?.Initialize(); + } + + public static void Update() + { + CurrentScreen?.Update(); + } + + public static void Draw() + { + CurrentScreen?.Draw(); + } + + public static void Free() + { + CurrentScreen?.Dispose(); + CurrentScreen = null; + } + +} \ No newline at end of file From 7b825dc6c8053b04d3558bac972d3bc3af700930 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 17:36:25 +0200 Subject: [PATCH 042/107] move to raylib-cs :D --- BuildingGame.csproj | 3 ++- Player.cs | 19 ++++++++--------- Program.cs | 9 ++++++-- Raylib.ExtraMethods.cs | 29 ++++++++++++++++++++++++++ Resources.cs | 4 ++-- Tiles/Chunk.cs | 2 +- UI/Brushes/GradientBrush.cs | 8 ++++---- UI/Brushes/SolidBrush.cs | 2 +- UI/Brushes/TextureBrush.cs | 8 ++++---- UI/Element.cs | 40 ++++++++++++++++++------------------ UI/Elements/CheckBox.cs | 10 ++++----- UI/Elements/ListBox.cs | 11 +++++----- UI/Elements/Panel.cs | 2 +- UI/Elements/TextBox.cs | 10 +++++---- UI/Elements/TextElement.cs | 14 ++++++------- UI/Interfaces/BlockMenu.cs | 2 +- UI/Interfaces/GameHud.cs | 2 +- UI/Interfaces/PauseScreen.cs | 2 +- UI/Screens/GameScreen.cs | 2 +- 19 files changed, 108 insertions(+), 71 deletions(-) create mode 100644 Raylib.ExtraMethods.cs diff --git a/BuildingGame.csproj b/BuildingGame.csproj index 34f4834..9fb64f2 100644 --- a/BuildingGame.csproj +++ b/BuildingGame.csproj @@ -6,6 +6,7 @@ enable enable assets/icon.ico + true @@ -26,7 +27,7 @@ - + diff --git a/Player.cs b/Player.cs index 5fcbba2..b4fae45 100644 --- a/Player.cs +++ b/Player.cs @@ -2,7 +2,6 @@ using BuildingGame.Tiles; using BuildingGame.Tiles.Data; using BuildingGame.UI; -using ZeroElectric.Vinculum; namespace BuildingGame; @@ -25,9 +24,9 @@ public Player(World world, Vector2 position, float zoom, float speed, float lerp World = world; Camera = new Camera2D { - offset = new Vector2(GetScreenWidth(), GetScreenHeight()) / 2, - target = position, - zoom = zoom + Offset = new Vector2(GetScreenWidth(), GetScreenHeight()) / 2, + Target = position, + Zoom = zoom }; _targetPosition = position; _targetZoom = zoom; @@ -37,8 +36,8 @@ public Player(World world, Vector2 position, float zoom, float speed, float lerp public void Update() { - Camera.target = Vector2.Lerp(Camera.target, _targetPosition, LerpSpeed); // lerp camera position to target position - Camera.zoom = (Camera.zoom * (1.0f - LerpSpeed)) + (_targetZoom * LerpSpeed); // lerp camera zoom to target zoom + Camera.Target = Vector2.Lerp(Camera.Target, _targetPosition, LerpSpeed); // lerp camera position to target position + Camera.Zoom = (Camera.Zoom * (1.0f - LerpSpeed)) + (_targetZoom * LerpSpeed); // lerp camera zoom to target zoom // zoom in/zoom out camera float scrollDelta = GetMouseWheelMove() * (GuiManager.IsMouseOverElement() ? 0 : 1); @@ -49,7 +48,7 @@ public void Update() float speed = IsKeyDown(KeyboardKey.KEY_LEFT_CONTROL) || IsKeyDown(KeyboardKey.KEY_LEFT_SHIFT) ? Speed * 1.25f : Speed * 0.5f; - speed /= Camera.zoom; + speed /= Camera.Zoom; speed = Math.Clamp(speed, 0, Speed * 2); // move camera @@ -61,7 +60,7 @@ public void Update() // adapt camera center when windows is resized if (IsWindowResized()) { - Camera.offset = new Vector2(GetScreenWidth(), GetScreenHeight()) / 2; + Camera.Offset = new Vector2(GetScreenWidth(), GetScreenHeight()) / 2; } UpdateTileControls(); @@ -132,8 +131,8 @@ public void Move(float x, float y) public void PushCameraInfo() { - World.PlayerPosition = Camera.target; - World.PlayerZoom = Camera.zoom; + World.PlayerPosition = Camera.Target; + World.PlayerZoom = Camera.Zoom; } public Rectangle GetViewRectangle() diff --git a/Program.cs b/Program.cs index f30d727..f51d4cf 100644 --- a/Program.cs +++ b/Program.cs @@ -1,6 +1,8 @@ -global using static ZeroElectric.Vinculum.Raylib; -global using ZeroElectric.Vinculum; +global using static Raylib_cs.Raylib; +global using static BuildingGame.Raylib; +global using Raylib_cs; using System.Numerics; +using System.Runtime.CompilerServices; using BuildingGame; using BuildingGame.Tiles; using BuildingGame.Tiles.IO; @@ -10,6 +12,9 @@ using BuildingGame.UI.Interfaces; using BuildingGame.UI.Screens; +// remove this when raylib-cs will have rl 5.0 functions +[assembly: DisableRuntimeMarshalling] + internal class Program { public static bool Paused = false; diff --git a/Raylib.ExtraMethods.cs b/Raylib.ExtraMethods.cs new file mode 100644 index 0000000..31737a0 --- /dev/null +++ b/Raylib.ExtraMethods.cs @@ -0,0 +1,29 @@ +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace BuildingGame; + + +/// +/// contains some extra methods to simplify transition from raylib-csharp-vinculum +/// +public static partial class Raylib +{ + [LibraryImport(NativeLibName, EntryPoint = "IsKeyPressedRepeat")] + public static partial CBool IsKeyPressedRepeat(KeyboardKey key); + + // https://github.com/raysan5/raylib/blob/d2b1256e5c3567484486ad70cc2bb69495abfbf4/src/rtext.c#L1108 + public static void DrawText(string text, float posX, float posY, float fontSize, Color color) + { + if (GetFontDefault().Texture.Id == 0) return; + + var pos = new Vector2(posX, posY); + + var defaultFontSize = 10.0f; + if (fontSize < defaultFontSize) fontSize = defaultFontSize; + var spacing = fontSize / defaultFontSize; + + DrawTextEx(GetFontDefault(), text, pos, fontSize, spacing, color); + } +} \ No newline at end of file diff --git a/Resources.cs b/Resources.cs index 425adc9..34db0c6 100644 --- a/Resources.cs +++ b/Resources.cs @@ -2,9 +2,9 @@ namespace BuildingGame; public static class Resources { - private static Dictionary _textures = new Dictionary(); + private static Dictionary _textures = new Dictionary(); - public static Texture GetTexture(string key) + public static Texture2D GetTexture(string key) { key = key.ToLower(); if (_textures.TryGetValue(key, out var texture)) return texture; diff --git a/Tiles/Chunk.cs b/Tiles/Chunk.cs index 43218bf..1a20b4e 100644 --- a/Tiles/Chunk.cs +++ b/Tiles/Chunk.cs @@ -50,7 +50,7 @@ public void Draw() { TileInfo tile = _tiles[x][y]; if (tile == 0) continue; - Tiles.GetTile(tile).Draw(World, tile, X * Size + x, Y * Size + y, WHITE); + Tiles.GetTile(tile).Draw(World, tile, X * Size + x, Y * Size + y, Color.WHITE); } } } diff --git a/UI/Brushes/GradientBrush.cs b/UI/Brushes/GradientBrush.cs index 1076ebc..45ec146 100644 --- a/UI/Brushes/GradientBrush.cs +++ b/UI/Brushes/GradientBrush.cs @@ -15,10 +15,10 @@ public GradientBrush(Color colorA, Color colorB, GradientDirection direction = G public void FillArea(Rectangle area) { - int x = (int)area.x; - int y = (int)area.y; - int width = (int)area.width; - int height = (int)area.height; + int x = (int)area.X; + int y = (int)area.Y; + int width = (int)area.Width; + int height = (int)area.Height; switch (Direction) { diff --git a/UI/Brushes/SolidBrush.cs b/UI/Brushes/SolidBrush.cs index a8632f3..05a8f19 100644 --- a/UI/Brushes/SolidBrush.cs +++ b/UI/Brushes/SolidBrush.cs @@ -11,7 +11,7 @@ public SolidBrush(Color color) public void FillArea(Rectangle area) { - RlGl.rlSetBlendMode(0); + Rlgl.SetBlendMode(0); DrawRectangleRec(area, Color); } } \ No newline at end of file diff --git a/UI/Brushes/TextureBrush.cs b/UI/Brushes/TextureBrush.cs index 36b3992..6865787 100644 --- a/UI/Brushes/TextureBrush.cs +++ b/UI/Brushes/TextureBrush.cs @@ -4,14 +4,14 @@ namespace BuildingGame.UI.Brushes; public class TextureBrush : IBrush { - public Texture Texture; - public Color Tint = WHITE; + public Texture2D Texture; + public Color Tint = Color.WHITE; public Rectangle CropArea; - public TextureBrush(Texture texture) + public TextureBrush(Texture2D texture) { Texture = texture; - CropArea = new Rectangle(0, 0, texture.width, texture.height); + CropArea = new Rectangle(0, 0, texture.Width, texture.Height); } public void FillArea(Rectangle area) diff --git a/UI/Element.cs b/UI/Element.cs index cec0631..fc2eb40 100644 --- a/UI/Element.cs +++ b/UI/Element.cs @@ -14,20 +14,20 @@ public Rectangle Area _Area = value; UnloadRenderTexture(_controlTexture); - _controlTexture = LoadRenderTexture((int)value.width, (int)value.height); + _controlTexture = LoadRenderTexture((int)value.Width, (int)value.Height); } } public Vector2 Position { - get => new Vector2(_Area.x, _Area.y); - set => _Area = new Rectangle(value.X, value.Y, _Area.width, _Area.height); + get => new Vector2(_Area.X, _Area.Y); + set => _Area = new Rectangle(value.X, value.Y, _Area.Width, _Area.Height); } public Vector2 Size { - get => new Vector2(_Area.width, _Area.height); - set => Area = new Rectangle(_Area.x, _Area.y, value.X, value.Y); + get => new Vector2(_Area.Width, _Area.Height); + set => Area = new Rectangle(_Area.X, _Area.Y, value.X, value.Y); } public string Name; @@ -42,7 +42,7 @@ public Vector2 Size public bool IgnorePause = false; - private RenderTexture _controlTexture; + private RenderTexture2D _controlTexture; public Element(string name) { @@ -58,7 +58,7 @@ public virtual void Update() public void Draw() { BeginTextureMode(_controlTexture); - ClearBackground(BLANK); + ClearBackground(Color.BLANK); Render(); @@ -67,32 +67,32 @@ public void Draw() Vector2 offset = Origin switch { Alignment.TopLeft => new Vector2(0, 0), - Alignment.TopRight => new Vector2(_Area.width, 0), - Alignment.TopCenter => new Vector2(_Area.width / 2, 0), - Alignment.CenterLeft => new Vector2(0, _Area.height / 2), - Alignment.CenterRight => new Vector2(_Area.width, _Area.height / 2), - Alignment.Center => new Vector2(_Area.width / 2, _Area.height / 2), - Alignment.BottomLeft => new Vector2(0, _Area.height), - Alignment.BottomRight => new Vector2(_Area.width, _Area.height), - Alignment.BottomCenter => new Vector2(_Area.width / 2, _Area.height), + Alignment.TopRight => new Vector2(_Area.Width, 0), + Alignment.TopCenter => new Vector2(_Area.Width / 2, 0), + Alignment.CenterLeft => new Vector2(0, _Area.Height / 2), + Alignment.CenterRight => new Vector2(_Area.Width, _Area.Height / 2), + Alignment.Center => new Vector2(_Area.Width / 2, _Area.Height / 2), + Alignment.BottomLeft => new Vector2(0, _Area.Height), + Alignment.BottomRight => new Vector2(_Area.Width, _Area.Height), + Alignment.BottomCenter => new Vector2(_Area.Width / 2, _Area.Height), _ => new Vector2(0, 0) }; DrawTexturePro( - _controlTexture.texture, + _controlTexture.Texture, new Rectangle( -1, 0, - _Area.width + 1, -_Area.height - 1 // we need to negate render texture height because opengl uses bottom-left instead of top-left + _Area.Width + 1, -_Area.Height - 1 // we need to negate render texture height because opengl uses bottom-left instead of top-left ), _Area, offset, Rotation, - WHITE + Color.WHITE ); } protected virtual void Render() { - ClearBackground(BLACK); - DrawText(":(", 0, 0, 16, WHITE); + ClearBackground(Color.BLACK); + DrawText(":(", 0, 0, 16, Color.WHITE); } public bool IsHovered() diff --git a/UI/Elements/CheckBox.cs b/UI/Elements/CheckBox.cs index 41d7df1..213e293 100644 --- a/UI/Elements/CheckBox.cs +++ b/UI/Elements/CheckBox.cs @@ -7,12 +7,12 @@ public class CheckBox : Element { public bool Checked; - public IBrush? CheckBoxBrush = new OutlineBrush(GRAY, LIGHTGRAY); + public IBrush? CheckBoxBrush = new OutlineBrush(Color.GRAY, Color.LIGHTGRAY); public float BoxScale = 1f; public string Text = string.Empty; public float TextSize = 12; - public Color TextColor = WHITE; + public Color TextColor = Color.WHITE; public CheckBox(string name) : base(name) @@ -28,7 +28,7 @@ protected override void Render() { Rectangle boxArea = new Rectangle( 0, - 0 + Area.height / 2 - 18 * BoxScale / 2, + 0 + Area.Height / 2 - 18 * BoxScale / 2, 18 * BoxScale, 18 * BoxScale ); @@ -39,9 +39,9 @@ protected override void Render() Resources.GetTexture("Checkmark.png"), new Rectangle(0, 0, 18, 18), boxArea, - Vector2.Zero, 0, WHITE); + Vector2.Zero, 0, Color.WHITE); } - DrawText(Text, 8 + 18 * BoxScale, Area.height / 2 - TextSize / 2f, TextSize, TextColor); + DrawText(Text, 8 + 18 * BoxScale, Area.Height / 2 - TextSize / 2f, TextSize, TextColor); } } \ No newline at end of file diff --git a/UI/Elements/ListBox.cs b/UI/Elements/ListBox.cs index 5b28597..0735d21 100644 --- a/UI/Elements/ListBox.cs +++ b/UI/Elements/ListBox.cs @@ -1,3 +1,4 @@ +using System.Numerics; using BuildingGame.UI.Brushes; namespace BuildingGame.UI.Elements; @@ -9,13 +10,13 @@ public class ListBox : Element public List Items = new List(); public event Action? OnItemSelect; - public IBrush? BackgroundBrush = new SolidBrush(WHITE); + public IBrush? BackgroundBrush = new SolidBrush(Color.WHITE); public IBrush? HighlightBrush = new SolidBrush(new Color(212, 245, 255, 255)); public IBrush? SelectionBrush = new SolidBrush(new Color(122, 214, 255, 255)); public float ItemTextSize = 12; public float ItemPadding = 4; - public Color ItemColor = WHITE; + public Color ItemColor = Color.WHITE; private float _scroll = 0; private int _highlightIndex = -1; @@ -35,7 +36,7 @@ public override void Update() _highlightIndex = index; // list scrolling - float boxHeight = Items.Count * ItemTextSize - Area.height + ItemPadding; + float boxHeight = Items.Count * ItemTextSize - Area.Height + ItemPadding; float wheel = GetMouseWheelMove(); float wheelAxis = wheel * ScrollSpeed * GetFrameTime(); @@ -62,7 +63,7 @@ protected override void Render() Rectangle area = new Rectangle( ItemPadding, i * ItemTextSize + ItemPadding + _scroll, - Area.width, + Area.Width, ItemTextSize ); if (i == _selectedIndex) @@ -74,7 +75,7 @@ protected override void Render() HighlightBrush?.FillArea(area); } - DrawText(Items[i], area.x, area.y, ItemTextSize, ItemColor); + DrawText(Items[i], area.X, area.Y, ItemTextSize, ItemColor); } } } \ No newline at end of file diff --git a/UI/Elements/Panel.cs b/UI/Elements/Panel.cs index 3bbf8aa..09980c5 100644 --- a/UI/Elements/Panel.cs +++ b/UI/Elements/Panel.cs @@ -13,6 +13,6 @@ public Panel(string name) : base(name) protected override void Render() { - Brush?.FillArea(new Rectangle(Padding, Padding, Area.width - Padding - 1, Area.height - Padding - 1)); + Brush?.FillArea(new Rectangle(Padding, Padding, Area.Width - Padding - 1, Area.Height - Padding - 1)); } } \ No newline at end of file diff --git a/UI/Elements/TextBox.cs b/UI/Elements/TextBox.cs index 7ebe8af..2245c3d 100644 --- a/UI/Elements/TextBox.cs +++ b/UI/Elements/TextBox.cs @@ -1,3 +1,4 @@ +using System.Runtime.InteropServices; using BuildingGame.UI.Brushes; namespace BuildingGame.UI.Elements; @@ -11,8 +12,8 @@ public class TextBox : TextElement public TextBox(string name) : base(name) { - _brush = new OutlineBrush(BLACK, LIGHTGRAY); - TextColor = BLACK; + _brush = new OutlineBrush(Color.BLACK, Color.LIGHTGRAY); + TextColor = Color.BLACK; } public override void Update() @@ -20,7 +21,7 @@ public override void Update() if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT)) { _focused = IsHovered(); - _brush.LineColor = _focused ? GRAY : BLACK; + _brush.LineColor = _focused ? Color.GRAY : Color.BLACK; // _brush.LineThick = _focused ? 1.5f : 1; GuiManager.IsFocused = _focused; @@ -39,7 +40,8 @@ private void GatherInput() if (c is >= 32 and <= 125 && Text.Length < MaxCharacters) Text += char.ConvertFromUtf32(c); - if (IsKeyPressedRepeat((int)KeyboardKey.KEY_BACKSPACE) && Text.Length > 0) + + if (IsKeyPressedRepeat(KeyboardKey.KEY_BACKSPACE) && Text.Length > 0) Text = Text.Remove(Text.Length - 1); } } \ No newline at end of file diff --git a/UI/Elements/TextElement.cs b/UI/Elements/TextElement.cs index a860dbc..90f1dd4 100644 --- a/UI/Elements/TextElement.cs +++ b/UI/Elements/TextElement.cs @@ -7,7 +7,7 @@ public class TextElement : Element { public IBrush? BackgroundBrush; - public Color TextColor = WHITE; + public Color TextColor = Color.WHITE; public string Text = string.Empty; public float TextSize = 10; public Alignment TextAlignment = Alignment.TopLeft; @@ -27,15 +27,15 @@ public Vector2 GetTextSize() protected override void Render() { Vector2 textSize = GetTextSize(); - float width = (AutoExtend ? MathF.Max(Area.width, textSize.X) : Area.width) - Padding - 1; - float height = (AutoExtend ? MathF.Max(Area.height, textSize.Y) : Area.height) - Padding - 1; + float width = (AutoExtend ? MathF.Max(Area.Width, textSize.X) : Area.Width) - Padding - 1; + float height = (AutoExtend ? MathF.Max(Area.Height, textSize.Y) : Area.Height) - Padding - 1; float xLeft = Padding + 4; - float xRight = Area.width - textSize.X - Padding * 2; - float xCenter = Area.width / 2 - textSize.X / 2; + float xRight = Area.Width - textSize.X - Padding * 2; + float xCenter = Area.Width / 2 - textSize.X / 2; float yTop = Padding + 4; - float yBottom = Area.height - textSize.Y - Padding * 2; - float yCenter = Area.height / 2 - textSize.Y / 2; + float yBottom = Area.Height - textSize.Y - Padding * 2; + float yCenter = Area.Height / 2 - textSize.Y / 2; Vector2 xy = TextAlignment switch { diff --git a/UI/Interfaces/BlockMenu.cs b/UI/Interfaces/BlockMenu.cs index 5ff24dd..5e6bdf5 100644 --- a/UI/Interfaces/BlockMenu.cs +++ b/UI/Interfaces/BlockMenu.cs @@ -25,7 +25,7 @@ public override void Initialize() _menuTitle = new TextElement("blockMenu::title") { Text = "Select a tile", - TextColor = WHITE, + TextColor = Color.WHITE, TextSize = 32, TextAlignment = Alignment.Center }; diff --git a/UI/Interfaces/GameHud.cs b/UI/Interfaces/GameHud.cs index 3d8d3b8..ed42d0f 100644 --- a/UI/Interfaces/GameHud.cs +++ b/UI/Interfaces/GameHud.cs @@ -46,7 +46,7 @@ public override void Update() var brush = (TextureBrush)_tileMenuButton.BackgroundBrush!; var tile = Tiles.Tiles.GetTile(Player.CurrentTile); - (brush.CropArea.x, brush.CropArea.y) = (tile.TexCoord.X * Tile.TileSize, tile.TexCoord.Y * Tile.TileSize); + (brush.CropArea.X, brush.CropArea.Y) = (tile.TexCoord.X * Tile.TileSize, tile.TexCoord.Y * Tile.TileSize); } public override void Configure() diff --git a/UI/Interfaces/PauseScreen.cs b/UI/Interfaces/PauseScreen.cs index 87307e0..2dd66e0 100644 --- a/UI/Interfaces/PauseScreen.cs +++ b/UI/Interfaces/PauseScreen.cs @@ -22,7 +22,7 @@ public override void Initialize() _background = new Panel("pauseScreen::background") { - Brush = new GradientBrush(BLANK, BLACK), + Brush = new GradientBrush(Color.BLANK, Color.BLACK), IgnorePause = true, ZIndex = 100 }; diff --git a/UI/Screens/GameScreen.cs b/UI/Screens/GameScreen.cs index f139fee..dfcf0ef 100644 --- a/UI/Screens/GameScreen.cs +++ b/UI/Screens/GameScreen.cs @@ -41,7 +41,7 @@ public override void Update() public override void Draw() { - ClearBackground(SKYBLUE); + ClearBackground(Color.SKYBLUE); BeginMode2D(_player.Camera); { From 222f2898ea4ebe232fc0ec0015edc5c727f72b68 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 17:38:08 +0200 Subject: [PATCH 043/107] rename interfaces --- UI/Interfaces/{BlockMenu.cs => BlockUI.cs} | 2 +- UI/Interfaces/{GameHud.cs => GameUI.cs} | 10 +++++----- UI/Interfaces/{PauseScreen.cs => PauseUI.cs} | 4 ++-- UI/Screens/GameScreen.cs | 12 ++++++------ 4 files changed, 14 insertions(+), 14 deletions(-) rename UI/Interfaces/{BlockMenu.cs => BlockUI.cs} (98%) rename UI/Interfaces/{GameHud.cs => GameUI.cs} (90%) rename UI/Interfaces/{PauseScreen.cs => PauseUI.cs} (97%) diff --git a/UI/Interfaces/BlockMenu.cs b/UI/Interfaces/BlockUI.cs similarity index 98% rename from UI/Interfaces/BlockMenu.cs rename to UI/Interfaces/BlockUI.cs index 5e6bdf5..f171619 100644 --- a/UI/Interfaces/BlockMenu.cs +++ b/UI/Interfaces/BlockUI.cs @@ -5,7 +5,7 @@ namespace BuildingGame.UI.Interfaces; -public class BlockMenu : UIInterface +public class BlockUI : UIInterface { private Panel _background = null!; private TextElement _menuTitle = null!; diff --git a/UI/Interfaces/GameHud.cs b/UI/Interfaces/GameUI.cs similarity index 90% rename from UI/Interfaces/GameHud.cs rename to UI/Interfaces/GameUI.cs index ed42d0f..1208afc 100644 --- a/UI/Interfaces/GameHud.cs +++ b/UI/Interfaces/GameUI.cs @@ -4,18 +4,18 @@ namespace BuildingGame.UI.Interfaces; -public class GameHud : UIInterface +public class GameUI : UIInterface { private const float TileButtonOffset = Tile.RealTileSize / 2; private const float TileButtonSize = Tile.RealTileSize * 2; - private BlockMenu _menu; + private BlockUI _ui; private Button _tileMenuButton = null!; - public GameHud(BlockMenu menu) + public GameUI(BlockUI ui) { - _menu = menu; + _ui = ui; } public override void Initialize() @@ -32,7 +32,7 @@ public override void Initialize() }; _tileMenuButton.OnClick += () => { - _menu.Visible = !_menu.Visible; + _ui.Visible = !_ui.Visible; }; Elements.Add(_tileMenuButton); diff --git a/UI/Interfaces/PauseScreen.cs b/UI/Interfaces/PauseUI.cs similarity index 97% rename from UI/Interfaces/PauseScreen.cs rename to UI/Interfaces/PauseUI.cs index 2dd66e0..cd9bb15 100644 --- a/UI/Interfaces/PauseScreen.cs +++ b/UI/Interfaces/PauseUI.cs @@ -4,14 +4,14 @@ namespace BuildingGame.UI.Interfaces; -public class PauseScreen : UIInterface +public class PauseUI : UIInterface { private Panel _background; private Button _resumeButton; private Button _menuButton; private Button _settingsButton; - public PauseScreen() + public PauseUI() { IgnorePause = true; } diff --git a/UI/Screens/GameScreen.cs b/UI/Screens/GameScreen.cs index dfcf0ef..f7ae2c3 100644 --- a/UI/Screens/GameScreen.cs +++ b/UI/Screens/GameScreen.cs @@ -7,9 +7,9 @@ public class GameScreen : Screen { private World _world; private Player _player; - private BlockMenu _menu; - private GameHud _hud; - private PauseScreen _pause; + private BlockUI _blockUi; + private GameUI _ui; + private PauseUI _pause; public override void Initialize() { @@ -20,9 +20,9 @@ public override void Initialize() _player = new Player(_world, _world.PlayerPosition, _world.PlayerZoom, 50, 0.1f); - _menu = new BlockMenu(); - _hud = new GameHud(_menu); - _pause = new PauseScreen(); + _blockUi = new BlockUI(); + _ui = new GameUI(_blockUi); + _pause = new PauseUI(); } public override void Update() From af9f8fabc3acfd7fd7d8adfe4b4a518d65545285 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 17:41:06 +0200 Subject: [PATCH 044/107] use IsKeyPressed for shortcuts instead --- UI/Interfaces/BlockUI.cs | 2 +- UI/Interfaces/PauseUI.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/UI/Interfaces/BlockUI.cs b/UI/Interfaces/BlockUI.cs index f171619..5b91206 100644 --- a/UI/Interfaces/BlockUI.cs +++ b/UI/Interfaces/BlockUI.cs @@ -120,7 +120,7 @@ public override void Update() { base.Update(); - if (IsKeyReleased(KeyboardKey.KEY_B)) Visible = !Visible; + if (IsKeyPressed(KeyboardKey.KEY_B)) Visible = !Visible; if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT) && !_background.IsHovered()) Visible = false; } diff --git a/UI/Interfaces/PauseUI.cs b/UI/Interfaces/PauseUI.cs index cd9bb15..15c76ba 100644 --- a/UI/Interfaces/PauseUI.cs +++ b/UI/Interfaces/PauseUI.cs @@ -97,7 +97,7 @@ public override void Update() { base.Update(); - if (IsKeyReleased(KeyboardKey.KEY_ESCAPE)) + if (IsKeyPressed(KeyboardKey.KEY_ESCAPE)) { Visible = !Visible; Program.Paused = !Program.Paused; From ec60ec959e924a340c08af87ceee6075d9e84316 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 17:52:58 +0200 Subject: [PATCH 045/107] rename variable --- UI/Interfaces/GameUI.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/UI/Interfaces/GameUI.cs b/UI/Interfaces/GameUI.cs index 1208afc..ccf113f 100644 --- a/UI/Interfaces/GameUI.cs +++ b/UI/Interfaces/GameUI.cs @@ -9,13 +9,13 @@ public class GameUI : UIInterface private const float TileButtonOffset = Tile.RealTileSize / 2; private const float TileButtonSize = Tile.RealTileSize * 2; - private BlockUI _ui; + private BlockUI _blockUi; private Button _tileMenuButton = null!; - public GameUI(BlockUI ui) + public GameUI(BlockUI blockUi) { - _ui = ui; + _blockUi = blockUi; } public override void Initialize() @@ -32,7 +32,7 @@ public override void Initialize() }; _tileMenuButton.OnClick += () => { - _ui.Visible = !_ui.Visible; + _blockUi.Visible = !_blockUi.Visible; }; Elements.Add(_tileMenuButton); From b96fa3e3f1a85b4f9b4c4e11269d6806d2fff6a6 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 18:02:44 +0200 Subject: [PATCH 046/107] fix toggle menu button --- UI/Interfaces/BlockUI.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/UI/Interfaces/BlockUI.cs b/UI/Interfaces/BlockUI.cs index 5b91206..55c8378 100644 --- a/UI/Interfaces/BlockUI.cs +++ b/UI/Interfaces/BlockUI.cs @@ -121,7 +121,8 @@ public override void Update() base.Update(); if (IsKeyPressed(KeyboardKey.KEY_B)) Visible = !Visible; - if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT) && !_background.IsHovered()) + if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT) && !_background.IsHovered() && + GuiManager.GetElementUnderMouse()?.Name != "gameHud::tileMenuButton") // 🤟😏 Visible = false; } } \ No newline at end of file From e5acec30e422bc0734416ecce7958684b6097272 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 18:39:12 +0200 Subject: [PATCH 047/107] use element id instead of name --- UI/Element.cs | 6 +-- UI/ElementId.cs | 75 ++++++++++++++++++++++++++++++++++++++ UI/Elements/Button.cs | 2 +- UI/Elements/CheckBox.cs | 2 +- UI/Elements/ListBox.cs | 2 +- UI/Elements/Panel.cs | 2 +- UI/Elements/TextBox.cs | 2 +- UI/Elements/TextElement.cs | 2 +- UI/Elements/Tooltip.cs | 2 +- UI/GuiManager.cs | 12 +++--- UI/Interfaces/BlockUI.cs | 8 ++-- UI/Interfaces/GameUI.cs | 2 +- UI/Interfaces/PauseUI.cs | 8 ++-- 13 files changed, 100 insertions(+), 25 deletions(-) create mode 100644 UI/ElementId.cs diff --git a/UI/Element.cs b/UI/Element.cs index fc2eb40..393039e 100644 --- a/UI/Element.cs +++ b/UI/Element.cs @@ -30,7 +30,7 @@ public Vector2 Size set => Area = new Rectangle(_Area.X, _Area.Y, value.X, value.Y); } - public string Name; + public ElementId Id; public short ZIndex; public bool Active = true; @@ -44,9 +44,9 @@ public Vector2 Size private RenderTexture2D _controlTexture; - public Element(string name) + public Element(ElementId id) { - Name = name; + Id = id; Area = new Rectangle(0, 0, 128, 128); GuiManager.Add(this); } diff --git a/UI/ElementId.cs b/UI/ElementId.cs new file mode 100644 index 0000000..722eccd --- /dev/null +++ b/UI/ElementId.cs @@ -0,0 +1,75 @@ +using System.Text; + +namespace BuildingGame.UI; + +public struct ElementId +{ + public readonly string? Root; + public string Name; + + public ElementId(string root, string name) + { + Root = root; + Name = name; + } + + public ElementId(string name) + { + var split = name.Split("::"); + + switch (split.Length) + { + case >= 2: + Root = split[0]; + Name = split[1]; + break; + case >= 1: + Name = split[0]; + break; + } + } + + public override bool Equals(object? obj) + { + if (obj is string str) return Equals(str); + if (obj is ElementId id) return Equals(id); + + return false; + } + + public override int GetHashCode() + { + return HashCode.Combine(Root, Name); + } + + private bool Equals(ElementId id) + { + return string.Equals(Root, id.Root, StringComparison.CurrentCultureIgnoreCase) && + string.Equals(Name, id.Name, StringComparison.CurrentCultureIgnoreCase); + } + + private bool Equals(string id) + { + return string.Equals(id, ToString(), StringComparison.CurrentCultureIgnoreCase); + } + + public override string ToString() + { + var builder = new StringBuilder(); + if (Root != null) + { + builder.Append(Root); + builder.Append("::"); + } + builder.Append(Name); + return builder.ToString(); + } + + public static implicit operator string(ElementId id) => id.ToString(); + + public static bool operator ==(ElementId a, ElementId b) => a.Equals(b); + public static bool operator !=(ElementId a, ElementId b) => !(a == b); + + public static bool operator ==(ElementId a, string b) => a.Equals(b); + public static bool operator !=(ElementId a, string b) => !(a == b); +} \ No newline at end of file diff --git a/UI/Elements/Button.cs b/UI/Elements/Button.cs index bdc8d77..d667684 100644 --- a/UI/Elements/Button.cs +++ b/UI/Elements/Button.cs @@ -7,7 +7,7 @@ public class Button : TextElement public bool ShowHoverText = true; public event Action? OnClick; - public Button(string name) : base(name) + public Button(ElementId id) : base(id) { } diff --git a/UI/Elements/CheckBox.cs b/UI/Elements/CheckBox.cs index 213e293..5b29e81 100644 --- a/UI/Elements/CheckBox.cs +++ b/UI/Elements/CheckBox.cs @@ -15,7 +15,7 @@ public class CheckBox : Element public Color TextColor = Color.WHITE; - public CheckBox(string name) : base(name) + public CheckBox(ElementId id) : base(id) { } diff --git a/UI/Elements/ListBox.cs b/UI/Elements/ListBox.cs index 0735d21..cf5040d 100644 --- a/UI/Elements/ListBox.cs +++ b/UI/Elements/ListBox.cs @@ -22,7 +22,7 @@ public class ListBox : Element private int _highlightIndex = -1; private int _selectedIndex = -1; - public ListBox(string name) : base(name) + public ListBox(ElementId id) : base(id) { } diff --git a/UI/Elements/Panel.cs b/UI/Elements/Panel.cs index 09980c5..7ad096d 100644 --- a/UI/Elements/Panel.cs +++ b/UI/Elements/Panel.cs @@ -7,7 +7,7 @@ public class Panel : Element public IBrush? Brush; public int Padding = 0; - public Panel(string name) : base(name) + public Panel(ElementId id) : base(id) { } diff --git a/UI/Elements/TextBox.cs b/UI/Elements/TextBox.cs index 2245c3d..06d94b4 100644 --- a/UI/Elements/TextBox.cs +++ b/UI/Elements/TextBox.cs @@ -10,7 +10,7 @@ public class TextBox : TextElement private bool _focused; private OutlineBrush _brush; - public TextBox(string name) : base(name) + public TextBox(ElementId id) : base(id) { _brush = new OutlineBrush(Color.BLACK, Color.LIGHTGRAY); TextColor = Color.BLACK; diff --git a/UI/Elements/TextElement.cs b/UI/Elements/TextElement.cs index 90f1dd4..bbb3a21 100644 --- a/UI/Elements/TextElement.cs +++ b/UI/Elements/TextElement.cs @@ -15,7 +15,7 @@ public class TextElement : Element public float Padding = 0; - public TextElement(string name) : base(name) + public TextElement(ElementId id) : base(id) { } diff --git a/UI/Elements/Tooltip.cs b/UI/Elements/Tooltip.cs index 6d4ef8b..f6a1f72 100644 --- a/UI/Elements/Tooltip.cs +++ b/UI/Elements/Tooltip.cs @@ -4,7 +4,7 @@ namespace BuildingGame.UI.Elements; public class Tooltip : TextElement { - public Tooltip(string name) : base(name) + public Tooltip(ElementId id) : base(id) { Visible = false; TextAlignment = Alignment.CenterLeft; diff --git a/UI/GuiManager.cs b/UI/GuiManager.cs index 881dc85..51b6e35 100644 --- a/UI/GuiManager.cs +++ b/UI/GuiManager.cs @@ -19,30 +19,30 @@ public static void Remove(Element element) ScreenManager.CurrentScreen?.Elements.Remove(element); } - public static void Remove(string name) + public static void Remove(ElementId id) { if (ScreenManager.CurrentScreen == null) return; - int index = ScreenManager.CurrentScreen.Elements.FindIndex(e => string.Equals(e.Name, name, StringComparison.CurrentCultureIgnoreCase)); + int index = ScreenManager.CurrentScreen.Elements.FindIndex(e => e.Id == id); if (index < 0) return; ScreenManager.CurrentScreen.Elements.RemoveAt(index); } - public static Element? Get(string name) + public static Element? Get(ElementId id) { if (ScreenManager.CurrentScreen == null) return null; - int index = ScreenManager.CurrentScreen.Elements.FindIndex(e => string.Equals(e.Name, name, StringComparison.CurrentCultureIgnoreCase)); + int index = ScreenManager.CurrentScreen.Elements.FindIndex(e => e.Id == id); if (index < 0) return null; return ScreenManager.CurrentScreen.Elements[index]; } - public static TElement? GetAs(string name) where TElement : Element + public static TElement? GetAs(ElementId id) where TElement : Element { if (ScreenManager.CurrentScreen == null) return default; int index = ScreenManager.CurrentScreen.Elements.FindIndex(e => - e.GetType() == typeof(TElement) && string.Equals(e.Name, name, StringComparison.CurrentCultureIgnoreCase)); + e.GetType() == typeof(TElement) && e.Id == id); if (index < 0) return default; return ScreenManager.CurrentScreen.Elements[index] as TElement; } diff --git a/UI/Interfaces/BlockUI.cs b/UI/Interfaces/BlockUI.cs index 55c8378..1898fe9 100644 --- a/UI/Interfaces/BlockUI.cs +++ b/UI/Interfaces/BlockUI.cs @@ -15,14 +15,14 @@ public override void Initialize() { base.Initialize(); - _background = new Panel("blockMenu::background") + _background = new Panel(new ElementId("blockMenu", "background")) { Brush = new GradientBrush(new Color(0, 0, 25, 100), new Color(0, 0, 0, 200)), ZIndex = -1 }; Elements.Add(_background); - _menuTitle = new TextElement("blockMenu::title") + _menuTitle = new TextElement(new ElementId("blockMenu", "title")) { Text = "Select a tile", TextColor = Color.WHITE, @@ -48,7 +48,7 @@ public override void Initialize() float ratio = aspectX < aspectY ? aspectX : aspectY; - _tileButtons[i] = new Button("blockMenu::tile_" + i) + _tileButtons[i] = new Button(new ElementId("blockMenu", "tile_" + i)) { Size = new Vector2(1) * Tile.RealTileSize, BackgroundBrush = new TextureBrush(Resources.GetTexture("Atlas.png")) @@ -122,7 +122,7 @@ public override void Update() if (IsKeyPressed(KeyboardKey.KEY_B)) Visible = !Visible; if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT) && !_background.IsHovered() && - GuiManager.GetElementUnderMouse()?.Name != "gameHud::tileMenuButton") // 🤟😏 + GuiManager.GetElementUnderMouse()?.Id != "gameHud::tileMenuButton") // 🤟😏 Visible = false; } } \ No newline at end of file diff --git a/UI/Interfaces/GameUI.cs b/UI/Interfaces/GameUI.cs index ccf113f..e595db6 100644 --- a/UI/Interfaces/GameUI.cs +++ b/UI/Interfaces/GameUI.cs @@ -22,7 +22,7 @@ public override void Initialize() { base.Initialize(); - _tileMenuButton = new Button("gameHud::tileMenuButton") + _tileMenuButton = new Button(new ElementId("gameHud", "tileMenuButton")) { BackgroundBrush = new TextureBrush(Resources.GetTexture("Atlas.png")) { diff --git a/UI/Interfaces/PauseUI.cs b/UI/Interfaces/PauseUI.cs index 15c76ba..96ae820 100644 --- a/UI/Interfaces/PauseUI.cs +++ b/UI/Interfaces/PauseUI.cs @@ -20,7 +20,7 @@ public override void Initialize() { base.Initialize(); - _background = new Panel("pauseScreen::background") + _background = new Panel(new ElementId("pauseScreen", "background")) { Brush = new GradientBrush(Color.BLANK, Color.BLACK), IgnorePause = true, @@ -28,7 +28,7 @@ public override void Initialize() }; Elements.Add(_background); - _resumeButton = new Button("pauseScreen::resumeButton") + _resumeButton = new Button(new ElementId("pauseScreen", "resumeButton")) { Text = "resume", TextSize = 24, @@ -43,7 +43,7 @@ public override void Initialize() }; Elements.Add(_resumeButton); - _settingsButton = new Button("pauseScreen::settingsButton") + _settingsButton = new Button(new ElementId("pauseScreen", "settingsButton")) { Text = "settings", TextSize = 24, @@ -53,7 +53,7 @@ public override void Initialize() }; Elements.Add(_settingsButton); - _menuButton = new Button("pauseScreen::menuButton") + _menuButton = new Button(new ElementId("pauseScreen", "menuButton")) { Text = "menu", TextSize = 24, From 95870e19d494bf9573d9506b0c0de877c8167990 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 18:55:22 +0200 Subject: [PATCH 048/107] i hope i fixed element rendering --- UI/Element.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UI/Element.cs b/UI/Element.cs index 393039e..547f52e 100644 --- a/UI/Element.cs +++ b/UI/Element.cs @@ -81,8 +81,8 @@ public void Draw() DrawTexturePro( _controlTexture.Texture, new Rectangle( - -1, 0, - _Area.Width + 1, -_Area.Height - 1 // we need to negate render texture height because opengl uses bottom-left instead of top-left + 0, 0, + _Area.Width + 1, -_Area.Height // we need to negate render texture height because opengl uses bottom-left instead of top-left ), _Area, offset, Rotation, Color.WHITE From 9ffbaacd678d4ad1d17b06079a1ce955c43bf455 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 19:01:36 +0200 Subject: [PATCH 049/107] implement auto extend fr --- UI/Elements/TextElement.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/UI/Elements/TextElement.cs b/UI/Elements/TextElement.cs index bbb3a21..cb2c43e 100644 --- a/UI/Elements/TextElement.cs +++ b/UI/Elements/TextElement.cs @@ -24,11 +24,20 @@ public Vector2 GetTextSize() return MeasureTextEx(GuiManager.Font, Text, TextSize, TextSize / GuiManager.FontSize); } + public override void Update() + { + var textSize = GetTextSize(); + if (AutoExtend && (Size.X < textSize.X || Size.Y < textSize.Y)) + { + Size = textSize + new Vector2(Padding + 4.0f); + } + } + protected override void Render() { - Vector2 textSize = GetTextSize(); - float width = (AutoExtend ? MathF.Max(Area.Width, textSize.X) : Area.Width) - Padding - 1; - float height = (AutoExtend ? MathF.Max(Area.Height, textSize.Y) : Area.Height) - Padding - 1; + var textSize = GetTextSize(); + float width = Area.Width - Padding - 1; + float height = Area.Height - Padding - 1; float xLeft = Padding + 4; float xRight = Area.Width - textSize.X - Padding * 2; From a28003d1d0430bbd0aabec202605795ae02208ba Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 19:06:28 +0200 Subject: [PATCH 050/107] whoops textelement inheritors didnt update base --- UI/Elements/Button.cs | 2 ++ UI/Elements/TextBox.cs | 2 ++ UI/Elements/Tooltip.cs | 2 ++ 3 files changed, 6 insertions(+) diff --git a/UI/Elements/Button.cs b/UI/Elements/Button.cs index d667684..9a5b9af 100644 --- a/UI/Elements/Button.cs +++ b/UI/Elements/Button.cs @@ -13,6 +13,8 @@ public Button(ElementId id) : base(id) public override void Update() { + base.Update(); + if (IsClicked()) { OnClick?.Invoke(); diff --git a/UI/Elements/TextBox.cs b/UI/Elements/TextBox.cs index 06d94b4..0bf5f7d 100644 --- a/UI/Elements/TextBox.cs +++ b/UI/Elements/TextBox.cs @@ -18,6 +18,8 @@ public TextBox(ElementId id) : base(id) public override void Update() { + base.Update(); + if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT)) { _focused = IsHovered(); diff --git a/UI/Elements/Tooltip.cs b/UI/Elements/Tooltip.cs index f6a1f72..023c764 100644 --- a/UI/Elements/Tooltip.cs +++ b/UI/Elements/Tooltip.cs @@ -12,6 +12,8 @@ public Tooltip(ElementId id) : base(id) public override void Update() { + base.Update(); + Element? el = GuiManager.GetElementUnderMouse(); if (el != null && el.TooltipText != string.Empty) From 77e3a77fdcae5eca481de6c9d395ddc990c3b93b Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 20:14:50 +0200 Subject: [PATCH 051/107] fix element rendering one more time --- UI/Element.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/Element.cs b/UI/Element.cs index 547f52e..35359bd 100644 --- a/UI/Element.cs +++ b/UI/Element.cs @@ -82,7 +82,7 @@ public void Draw() _controlTexture.Texture, new Rectangle( 0, 0, - _Area.Width + 1, -_Area.Height // we need to negate render texture height because opengl uses bottom-left instead of top-left + _Area.Width, -_Area.Height // we need to negate render texture height because opengl uses bottom-left instead of top-left ), _Area, offset, Rotation, Color.WHITE From ab046a77c306091281954b1ed3e3b0f37f14294a Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 20:15:11 +0200 Subject: [PATCH 052/107] add extra raylib methods (aka. utils :D) --- Raylib.ExtraMethods.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Raylib.ExtraMethods.cs b/Raylib.ExtraMethods.cs index 31737a0..469e595 100644 --- a/Raylib.ExtraMethods.cs +++ b/Raylib.ExtraMethods.cs @@ -19,11 +19,15 @@ public static void DrawText(string text, float posX, float posY, float fontSize, if (GetFontDefault().Texture.Id == 0) return; var pos = new Vector2(posX, posY); + var spacing = GetSpacing(fontSize); + + DrawTextEx(GetFontDefault(), text, pos, fontSize, spacing, color); + } + public static float GetSpacing(float fontSize) + { var defaultFontSize = 10.0f; if (fontSize < defaultFontSize) fontSize = defaultFontSize; - var spacing = fontSize / defaultFontSize; - - DrawTextEx(GetFontDefault(), text, pos, fontSize, spacing, color); + return fontSize / defaultFontSize; } } \ No newline at end of file From 9264de29730ab58fa2f2e4aeff660f25dcae3bd3 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 20:19:31 +0200 Subject: [PATCH 053/107] implement screen switching --- UI/Interfaces/UIInterfaceManager.cs | 1 + UI/Screens/ScreenManager.cs | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/UI/Interfaces/UIInterfaceManager.cs b/UI/Interfaces/UIInterfaceManager.cs index 99dd075..e9d80ba 100644 --- a/UI/Interfaces/UIInterfaceManager.cs +++ b/UI/Interfaces/UIInterfaceManager.cs @@ -32,5 +32,6 @@ public static void Update() public static void Destroy() { foreach (var i in _interfaces) i.Destroy(); + _interfaces.Clear(); } } diff --git a/UI/Screens/ScreenManager.cs b/UI/Screens/ScreenManager.cs index d29c627..699c1d5 100644 --- a/UI/Screens/ScreenManager.cs +++ b/UI/Screens/ScreenManager.cs @@ -1,9 +1,21 @@ +using BuildingGame.UI.Interfaces; + namespace BuildingGame.UI.Screens; public static class ScreenManager { public static Screen? CurrentScreen; + public static void Switch(Screen newScreen) + { + UIInterfaceManager.Destroy(); + Free(); + + newScreen.IsCurrent = true; + Initialize(); + UIInterfaceManager.Initialize(); + } + public static void Initialize() { CurrentScreen?.Initialize(); From da64830f1a4a6aadb0745b63f42494ba29ec13fe Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 21:11:06 +0200 Subject: [PATCH 054/107] implement menu --- Program.cs | 5 +- UI/Interfaces/MenuUI.cs | 103 +++++++++++++++++++++++++++++++++++++++ UI/Interfaces/PauseUI.cs | 6 +++ UI/Screens/MenuScreen.cs | 23 +++++++++ 4 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 UI/Interfaces/MenuUI.cs create mode 100644 UI/Screens/MenuScreen.cs diff --git a/Program.cs b/Program.cs index f51d4cf..c8c2c13 100644 --- a/Program.cs +++ b/Program.cs @@ -17,6 +17,7 @@ internal class Program { + public static bool Running = true; public static bool Paused = false; public static void Main(string[] args) @@ -33,7 +34,7 @@ public static void Main(string[] args) Initialize(); - while (!WindowShouldClose()) + while (Running && !WindowShouldClose()) { Update(); Draw(); @@ -52,7 +53,7 @@ private static void Initialize() WorldIO.AddDeserializerAsBackupable(new BGWorld2Format.Deserializer()); WorldIO.AddDeserializerAsBackupable(new LvlFormat.Deserializer()); - ScreenManager.CurrentScreen = new GameScreen(); + ScreenManager.CurrentScreen = new MenuScreen(); ScreenManager.Initialize(); UIInterfaceManager.Initialize(); diff --git a/UI/Interfaces/MenuUI.cs b/UI/Interfaces/MenuUI.cs new file mode 100644 index 0000000..3ca5c7e --- /dev/null +++ b/UI/Interfaces/MenuUI.cs @@ -0,0 +1,103 @@ +using System.Numerics; +using System.Reflection; +using BuildingGame.UI.Elements; +using BuildingGame.UI.Screens; + +namespace BuildingGame.UI.Interfaces; + +public class MenuUI : UIInterface +{ + private TextElement _title; + private Button _playButton; + private Button _settingsButton; + private Button _packsButton; + private Button _exitButton; + private TextElement _versionText; + + public override void Initialize() + { + _title = new TextElement(new ElementId("menuUi", "title")) + { + TextSize = 36.0f, + Text = "building game rewritten" + }; + Elements.Add(_title); + + _playButton = new Button(new ElementId("menuUi", "playButton")) + { + Text = "play", + TextSize = 24.0f, + Size = new Vector2(100.0f, 28.0f) + }; + _playButton.OnClick += () => + { + ScreenManager.Switch(new GameScreen()); + }; + Elements.Add(_playButton); + + _settingsButton = new Button(new ElementId("menuUi", "settingsButton")) + { + Text = "settings", + TextSize = 24.0f, + Size = new Vector2(100.0f, 28.0f) + }; + Elements.Add(_settingsButton); + + _packsButton = new Button(new ElementId("menuUi", "packsButton")) + { + Text = "packs", + TextSize = 24.0f, + Size = new Vector2(100.0f, 28.0f) + }; + Elements.Add(_packsButton); + + _exitButton = new Button(new ElementId("menuUi", "exitButton")) + { + Text = "exit", + TextSize = 24.0f, + Size = new Vector2(100.0f, 28.0f) + }; + _exitButton.OnClick += () => + { + Program.Running = false; + }; + Elements.Add(_exitButton); + + var version = Assembly.GetExecutingAssembly().GetName().Version ?? new Version(); + + _versionText = new TextElement(new ElementId("menuUi", "versionText")) + { + Text = $"v{version.Major}.{version.Minor}.{version.Revision}", + TextSize = 18.0f, + Size = new Vector2(100.0f, 18.0f) + }; + Elements.Add(_versionText); + + Configure(); + } + + public override void Configure() + { + _title.Position = new Vector2(12, GetYAt(0)); + _playButton.Position = new Vector2(12, GetYAt(1)); + _settingsButton.Position = new Vector2(12, GetYAt(2)); + _packsButton.Position = new Vector2(12, GetYAt(3)); + _exitButton.Position = new Vector2(12, GetYAt(4)); + _versionText.Position = new Vector2(8, GetScreenHeight() - 8 - _versionText.TextSize); + } + + public override void Resized() + { + Configure(); + } + + private float GetYAt(int index) + { + var height = GetScreenHeight(); + + var origin = height / 3.0f + 36.0f; + var indexY = 32.0f * index; + + return origin + indexY; + } +} \ No newline at end of file diff --git a/UI/Interfaces/PauseUI.cs b/UI/Interfaces/PauseUI.cs index 96ae820..57cd7fd 100644 --- a/UI/Interfaces/PauseUI.cs +++ b/UI/Interfaces/PauseUI.cs @@ -1,6 +1,7 @@ using System.Numerics; using BuildingGame.UI.Brushes; using BuildingGame.UI.Elements; +using BuildingGame.UI.Screens; namespace BuildingGame.UI.Interfaces; @@ -61,6 +62,11 @@ public override void Initialize() IgnorePause = true, ZIndex = 101 }; + _menuButton.OnClick += () => + { + Program.Paused = false; + ScreenManager.Switch(new MenuScreen()); + }; Elements.Add(_menuButton); Configure(); diff --git a/UI/Screens/MenuScreen.cs b/UI/Screens/MenuScreen.cs new file mode 100644 index 0000000..6fab343 --- /dev/null +++ b/UI/Screens/MenuScreen.cs @@ -0,0 +1,23 @@ +using BuildingGame.UI.Elements; +using BuildingGame.UI.Interfaces; + +namespace BuildingGame.UI.Screens; + +public class MenuScreen : Screen +{ + private MenuUI _ui; + + public override void Initialize() + { + base.Initialize(); + + _ui = new MenuUI(); + } + + public override void Draw() + { + ClearBackground(new Color(20, 20, 20, 255)); + + base.Draw(); + } +} \ No newline at end of file From 06aee1758a138a25d031e4e2b8cea5a6e70b4f52 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 21:28:49 +0200 Subject: [PATCH 055/107] add character range to textbox --- UI/Elements/TextBox.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/UI/Elements/TextBox.cs b/UI/Elements/TextBox.cs index 0bf5f7d..6d49e33 100644 --- a/UI/Elements/TextBox.cs +++ b/UI/Elements/TextBox.cs @@ -6,6 +6,8 @@ namespace BuildingGame.UI.Elements; public class TextBox : TextElement { public int MaxCharacters = 16; + + public Range CharacterRange = new Range(32, 125); private bool _focused; private OutlineBrush _brush; @@ -39,7 +41,7 @@ private void GatherInput() if (!_focused) return; int c = GetCharPressed(); - if (c is >= 32 and <= 125 && Text.Length < MaxCharacters) + if (c >= CharacterRange.Start.Value && c <= CharacterRange.End.Value && Text.Length < MaxCharacters) Text += char.ConvertFromUtf32(c); From 3224044f12b6022905e621dbdb6f29b6a84d8d9f Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 21:53:15 +0200 Subject: [PATCH 056/107] add extra constructor to elementid --- UI/ElementId.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/UI/ElementId.cs b/UI/ElementId.cs index 722eccd..656abde 100644 --- a/UI/ElementId.cs +++ b/UI/ElementId.cs @@ -7,6 +7,12 @@ public struct ElementId public readonly string? Root; public string Name; + public ElementId(ElementId root, string name) + { + Root = root.ToString(); + Name = name; + } + public ElementId(string root, string name) { Root = root; From a79aa52e92e2760b347e945e56670ff9cb767711 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 22:10:57 +0200 Subject: [PATCH 057/107] no IsKeyPressedRepeat --- Raylib.ExtraMethods.cs | 7 ++++--- UI/Elements/TextBox.cs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Raylib.ExtraMethods.cs b/Raylib.ExtraMethods.cs index 469e595..9dc7ff4 100644 --- a/Raylib.ExtraMethods.cs +++ b/Raylib.ExtraMethods.cs @@ -10,9 +10,10 @@ namespace BuildingGame; /// public static partial class Raylib { - [LibraryImport(NativeLibName, EntryPoint = "IsKeyPressedRepeat")] - public static partial CBool IsKeyPressedRepeat(KeyboardKey key); - + // raylib-cs has rayib 4.5 dll lmao + // [LibraryImport(NativeLibName, EntryPoint = "IsKeyPressedRepeat")] + // public static partial CBool IsKeyPressedRepeat(KeyboardKey key); + // https://github.com/raysan5/raylib/blob/d2b1256e5c3567484486ad70cc2bb69495abfbf4/src/rtext.c#L1108 public static void DrawText(string text, float posX, float posY, float fontSize, Color color) { diff --git a/UI/Elements/TextBox.cs b/UI/Elements/TextBox.cs index 6d49e33..c39848a 100644 --- a/UI/Elements/TextBox.cs +++ b/UI/Elements/TextBox.cs @@ -45,7 +45,7 @@ private void GatherInput() Text += char.ConvertFromUtf32(c); - if (IsKeyPressedRepeat(KeyboardKey.KEY_BACKSPACE) && Text.Length > 0) + if (IsKeyPressed(KeyboardKey.KEY_BACKSPACE) && Text.Length > 0) Text = Text.Remove(Text.Length - 1); } } \ No newline at end of file From c281b2fc7f8c4cd0694c2982a39f1b48827c7cb0 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 23:35:16 +0200 Subject: [PATCH 058/107] add text update event --- UI/Elements/TextBox.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/UI/Elements/TextBox.cs b/UI/Elements/TextBox.cs index c39848a..31c050e 100644 --- a/UI/Elements/TextBox.cs +++ b/UI/Elements/TextBox.cs @@ -8,6 +8,8 @@ public class TextBox : TextElement public int MaxCharacters = 16; public Range CharacterRange = new Range(32, 125); + + public event Action? OnTextUpdate; private bool _focused; private OutlineBrush _brush; @@ -43,9 +45,10 @@ private void GatherInput() int c = GetCharPressed(); if (c >= CharacterRange.Start.Value && c <= CharacterRange.End.Value && Text.Length < MaxCharacters) Text += char.ConvertFromUtf32(c); - if (IsKeyPressed(KeyboardKey.KEY_BACKSPACE) && Text.Length > 0) Text = Text.Remove(Text.Length - 1); + + OnTextUpdate?.Invoke(Text); } } \ No newline at end of file From 8bbe0cb34ae447971573bad542844571be6b48c1 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 23:35:24 +0200 Subject: [PATCH 059/107] add color line --- UI/Elements/ColorLine.cs | 147 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 UI/Elements/ColorLine.cs diff --git a/UI/Elements/ColorLine.cs b/UI/Elements/ColorLine.cs new file mode 100644 index 0000000..5b2ca25 --- /dev/null +++ b/UI/Elements/ColorLine.cs @@ -0,0 +1,147 @@ +using System.Numerics; +using BuildingGame.UI.Brushes; + +namespace BuildingGame.UI.Elements; + +public class ColorLine : Element +{ + public byte R + { + get + { + if (!byte.TryParse(_redBox.Text, out var r)) return 0; + return r; + } + set + { + _redBox.Text = value.ToString(); + ((OutlineBrush)_colorPreview.Brush!).FillColor.R = value; + } + } + + public byte G + { + get + { + if (!byte.TryParse(_greenBox.Text, out var g)) return 0; + return g; + } + set + { + _greenBox.Text = value.ToString(); + ((OutlineBrush)_colorPreview.Brush!).FillColor.G = value; + } + } + + public byte B + { + get + { + if (!byte.TryParse(_blueBox.Text, out var b)) return 0; + return b; + } + set + { + _blueBox.Text = value.ToString(); + ((OutlineBrush)_colorPreview.Brush!).FillColor.B = value; + } + } + + public Color Color + { + get => new Color(R, G, B, (byte)255); + set => (R, G, B) = (value.R, value.G, value.B); + } + + private Panel _colorPreview; + private TextBox _redBox; + private TextBox _greenBox; + private TextBox _blueBox; + + public event Action? OnColorUpdate; + + public ColorLine(ElementId id) : base(id) + { + _colorPreview = new Panel(new ElementId(id, "colorPreview")) + { + Brush = new OutlineBrush(Color.DARKGRAY, Color.WHITE), + Size = new Vector2(40.0f, 20.0f) + }; + _redBox = new TextBox(new ElementId(id, "redBox")) + { + TextSize = 16.0f, + Size = new Vector2(40.0f, 20.0f), + CharacterRange = new Range(48, 57), + Text = "255" + }; + _greenBox = new TextBox(new ElementId(id, "greenBox")) + { + TextSize = 16.0f, + Size = new Vector2(40.0f, 20.0f), + CharacterRange = new Range(48, 57), + Text = "255" + }; + _blueBox = new TextBox(new ElementId(id, "blueBox")) + { + TextSize = 16.0f, + Size = new Vector2(40.0f, 20.0f), + CharacterRange = new Range(48, 57), + Text = "255" + }; + + _redBox.OnTextUpdate += RedBoxOnTextUpdate; + _greenBox.OnTextUpdate += GreenBoxOnTextUpdate; + _blueBox.OnTextUpdate += BlueBoxOnTextUpdate; + + Size = _colorPreview.Size with { X = _colorPreview.Size.X + _redBox.Size.X + _greenBox.Size.X + _blueBox.Size.X + 8 * 3 }; + } + + private void RedBoxOnTextUpdate(string arg2) + { + _ = int.TryParse(arg2, out var r); + r = Math.Clamp(r, 0, 255); + + _redBox.Text = r.ToString(); + ((OutlineBrush)_colorPreview.Brush!).FillColor.R = (byte)r; + + OnColorUpdate?.Invoke(Color); + } + + private void GreenBoxOnTextUpdate(string arg2) + { + _ = int.TryParse(arg2, out var g); + g = Math.Clamp(g, 0, 255); + + _greenBox.Text = g.ToString(); + ((OutlineBrush)_colorPreview.Brush!).FillColor.G = (byte)g; + + OnColorUpdate?.Invoke(Color); + } + + private void BlueBoxOnTextUpdate(string arg2) + { + _ = int.TryParse(arg2, out var b); + b = Math.Clamp(b, 0, 255); + + ((OutlineBrush)_colorPreview.Brush!).FillColor.B = (byte)b; + _blueBox.Text = b.ToString(); + + OnColorUpdate?.Invoke(Color); + } + + public override void Update() + { + _colorPreview.Position = Position + new Vector2(0, Size.Y / 2 - _colorPreview.Size.Y / 2); + _redBox.Position = _colorPreview.Position + new Vector2(_colorPreview.Size.X + 8, 0); + _greenBox.Position = _redBox.Position + new Vector2(+ _redBox.Size.X + 8, 0); + _blueBox.Position = _greenBox.Position + new Vector2(_greenBox.Size.X + 8, 0); + + _colorPreview.Visible = _redBox.Visible = _greenBox.Visible = _blueBox.Visible = Visible; + _colorPreview.Active = _redBox.Active = _greenBox.Active = _blueBox.Active = Active; + } + + protected override void Render() + { + + } +} \ No newline at end of file From 9fd62a96d199e017b2714cc8d565df374d65a1f2 Mon Sep 17 00:00:00 2001 From: danil Date: Sun, 14 Jan 2024 23:35:31 +0200 Subject: [PATCH 060/107] add settings --- Program.cs | 4 +++ Settings.cs | 55 +++++++++++++++++++++++++++++++++++ UI/Interfaces/MenuUI.cs | 5 ++++ UI/Interfaces/PauseUI.cs | 8 ++++-- UI/Interfaces/SettingsUI.cs | 57 +++++++++++++++++++++++++++++++++++++ UI/Screens/GameScreen.cs | 2 +- 6 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 Settings.cs create mode 100644 UI/Interfaces/SettingsUI.cs diff --git a/Program.cs b/Program.cs index c8c2c13..b3172d3 100644 --- a/Program.cs +++ b/Program.cs @@ -46,6 +46,8 @@ public static void Main(string[] args) private static void Initialize() { + Settings.Load(); + BGWorld21Format.Register(); BGWorld2Format.Register(); LvlFormat.Register(); @@ -78,6 +80,8 @@ private static void Closing() { ScreenManager.Free(); UIInterfaceManager.Destroy(); + + Settings.Save(); Resources.Free(); } diff --git a/Settings.cs b/Settings.cs new file mode 100644 index 0000000..7cf3f6e --- /dev/null +++ b/Settings.cs @@ -0,0 +1,55 @@ +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; + +namespace BuildingGame; + +public static class Settings +{ + public record struct Record(Color SkyColor); + + public const string SettingsFile = "Settings.yaml"; + + private static readonly IDeserializer _deserializer = new DeserializerBuilder() + .WithNamingConvention(UnderscoredNamingConvention.Instance) + .Build(); + + private static readonly ISerializer _serializer = new SerializerBuilder() + .WithNamingConvention(UnderscoredNamingConvention.Instance) + .Build(); + + public static Color SkyColor = Color.SKYBLUE; + + public static void Load() + { + try + { + var content = File.ReadAllText(SettingsFile); + var record = _deserializer.Deserialize(content); + + SkyColor = record.SkyColor; + } + catch (FileNotFoundException) + { + Console.WriteLine("no " + SettingsFile); + } + catch (Exception ex) + { + Console.WriteLine("whoops: " + ex.ToString()); + } + } + + public static void Save() + { + try + { + var record = new Record(SkyColor); + + var content = _serializer.Serialize(record); + File.WriteAllText(SettingsFile, content); + } + catch (Exception ex) + { + Console.WriteLine("whoops: " + ex); + } + } +} \ No newline at end of file diff --git a/UI/Interfaces/MenuUI.cs b/UI/Interfaces/MenuUI.cs index 3ca5c7e..65d3d6b 100644 --- a/UI/Interfaces/MenuUI.cs +++ b/UI/Interfaces/MenuUI.cs @@ -13,6 +13,7 @@ public class MenuUI : UIInterface private Button _packsButton; private Button _exitButton; private TextElement _versionText; + private SettingsUI _settingsUi = new SettingsUI(); public override void Initialize() { @@ -41,6 +42,10 @@ public override void Initialize() TextSize = 24.0f, Size = new Vector2(100.0f, 28.0f) }; + _settingsButton.OnClick += () => + { + _settingsUi.Visible = !_settingsUi.Visible; + }; Elements.Add(_settingsButton); _packsButton = new Button(new ElementId("menuUi", "packsButton")) diff --git a/UI/Interfaces/PauseUI.cs b/UI/Interfaces/PauseUI.cs index 57cd7fd..f66e702 100644 --- a/UI/Interfaces/PauseUI.cs +++ b/UI/Interfaces/PauseUI.cs @@ -12,6 +12,8 @@ public class PauseUI : UIInterface private Button _menuButton; private Button _settingsButton; + private SettingsUI _settingsUi = new SettingsUI(); + public PauseUI() { IgnorePause = true; @@ -19,8 +21,6 @@ public PauseUI() public override void Initialize() { - base.Initialize(); - _background = new Panel(new ElementId("pauseScreen", "background")) { Brush = new GradientBrush(Color.BLANK, Color.BLACK), @@ -52,6 +52,10 @@ public override void Initialize() IgnorePause = true, ZIndex = 101 }; + _settingsButton.OnClick += () => + { + _settingsUi.Visible = !_settingsUi.Visible; + }; Elements.Add(_settingsButton); _menuButton = new Button(new ElementId("pauseScreen", "menuButton")) diff --git a/UI/Interfaces/SettingsUI.cs b/UI/Interfaces/SettingsUI.cs new file mode 100644 index 0000000..cc7190d --- /dev/null +++ b/UI/Interfaces/SettingsUI.cs @@ -0,0 +1,57 @@ +using System.Numerics; +using BuildingGame.UI.Brushes; +using BuildingGame.UI.Elements; + +namespace BuildingGame.UI.Interfaces; + +public class SettingsUI : UIInterface +{ + private Panel _background; + private TextElement _skyColorLineText; + private ColorLine _skyColorLine; + + public override void Initialize() + { + _background = new Panel(new ElementId("settings", "background")) + { + Brush = new SolidBrush(new Color(0, 0, 0, 100)), + ZIndex = 200 + }; + Elements.Add(_background); + + _skyColorLineText = new TextElement(new ElementId("settings", "skyColorLineText")) + { + Text = "sky color (RGB): ", + Size = new Vector2(128.0f, 20.0f), + TextSize = 16.0f, + ZIndex = 201 + }; + Elements.Add(_skyColorLineText); + + _skyColorLine = new ColorLine(new ElementId("settings", "skyColorLine")) + { + ZIndex = 201 + }; + _skyColorLine.Color = Settings.SkyColor; + _skyColorLine.OnColorUpdate += color => + { + Settings.SkyColor = color; + }; + Elements.Add(_skyColorLine); + + Configure(); + Visible = false; + } + + public override void Resized() + { + Configure(); + } + + public override void Configure() + { + _background.Area = new Rectangle(50.0f, 50.0f, GetScreenWidth() - 100.0f, GetScreenHeight() - 100.0f); + _skyColorLineText.Position = _background.Position + new Vector2(8.0f, 16.0f); + _skyColorLine.Position = _skyColorLineText.Position + _skyColorLineText.Size with { Y = 0 } + new Vector2(16.0f, 2.0f); + } +} \ No newline at end of file diff --git a/UI/Screens/GameScreen.cs b/UI/Screens/GameScreen.cs index f7ae2c3..3858ff9 100644 --- a/UI/Screens/GameScreen.cs +++ b/UI/Screens/GameScreen.cs @@ -41,7 +41,7 @@ public override void Update() public override void Draw() { - ClearBackground(Color.SKYBLUE); + ClearBackground(Settings.SkyColor); BeginMode2D(_player.Camera); { From d363e4d9650f086ecdacfd460e20d34514a48850 Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 15 Jan 2024 08:36:38 +0200 Subject: [PATCH 061/107] IsUnderMouse sounds better --- UI/Element.cs | 6 +++--- UI/Elements/Button.cs | 4 ++-- UI/Elements/ListBox.cs | 2 +- UI/Elements/TextBox.cs | 2 +- UI/GuiManager.cs | 4 ++-- UI/Interfaces/BlockUI.cs | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/UI/Element.cs b/UI/Element.cs index 35359bd..fbb9998 100644 --- a/UI/Element.cs +++ b/UI/Element.cs @@ -95,19 +95,19 @@ protected virtual void Render() DrawText(":(", 0, 0, 16, Color.WHITE); } - public bool IsHovered() + public bool IsUnderMouse() { return CheckCollisionPointRec(GetMousePosition(), Area) && Visible && Active; } public bool IsClicked() { - return IsHovered() && IsMouseButtonReleased(MouseButton.MOUSE_BUTTON_LEFT) && Visible && Active; + return IsUnderMouse() && IsMouseButtonReleased(MouseButton.MOUSE_BUTTON_LEFT) && Visible && Active; } public bool IsPressed() { - return IsHovered() && IsMouseButtonDown(MouseButton.MOUSE_BUTTON_LEFT) && Visible && Active; + return IsUnderMouse() && IsMouseButtonDown(MouseButton.MOUSE_BUTTON_LEFT) && Visible && Active; } public void Dispose() diff --git a/UI/Elements/Button.cs b/UI/Elements/Button.cs index 9a5b9af..d6470d9 100644 --- a/UI/Elements/Button.cs +++ b/UI/Elements/Button.cs @@ -20,11 +20,11 @@ public override void Update() OnClick?.Invoke(); } - if (ShowHoverText && IsHovered() && !Text.StartsWith(HoverText)) + if (ShowHoverText && IsUnderMouse() && !Text.StartsWith(HoverText)) { Text = HoverText + Text; } - else if (!IsHovered() && Text.StartsWith(HoverText)) + else if (!IsUnderMouse() && Text.StartsWith(HoverText)) { Text = Text.Replace(HoverText, null); } diff --git a/UI/Elements/ListBox.cs b/UI/Elements/ListBox.cs index cf5040d..2731e45 100644 --- a/UI/Elements/ListBox.cs +++ b/UI/Elements/ListBox.cs @@ -28,7 +28,7 @@ public ListBox(ElementId id) : base(id) public override void Update() { - if (IsHovered()) + if (IsUnderMouse()) { // finding index for highlight float localMouseY = GetMousePosition().Y - Position.Y; diff --git a/UI/Elements/TextBox.cs b/UI/Elements/TextBox.cs index 31c050e..a83e399 100644 --- a/UI/Elements/TextBox.cs +++ b/UI/Elements/TextBox.cs @@ -26,7 +26,7 @@ public override void Update() if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT)) { - _focused = IsHovered(); + _focused = IsUnderMouse(); _brush.LineColor = _focused ? Color.GRAY : Color.BLACK; // _brush.LineThick = _focused ? 1.5f : 1; diff --git a/UI/GuiManager.cs b/UI/GuiManager.cs index 51b6e35..118d9c6 100644 --- a/UI/GuiManager.cs +++ b/UI/GuiManager.cs @@ -52,7 +52,7 @@ public static bool IsMouseOverElement() if (ScreenManager.CurrentScreen == null) return false; var elements = ScreenManager.CurrentScreen.ElementsSorted; - return elements.Any(element => element.Visible && element.Active && element.IsHovered()); + return elements.Any(element => element.Visible && element.Active && element.IsUnderMouse()); } public static Element? GetElementUnderMouse() @@ -60,7 +60,7 @@ public static bool IsMouseOverElement() if (ScreenManager.CurrentScreen == null) return null; var elements = ScreenManager.CurrentScreen.ElementsSorted; - return elements.FirstOrDefault(el => el.IsHovered()); + return elements.FirstOrDefault(el => el.IsUnderMouse()); } [Obsolete("Use ScreenManager.Draw instead")] diff --git a/UI/Interfaces/BlockUI.cs b/UI/Interfaces/BlockUI.cs index 1898fe9..41b5c18 100644 --- a/UI/Interfaces/BlockUI.cs +++ b/UI/Interfaces/BlockUI.cs @@ -121,7 +121,7 @@ public override void Update() base.Update(); if (IsKeyPressed(KeyboardKey.KEY_B)) Visible = !Visible; - if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT) && !_background.IsHovered() && + if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT) && !_background.IsUnderMouse() && GuiManager.GetElementUnderMouse()?.Id != "gameHud::tileMenuButton") // 🤟😏 Visible = false; } From c38292cef2218d0563a6b576658a17f275706629 Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 15 Jan 2024 08:42:00 +0200 Subject: [PATCH 062/107] add reset button to colorline --- UI/Elements/ColorLine.cs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/UI/Elements/ColorLine.cs b/UI/Elements/ColorLine.cs index 5b2ca25..ba0e7e3 100644 --- a/UI/Elements/ColorLine.cs +++ b/UI/Elements/ColorLine.cs @@ -52,11 +52,14 @@ public Color Color get => new Color(R, G, B, (byte)255); set => (R, G, B) = (value.R, value.G, value.B); } + + public Color DefaultColor = Color.WHITE; private Panel _colorPreview; private TextBox _redBox; private TextBox _greenBox; private TextBox _blueBox; + private Button _resetButton; public event Action? OnColorUpdate; @@ -64,7 +67,7 @@ public ColorLine(ElementId id) : base(id) { _colorPreview = new Panel(new ElementId(id, "colorPreview")) { - Brush = new OutlineBrush(Color.DARKGRAY, Color.WHITE), + Brush = new OutlineBrush(Color.DARKGRAY, DefaultColor), Size = new Vector2(40.0f, 20.0f) }; _redBox = new TextBox(new ElementId(id, "redBox")) @@ -72,21 +75,32 @@ public ColorLine(ElementId id) : base(id) TextSize = 16.0f, Size = new Vector2(40.0f, 20.0f), CharacterRange = new Range(48, 57), - Text = "255" + Text = DefaultColor.R.ToString() }; _greenBox = new TextBox(new ElementId(id, "greenBox")) { TextSize = 16.0f, Size = new Vector2(40.0f, 20.0f), CharacterRange = new Range(48, 57), - Text = "255" + Text = DefaultColor.G.ToString() }; _blueBox = new TextBox(new ElementId(id, "blueBox")) { TextSize = 16.0f, Size = new Vector2(40.0f, 20.0f), CharacterRange = new Range(48, 57), - Text = "255" + Text = DefaultColor.B.ToString() + }; + _resetButton = new Button(new ElementId(id, "resetButton")) + { + TextSize = 16.0f, + Size = new Vector2(64.0f, 20.0f), + Text = "reset", + ShowHoverText = false + }; + _resetButton.OnClick += () => + { + Color = DefaultColor; }; _redBox.OnTextUpdate += RedBoxOnTextUpdate; @@ -135,9 +149,10 @@ public override void Update() _redBox.Position = _colorPreview.Position + new Vector2(_colorPreview.Size.X + 8, 0); _greenBox.Position = _redBox.Position + new Vector2(+ _redBox.Size.X + 8, 0); _blueBox.Position = _greenBox.Position + new Vector2(_greenBox.Size.X + 8, 0); + _resetButton.Position = _blueBox.Position + new Vector2(_blueBox.Size.X + 8, 0); - _colorPreview.Visible = _redBox.Visible = _greenBox.Visible = _blueBox.Visible = Visible; - _colorPreview.Active = _redBox.Active = _greenBox.Active = _blueBox.Active = Active; + _colorPreview.Visible = _redBox.Visible = _greenBox.Visible = _blueBox.Visible = _resetButton.Visible = Visible; + _colorPreview.Active = _redBox.Active = _greenBox.Active = _blueBox.Active = _resetButton.Active = Active; } protected override void Render() From 71e4b320b3169e48bbc6bef7f561adb82395c86f Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 15 Jan 2024 08:42:57 +0200 Subject: [PATCH 063/107] set SKYBLUE as reset color for sky --- UI/Interfaces/SettingsUI.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/UI/Interfaces/SettingsUI.cs b/UI/Interfaces/SettingsUI.cs index cc7190d..7b65ef8 100644 --- a/UI/Interfaces/SettingsUI.cs +++ b/UI/Interfaces/SettingsUI.cs @@ -30,9 +30,10 @@ public override void Initialize() _skyColorLine = new ColorLine(new ElementId("settings", "skyColorLine")) { - ZIndex = 201 + ZIndex = 201, + Color = Settings.SkyColor, + DefaultColor = Color.SKYBLUE }; - _skyColorLine.Color = Settings.SkyColor; _skyColorLine.OnColorUpdate += color => { Settings.SkyColor = color; From 2cd6cfa73c1f8e96b9bd1dc46d9fce0b3805e5be Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 15 Jan 2024 08:55:46 +0200 Subject: [PATCH 064/107] add custom predicates for *ElementUnderMouse methods --- UI/GuiManager.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/UI/GuiManager.cs b/UI/GuiManager.cs index 118d9c6..1209d49 100644 --- a/UI/GuiManager.cs +++ b/UI/GuiManager.cs @@ -48,19 +48,29 @@ public static void Remove(ElementId id) } public static bool IsMouseOverElement() + { + return IsMouseOverElement(el => el.IsUnderMouse()); + } + + public static bool IsMouseOverElement(Func predicate) { if (ScreenManager.CurrentScreen == null) return false; var elements = ScreenManager.CurrentScreen.ElementsSorted; - return elements.Any(element => element.Visible && element.Active && element.IsUnderMouse()); + return elements.Any(predicate); } public static Element? GetElementUnderMouse() + { + return GetElementUnderMouse(el => el.IsUnderMouse()); + } + + public static Element? GetElementUnderMouse(Func predicate) { if (ScreenManager.CurrentScreen == null) return null; var elements = ScreenManager.CurrentScreen.ElementsSorted; - return elements.FirstOrDefault(el => el.IsUnderMouse()); + return elements.FirstOrDefault(predicate); } [Obsolete("Use ScreenManager.Draw instead")] From 2f2f782c14fd98c3032948288de33b9590490c13 Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 15 Jan 2024 08:57:53 +0200 Subject: [PATCH 065/107] update tooltip code --- UI/Elements/Tooltip.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/UI/Elements/Tooltip.cs b/UI/Elements/Tooltip.cs index 023c764..c248d8c 100644 --- a/UI/Elements/Tooltip.cs +++ b/UI/Elements/Tooltip.cs @@ -14,16 +14,12 @@ public override void Update() { base.Update(); - Element? el = GuiManager.GetElementUnderMouse(); + Element? el = GuiManager.GetElementUnderMouse(el => el.IsUnderMouse() && !string.IsNullOrWhiteSpace(el.TooltipText)); - if (el != null && el.TooltipText != string.Empty) + if (el != null) { Text = el.TooltipText; Visible = true; - - Vector2 measure = MeasureTextEx(GuiManager.Font, Text, TextSize, TextSize / GuiManager.FontSize); - Vector2 size = measure + new Vector2(Padding * 4, Padding * 2); - if (Size != size) Size = size; } else Visible = false; From 2fad2963846455a9b8f950f526e3765f5b722bfd Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 15 Jan 2024 09:58:29 +0200 Subject: [PATCH 066/107] dont update render texture if size is same --- UI/Element.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/UI/Element.cs b/UI/Element.cs index fbb9998..885575f 100644 --- a/UI/Element.cs +++ b/UI/Element.cs @@ -27,7 +27,12 @@ public Vector2 Position public Vector2 Size { get => new Vector2(_Area.Width, _Area.Height); - set => Area = new Rectangle(_Area.X, _Area.Y, value.X, value.Y); + set + { + if (value == new Vector2(Area.Width, Area.Height)) return; + + Area = new Rectangle(_Area.X, _Area.Y, value.X, value.Y); + } } public ElementId Id; From bdd615ef4fc1960238f52f9aad1b9693af0f6a0f Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 15 Jan 2024 10:53:17 +0200 Subject: [PATCH 067/107] make tooltip work like in original --- UI/Elements/Tooltip.cs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/UI/Elements/Tooltip.cs b/UI/Elements/Tooltip.cs index c248d8c..4ac6084 100644 --- a/UI/Elements/Tooltip.cs +++ b/UI/Elements/Tooltip.cs @@ -1,13 +1,18 @@ using System.Numerics; +using BuildingGame.UI.Brushes; namespace BuildingGame.UI.Elements; -public class Tooltip : TextElement +public class Tooltip : Element { + public string Text; + public float TextSize; + private GradientBrush _brush; + public Tooltip(ElementId id) : base(id) { + _brush = new GradientBrush(new Color(0, 0, 0, 50), new Color(16, 0, 16, 127)); Visible = false; - TextAlignment = Alignment.CenterLeft; } public override void Update() @@ -23,6 +28,16 @@ public override void Update() } else Visible = false; - Position = GetMousePosition() + new Vector2(16); + var pos = GetMousePosition() + new Vector2(0, 16); + var size = MeasureTextEx(GetFontDefault(), Text, TextSize, GetSpacing(TextSize)); + + Position = pos with { X = pos.X - 16.0f }; + Size = size + new Vector2(16); + } + + protected override void Render() + { + _brush.FillArea(new Rectangle(0, 0, Size.X, Size.Y)); + DrawText(Text, 8.0f, 8.0f, TextSize, Color.WHITE); } } \ No newline at end of file From 728d82095894aa20af1547a6c6c694b515e71eaa Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 15 Jan 2024 10:53:29 +0200 Subject: [PATCH 068/107] add tooltip to the game --- UI/Interfaces/BlockUI.cs | 4 +++- UI/Interfaces/GameUI.cs | 12 ++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/UI/Interfaces/BlockUI.cs b/UI/Interfaces/BlockUI.cs index 41b5c18..ed6152a 100644 --- a/UI/Interfaces/BlockUI.cs +++ b/UI/Interfaces/BlockUI.cs @@ -60,7 +60,9 @@ public override void Initialize() Tile.TileSize ) }, - ShowHoverText = false + ShowHoverText = false, + TooltipText = tiles[i].TexCoord.ToString(), + ZIndex = (short)(_background.ZIndex + 1) }; Elements.Add(_tileButtons[i]); diff --git a/UI/Interfaces/GameUI.cs b/UI/Interfaces/GameUI.cs index e595db6..9b22b7f 100644 --- a/UI/Interfaces/GameUI.cs +++ b/UI/Interfaces/GameUI.cs @@ -1,4 +1,5 @@ -using BuildingGame.Tiles; +using System.Numerics; +using BuildingGame.Tiles; using BuildingGame.UI.Brushes; using BuildingGame.UI.Elements; @@ -10,6 +11,7 @@ public class GameUI : UIInterface private const float TileButtonSize = Tile.RealTileSize * 2; private BlockUI _blockUi; + private Tooltip _tooltip; private Button _tileMenuButton = null!; @@ -34,9 +36,15 @@ public override void Initialize() { _blockUi.Visible = !_blockUi.Visible; }; - Elements.Add(_tileMenuButton); + _tooltip = new Tooltip(new ElementId("gameHud", "tooltip")) + { + TextSize = 16.0f, + Size = new Vector2(0.0f, 36.0f), + }; + Elements.Add(_tooltip); + Configure(); } From 35fa18a895d5b1fea3884c635548b83d8a08c844 Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 15 Jan 2024 12:25:50 +0200 Subject: [PATCH 069/107] implement translation --- Translation/TranslationContainer.cs | 33 +++++++++++++++++++++++++++++ Translation/TranslationLoader.cs | 28 ++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 Translation/TranslationContainer.cs create mode 100644 Translation/TranslationLoader.cs diff --git a/Translation/TranslationContainer.cs b/Translation/TranslationContainer.cs new file mode 100644 index 0000000..c4833a0 --- /dev/null +++ b/Translation/TranslationContainer.cs @@ -0,0 +1,33 @@ +namespace BuildingGame.Translation; + +public readonly struct TranslationContainer +{ + private static TranslationContainer _default; + + public static TranslationContainer Default + { + get + { + if (!_default.IsEmpty()) return _default; + + TranslationLoader.TryLoadTranslation(TranslationLoader.DefaultTranslationPath, out _default); + return _default; + } + } + private readonly Dictionary _translations = new Dictionary(); + + public TranslationContainer(Dictionary translations) + { + _translations = translations; + } + + public string GetTranslatedName(string name) + { + return _translations.GetValueOrDefault(name) ?? name; + } + + public bool IsEmpty() + { + return _translations == null || _translations.Count < 1; + } +} \ No newline at end of file diff --git a/Translation/TranslationLoader.cs b/Translation/TranslationLoader.cs new file mode 100644 index 0000000..f61d488 --- /dev/null +++ b/Translation/TranslationLoader.cs @@ -0,0 +1,28 @@ +using System.Diagnostics.CodeAnalysis; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; + +namespace BuildingGame.Translation; + +public static class TranslationLoader +{ + public const string DefaultTranslationPath = "Assets/Translation.yaml"; + + private static readonly IDeserializer _yaml = new DeserializerBuilder() + .WithNamingConvention(UnderscoredNamingConvention.Instance) + .IgnoreUnmatchedProperties() + .Build(); + + public static bool TryLoadTranslation(string path, out TranslationContainer translation) + { + translation = new TranslationContainer(); + + if (!File.Exists(path)) return false; + + var content = File.ReadAllText(path); + var translationMap = _yaml.Deserialize>(content); + translation = new TranslationContainer(translationMap); + + return true; + } +} \ No newline at end of file From 26adbfd3b581684d62870c26a3a2ce99dfd3ab36 Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 15 Jan 2024 12:26:06 +0200 Subject: [PATCH 070/107] add translation for tiles --- Assets/Translation.yaml | 50 ++++++++++++++++++++++++++++++++++++++ Tiles/Atlas/AtlasLoader.cs | 2 +- Tiles/Tile.cs | 8 ++++++ Tiles/Tiles.cs | 3 ++- UI/Interfaces/BlockUI.cs | 3 ++- 5 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 Assets/Translation.yaml diff --git a/Assets/Translation.yaml b/Assets/Translation.yaml new file mode 100644 index 0000000..2c02463 --- /dev/null +++ b/Assets/Translation.yaml @@ -0,0 +1,50 @@ +# layer 0 (x: 0-9, y: 0) +smooth_stone: "Smooth Stone" +wooden_planks: "Wooden Planks" +dirt: "Dirt" +grass_block: "Grass Block" +grass: "Grass" +sand: "Sand" +water: "Water" +lava: "Lava" +obsidian: "Obsidian" +door: "Door" + +# layer 1 (x: 0-8, y: 1) +nature_stone: "Nature Stone" +white_plate: "White Plate" +green_plate: "Green Plate" +red_plate: "Red Plate" +blue_plate: "Blue Plate" +chamomile: "Chamomile" +red_tulip: "Red Tulip" +chamomile_pot: "Chamomile in a Pot" +red_tulip_pot: "Red Tulip in a Pot" + +# layer 2 (x: 0-9, y: 2) +wooden_stairs: "Wooden Stairs" +wooden_slab: "Wooden Slab" +stone_stairs: "Stone Stairs" +stone_slab: "Stone Slab" +wooden_pole: "Wooden Pole" +wooden_pole_handle: "Wooden Pole Handle" +stone_pole: "Stone Pole" +stone_pole_handle: "Stone Pole Handle" +log: "Log" +log_top: "Log Top" + +# layer 3 (x: 0-9, y: 3) +foliage: "Foliage" +glass: "Glass" +white_wool: "White Wool" +red_wool: "Red Wool" +green_wool: "Green Wool" +blue_wool: "Blue Wool" +yellow_wool: "Yellow Wool" +black_wool: "Black Wool" +dark_gray_wool: "Dark Gray Wool" +gray_wool: "Gray Wool" + +# layer 4 (x: 0-1, y: 4) +sponge: "Sponge" +infection_block: "Infection Block" \ No newline at end of file diff --git a/Tiles/Atlas/AtlasLoader.cs b/Tiles/Atlas/AtlasLoader.cs index 37396e1..2a83a42 100644 --- a/Tiles/Atlas/AtlasLoader.cs +++ b/Tiles/Atlas/AtlasLoader.cs @@ -30,7 +30,7 @@ public static Dictionary ConvertTiles(Dictionary Date: Mon, 15 Jan 2024 12:36:01 +0200 Subject: [PATCH 071/107] localize ui --- Assets/Translation.yaml | 20 +++++++++++++++++++- UI/Elements/ColorLine.cs | 5 ++++- UI/Interfaces/BlockUI.cs | 6 ++++-- UI/Interfaces/MenuUI.cs | 15 +++++++++------ UI/Interfaces/PauseUI.cs | 9 ++++++--- UI/Interfaces/SettingsUI.cs | 5 ++++- 6 files changed, 46 insertions(+), 14 deletions(-) diff --git a/Assets/Translation.yaml b/Assets/Translation.yaml index 2c02463..e0cbaab 100644 --- a/Assets/Translation.yaml +++ b/Assets/Translation.yaml @@ -47,4 +47,22 @@ gray_wool: "Gray Wool" # layer 4 (x: 0-1, y: 4) sponge: "Sponge" -infection_block: "Infection Block" \ No newline at end of file +infection_block: "Infection Block" + +# UI +title: "building game rewritten" +version_format: "v{0}.{1}.{2}" # {0} - major, {1} - minor, {2} - revision + +play_button: "play" +settings_button: "settings" +packs_button: "packs" +exit_button: "exit" + +sky_color_line: "sky color (RGB): " + +resume_button: "resume" +menu_button: "menu" + +block_ui_title: "Select a tile" + +reset_button: "reset" \ No newline at end of file diff --git a/UI/Elements/ColorLine.cs b/UI/Elements/ColorLine.cs index ba0e7e3..8218f20 100644 --- a/UI/Elements/ColorLine.cs +++ b/UI/Elements/ColorLine.cs @@ -1,4 +1,5 @@ using System.Numerics; +using BuildingGame.Translation; using BuildingGame.UI.Brushes; namespace BuildingGame.UI.Elements; @@ -65,6 +66,8 @@ public Color Color public ColorLine(ElementId id) : base(id) { + var translation = TranslationContainer.Default; + _colorPreview = new Panel(new ElementId(id, "colorPreview")) { Brush = new OutlineBrush(Color.DARKGRAY, DefaultColor), @@ -95,7 +98,7 @@ public ColorLine(ElementId id) : base(id) { TextSize = 16.0f, Size = new Vector2(64.0f, 20.0f), - Text = "reset", + Text = translation.GetTranslatedName("reset_button"), ShowHoverText = false }; _resetButton.OnClick += () => diff --git a/UI/Interfaces/BlockUI.cs b/UI/Interfaces/BlockUI.cs index e3395d0..d6d5556 100644 --- a/UI/Interfaces/BlockUI.cs +++ b/UI/Interfaces/BlockUI.cs @@ -15,6 +15,8 @@ public class BlockUI : UIInterface public override void Initialize() { base.Initialize(); + + var translation = TranslationContainer.Default; _background = new Panel(new ElementId("blockMenu", "background")) { @@ -25,7 +27,7 @@ public override void Initialize() _menuTitle = new TextElement(new ElementId("blockMenu", "title")) { - Text = "Select a tile", + Text = translation.GetTranslatedName("block_ui_title"), TextColor = Color.WHITE, TextSize = 32, TextAlignment = Alignment.Center @@ -62,7 +64,7 @@ public override void Initialize() ) }, ShowHoverText = false, - TooltipText = TranslationContainer.Default.GetTranslatedName(tiles[i].TranslationKey), + TooltipText = translation.GetTranslatedName(tiles[i].TranslationKey), ZIndex = (short)(_background.ZIndex + 1) }; diff --git a/UI/Interfaces/MenuUI.cs b/UI/Interfaces/MenuUI.cs index 65d3d6b..b92a882 100644 --- a/UI/Interfaces/MenuUI.cs +++ b/UI/Interfaces/MenuUI.cs @@ -1,5 +1,6 @@ using System.Numerics; using System.Reflection; +using BuildingGame.Translation; using BuildingGame.UI.Elements; using BuildingGame.UI.Screens; @@ -17,16 +18,18 @@ public class MenuUI : UIInterface public override void Initialize() { + var translation = TranslationContainer.Default; + _title = new TextElement(new ElementId("menuUi", "title")) { TextSize = 36.0f, - Text = "building game rewritten" + Text = translation.GetTranslatedName("title") }; Elements.Add(_title); _playButton = new Button(new ElementId("menuUi", "playButton")) { - Text = "play", + Text = translation.GetTranslatedName("play_button"), TextSize = 24.0f, Size = new Vector2(100.0f, 28.0f) }; @@ -38,7 +41,7 @@ public override void Initialize() _settingsButton = new Button(new ElementId("menuUi", "settingsButton")) { - Text = "settings", + Text = translation.GetTranslatedName("settings_button"), TextSize = 24.0f, Size = new Vector2(100.0f, 28.0f) }; @@ -50,7 +53,7 @@ public override void Initialize() _packsButton = new Button(new ElementId("menuUi", "packsButton")) { - Text = "packs", + Text = translation.GetTranslatedName("packs_button"), TextSize = 24.0f, Size = new Vector2(100.0f, 28.0f) }; @@ -58,7 +61,7 @@ public override void Initialize() _exitButton = new Button(new ElementId("menuUi", "exitButton")) { - Text = "exit", + Text = translation.GetTranslatedName("exit_button"), TextSize = 24.0f, Size = new Vector2(100.0f, 28.0f) }; @@ -72,7 +75,7 @@ public override void Initialize() _versionText = new TextElement(new ElementId("menuUi", "versionText")) { - Text = $"v{version.Major}.{version.Minor}.{version.Revision}", + Text = string.Format(translation.GetTranslatedName("version_format"), version.Major, version.Minor, version.Revision), TextSize = 18.0f, Size = new Vector2(100.0f, 18.0f) }; diff --git a/UI/Interfaces/PauseUI.cs b/UI/Interfaces/PauseUI.cs index f66e702..f5866f4 100644 --- a/UI/Interfaces/PauseUI.cs +++ b/UI/Interfaces/PauseUI.cs @@ -1,4 +1,5 @@ using System.Numerics; +using BuildingGame.Translation; using BuildingGame.UI.Brushes; using BuildingGame.UI.Elements; using BuildingGame.UI.Screens; @@ -21,6 +22,8 @@ public PauseUI() public override void Initialize() { + var translation = TranslationContainer.Default; + _background = new Panel(new ElementId("pauseScreen", "background")) { Brush = new GradientBrush(Color.BLANK, Color.BLACK), @@ -31,7 +34,7 @@ public override void Initialize() _resumeButton = new Button(new ElementId("pauseScreen", "resumeButton")) { - Text = "resume", + Text = translation.GetTranslatedName("resume_button"), TextSize = 24, TextAlignment = Alignment.CenterLeft, IgnorePause = true, @@ -46,7 +49,7 @@ public override void Initialize() _settingsButton = new Button(new ElementId("pauseScreen", "settingsButton")) { - Text = "settings", + Text = translation.GetTranslatedName("settings_button"), TextSize = 24, TextAlignment = Alignment.CenterLeft, IgnorePause = true, @@ -60,7 +63,7 @@ public override void Initialize() _menuButton = new Button(new ElementId("pauseScreen", "menuButton")) { - Text = "menu", + Text = translation.GetTranslatedName("menu_button"), TextSize = 24, TextAlignment = Alignment.CenterLeft, IgnorePause = true, diff --git a/UI/Interfaces/SettingsUI.cs b/UI/Interfaces/SettingsUI.cs index 7b65ef8..b8dde93 100644 --- a/UI/Interfaces/SettingsUI.cs +++ b/UI/Interfaces/SettingsUI.cs @@ -1,4 +1,5 @@ using System.Numerics; +using BuildingGame.Translation; using BuildingGame.UI.Brushes; using BuildingGame.UI.Elements; @@ -12,6 +13,8 @@ public class SettingsUI : UIInterface public override void Initialize() { + var translation = TranslationContainer.Default; + _background = new Panel(new ElementId("settings", "background")) { Brush = new SolidBrush(new Color(0, 0, 0, 100)), @@ -21,7 +24,7 @@ public override void Initialize() _skyColorLineText = new TextElement(new ElementId("settings", "skyColorLineText")) { - Text = "sky color (RGB): ", + Text = translation.GetTranslatedName("sky_color_line"), Size = new Vector2(128.0f, 20.0f), TextSize = 16.0f, ZIndex = 201 From 900c0dc50d94e06d6c3044ce93873a9c5b2f1868 Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 15 Jan 2024 13:00:32 +0200 Subject: [PATCH 072/107] fix zindex on colorline --- UI/Elements/ColorLine.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/UI/Elements/ColorLine.cs b/UI/Elements/ColorLine.cs index 8218f20..90e0203 100644 --- a/UI/Elements/ColorLine.cs +++ b/UI/Elements/ColorLine.cs @@ -71,35 +71,40 @@ public ColorLine(ElementId id) : base(id) _colorPreview = new Panel(new ElementId(id, "colorPreview")) { Brush = new OutlineBrush(Color.DARKGRAY, DefaultColor), - Size = new Vector2(40.0f, 20.0f) + Size = new Vector2(40.0f, 20.0f), + ZIndex = (short)(ZIndex + 1) }; _redBox = new TextBox(new ElementId(id, "redBox")) { TextSize = 16.0f, Size = new Vector2(40.0f, 20.0f), CharacterRange = new Range(48, 57), - Text = DefaultColor.R.ToString() + Text = DefaultColor.R.ToString(), + ZIndex = (short)(ZIndex + 1) }; _greenBox = new TextBox(new ElementId(id, "greenBox")) { TextSize = 16.0f, Size = new Vector2(40.0f, 20.0f), CharacterRange = new Range(48, 57), - Text = DefaultColor.G.ToString() + Text = DefaultColor.G.ToString(), + ZIndex = (short)(ZIndex + 1) }; _blueBox = new TextBox(new ElementId(id, "blueBox")) { TextSize = 16.0f, Size = new Vector2(40.0f, 20.0f), CharacterRange = new Range(48, 57), - Text = DefaultColor.B.ToString() + Text = DefaultColor.B.ToString(), + ZIndex = (short)(ZIndex + 1) }; _resetButton = new Button(new ElementId(id, "resetButton")) { TextSize = 16.0f, Size = new Vector2(64.0f, 20.0f), Text = translation.GetTranslatedName("reset_button"), - ShowHoverText = false + ShowHoverText = false, + ZIndex = (short)(ZIndex + 1) }; _resetButton.OnClick += () => { From 277d12c0319809a78d39cf2991ecd803556820cf Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 15 Jan 2024 16:13:28 +0200 Subject: [PATCH 073/107] implement element children system, use children for colorline controls --- UI/Element.cs | 152 +++++++++++++++++++++++++++++++----- UI/Elements/ColorLine.cs | 37 +++++---- UI/Elements/ListBox.cs | 2 +- UI/Elements/Tooltip.cs | 2 +- UI/Interfaces/BlockUI.cs | 6 +- UI/Interfaces/MenuUI.cs | 12 +-- UI/Interfaces/PauseUI.cs | 4 +- UI/Interfaces/SettingsUI.cs | 4 +- 8 files changed, 170 insertions(+), 49 deletions(-) diff --git a/UI/Element.cs b/UI/Element.cs index 885575f..e10b7a3 100644 --- a/UI/Element.cs +++ b/UI/Element.cs @@ -18,10 +18,18 @@ public Rectangle Area } } - public Vector2 Position + public Vector2 GlobalPosition { get => new Vector2(_Area.X, _Area.Y); - set => _Area = new Rectangle(value.X, value.Y, _Area.Width, _Area.Height); + set + { + _Area = new Rectangle(value.X, value.Y, _Area.Width, _Area.Height); + + foreach (var child in Children) + { + child.GlobalPosition = GlobalPosition + child.LocalPosition; + } + } } public Vector2 Size @@ -35,17 +43,121 @@ public Vector2 Size } } + private Vector2 _localPosition; + public Vector2 LocalPosition + { + get => Parent != null ? _localPosition : GlobalPosition; + set + { + if (Parent == null) + { + GlobalPosition = value; + } + else + { + GlobalPosition = Parent.GlobalPosition + value; + _localPosition = value; + } + } + } + + private Element? _parent; + + public Element? Parent + { + get => _parent; + set + { + if (value == null && _parent != null) + { + _parent.Children.Remove(this); + } + else if (value != null && _parent == null) + { + value.Children.Add(this); + } + + _parent = value; + } + } + + public List Children = new List(); + public ElementId Id; - public short ZIndex; - public bool Active = true; - public bool Visible = true; + private short _zIndex; + + public short ZIndex + { + get + { + if (Parent == null) return _zIndex; + return (short)(Parent.ZIndex + _zIndex); + } + set + { + if (Parent == null) + { + _zIndex = value; + return; + } + + _zIndex = (short)(Parent.ZIndex + value); + return; + } + } + + private bool _active = true; + + public bool Active + { + get => _active; + set + { + foreach (var child in Children) + { + child.Active = value; + } + + _active = value; + } + } + + private bool _visible = true; + + public bool Visible + { + get => _visible; + set + { + foreach (var child in Children) + { + child.Visible = value; + } + + _visible = value; + } + } public Alignment Origin = Alignment.TopLeft; public float Rotation = 0; public string TooltipText = string.Empty; - public bool IgnorePause = false; + private bool _ignorePause = false; + + public bool IgnorePause + { + get => _ignorePause; + set + { + foreach (var child in Children) + { + child.IgnorePause = value; + } + + _ignorePause = value; + } + } private RenderTexture2D _controlTexture; @@ -62,13 +174,6 @@ public virtual void Update() public void Draw() { - BeginTextureMode(_controlTexture); - ClearBackground(Color.BLANK); - - Render(); - - EndTextureMode(); - Vector2 offset = Origin switch { Alignment.TopLeft => new Vector2(0, 0), @@ -83,14 +188,21 @@ public void Draw() _ => new Vector2(0, 0) }; - DrawTexturePro( - _controlTexture.Texture, - new Rectangle( - 0, 0, - _Area.Width, -_Area.Height // we need to negate render texture height because opengl uses bottom-left instead of top-left + BeginTextureMode(_controlTexture); + ClearBackground(Color.BLANK); + + Render(); + + EndTextureMode(); + + DrawTexturePro( + _controlTexture.Texture, + new Rectangle( + 0, 0, + _Area.Width, -_Area.Height // we need to negate render texture height because opengl uses bottom-left instead of top-left ), - _Area, offset, Rotation, - Color.WHITE + _Area, offset, Rotation, + Color.WHITE ); } diff --git a/UI/Elements/ColorLine.cs b/UI/Elements/ColorLine.cs index 90e0203..abb5186 100644 --- a/UI/Elements/ColorLine.cs +++ b/UI/Elements/ColorLine.cs @@ -71,40 +71,49 @@ public ColorLine(ElementId id) : base(id) _colorPreview = new Panel(new ElementId(id, "colorPreview")) { Brush = new OutlineBrush(Color.DARKGRAY, DefaultColor), - Size = new Vector2(40.0f, 20.0f), - ZIndex = (short)(ZIndex + 1) + LocalPosition = new Vector2(0, 0), + Parent = this, + Size = new Vector2(40.0f, 20.0f) }; + _redBox = new TextBox(new ElementId(id, "redBox")) { TextSize = 16.0f, Size = new Vector2(40.0f, 20.0f), CharacterRange = new Range(48, 57), Text = DefaultColor.R.ToString(), - ZIndex = (short)(ZIndex + 1) + Parent = this, + LocalPosition = new Vector2(_colorPreview.LocalPosition.X + _colorPreview.Size.X + 8, 0), }; + _greenBox = new TextBox(new ElementId(id, "greenBox")) { TextSize = 16.0f, Size = new Vector2(40.0f, 20.0f), CharacterRange = new Range(48, 57), Text = DefaultColor.G.ToString(), - ZIndex = (short)(ZIndex + 1) + Parent = this, + LocalPosition = new Vector2(_redBox.LocalPosition.X + _redBox.Size.X + 8, 0) }; + _blueBox = new TextBox(new ElementId(id, "blueBox")) { TextSize = 16.0f, Size = new Vector2(40.0f, 20.0f), CharacterRange = new Range(48, 57), Text = DefaultColor.B.ToString(), - ZIndex = (short)(ZIndex + 1) + Parent = this, + LocalPosition = new Vector2(_greenBox.LocalPosition.X + _greenBox.Size.X + 8, 0) }; + _resetButton = new Button(new ElementId(id, "resetButton")) { TextSize = 16.0f, Size = new Vector2(64.0f, 20.0f), Text = translation.GetTranslatedName("reset_button"), ShowHoverText = false, - ZIndex = (short)(ZIndex + 1) + Parent = this, + LocalPosition = new Vector2(_blueBox.LocalPosition.X + _blueBox.Size.X + 8, 0) }; _resetButton.OnClick += () => { @@ -153,14 +162,14 @@ private void BlueBoxOnTextUpdate(string arg2) public override void Update() { - _colorPreview.Position = Position + new Vector2(0, Size.Y / 2 - _colorPreview.Size.Y / 2); - _redBox.Position = _colorPreview.Position + new Vector2(_colorPreview.Size.X + 8, 0); - _greenBox.Position = _redBox.Position + new Vector2(+ _redBox.Size.X + 8, 0); - _blueBox.Position = _greenBox.Position + new Vector2(_greenBox.Size.X + 8, 0); - _resetButton.Position = _blueBox.Position + new Vector2(_blueBox.Size.X + 8, 0); - - _colorPreview.Visible = _redBox.Visible = _greenBox.Visible = _blueBox.Visible = _resetButton.Visible = Visible; - _colorPreview.Active = _redBox.Active = _greenBox.Active = _blueBox.Active = _resetButton.Active = Active; + // _colorPreview.GlobalPosition = GlobalPosition + new Vector2(0, Size.Y / 2 - _colorPreview.Size.Y / 2); + // _redBox.GlobalPosition = _colorPreview.GlobalPosition + new Vector2(_colorPreview.Size.X + 8, 0); + // _greenBox.GlobalPosition = _redBox.GlobalPosition + new Vector2(+ _redBox.Size.X + 8, 0); + // _blueBox.GlobalPosition = _greenBox.GlobalPosition + new Vector2(_greenBox.Size.X + 8, 0); + // _resetButton.GlobalPosition = _blueBox.GlobalPosition + new Vector2(_blueBox.Size.X + 8, 0); + // + // _colorPreview.Visible = _redBox.Visible = _greenBox.Visible = _blueBox.Visible = _resetButton.Visible = Visible; + // _colorPreview.Active = _redBox.Active = _greenBox.Active = _blueBox.Active = _resetButton.Active = Active; } protected override void Render() diff --git a/UI/Elements/ListBox.cs b/UI/Elements/ListBox.cs index 2731e45..37c9dca 100644 --- a/UI/Elements/ListBox.cs +++ b/UI/Elements/ListBox.cs @@ -31,7 +31,7 @@ public override void Update() if (IsUnderMouse()) { // finding index for highlight - float localMouseY = GetMousePosition().Y - Position.Y; + float localMouseY = GetMousePosition().Y - GlobalPosition.Y; int index = (int)((localMouseY - _scroll) / ItemTextSize); _highlightIndex = index; diff --git a/UI/Elements/Tooltip.cs b/UI/Elements/Tooltip.cs index 4ac6084..bda891d 100644 --- a/UI/Elements/Tooltip.cs +++ b/UI/Elements/Tooltip.cs @@ -31,7 +31,7 @@ public override void Update() var pos = GetMousePosition() + new Vector2(0, 16); var size = MeasureTextEx(GetFontDefault(), Text, TextSize, GetSpacing(TextSize)); - Position = pos with { X = pos.X - 16.0f }; + GlobalPosition = pos with { X = pos.X - 16.0f }; Size = size + new Vector2(16); } diff --git a/UI/Interfaces/BlockUI.cs b/UI/Interfaces/BlockUI.cs index d6d5556..dc971fa 100644 --- a/UI/Interfaces/BlockUI.cs +++ b/UI/Interfaces/BlockUI.cs @@ -82,9 +82,9 @@ public override void Configure() Vector2 screenSize = new Vector2(GetScreenWidth(), GetScreenHeight()); _background.Size = new Vector2(680, 420); - _background.Position = screenSize / 2 - _background.Size / 2; + _background.GlobalPosition = screenSize / 2 - _background.Size / 2; - _menuTitle.Position = _background.Position; + _menuTitle.GlobalPosition = _background.GlobalPosition; _menuTitle.Size = _background.Size with { Y = 38 }; float x = 20; @@ -95,7 +95,7 @@ public override void Configure() Button tileButton = _tileButtons[i]; Tile tile = Tiles.Tiles.GetTile((byte)(i + 1)); - tileButton.Position = _background.Position + new Vector2(x, y); + tileButton.GlobalPosition = _background.GlobalPosition + new Vector2(x, y); int ii = i; tileButton.OnClick += () => diff --git a/UI/Interfaces/MenuUI.cs b/UI/Interfaces/MenuUI.cs index b92a882..9b9287d 100644 --- a/UI/Interfaces/MenuUI.cs +++ b/UI/Interfaces/MenuUI.cs @@ -86,12 +86,12 @@ public override void Initialize() public override void Configure() { - _title.Position = new Vector2(12, GetYAt(0)); - _playButton.Position = new Vector2(12, GetYAt(1)); - _settingsButton.Position = new Vector2(12, GetYAt(2)); - _packsButton.Position = new Vector2(12, GetYAt(3)); - _exitButton.Position = new Vector2(12, GetYAt(4)); - _versionText.Position = new Vector2(8, GetScreenHeight() - 8 - _versionText.TextSize); + _title.GlobalPosition = new Vector2(12, GetYAt(0)); + _playButton.GlobalPosition = new Vector2(12, GetYAt(1)); + _settingsButton.GlobalPosition = new Vector2(12, GetYAt(2)); + _packsButton.GlobalPosition = new Vector2(12, GetYAt(3)); + _exitButton.GlobalPosition = new Vector2(12, GetYAt(4)); + _versionText.GlobalPosition = new Vector2(8, GetScreenHeight() - 8 - _versionText.TextSize); } public override void Resized() diff --git a/UI/Interfaces/PauseUI.cs b/UI/Interfaces/PauseUI.cs index f5866f4..c8201a8 100644 --- a/UI/Interfaces/PauseUI.cs +++ b/UI/Interfaces/PauseUI.cs @@ -91,11 +91,11 @@ public override void Configure() _resumeButton.Area = new Rectangle(buttonsOriginX, buttonsOriginY, 148, 24); _settingsButton.Area = new Rectangle( - buttonsOriginX, _resumeButton.Position.Y + _resumeButton.TextSize + 16, + buttonsOriginX, _resumeButton.GlobalPosition.Y + _resumeButton.TextSize + 16, 148, 24 ); _menuButton.Area = new Rectangle( - buttonsOriginX, _settingsButton.Position.Y + _settingsButton.TextSize + 16, + buttonsOriginX, _settingsButton.GlobalPosition.Y + _settingsButton.TextSize + 16, 148, 24); } diff --git a/UI/Interfaces/SettingsUI.cs b/UI/Interfaces/SettingsUI.cs index b8dde93..2c03a22 100644 --- a/UI/Interfaces/SettingsUI.cs +++ b/UI/Interfaces/SettingsUI.cs @@ -55,7 +55,7 @@ public override void Resized() public override void Configure() { _background.Area = new Rectangle(50.0f, 50.0f, GetScreenWidth() - 100.0f, GetScreenHeight() - 100.0f); - _skyColorLineText.Position = _background.Position + new Vector2(8.0f, 16.0f); - _skyColorLine.Position = _skyColorLineText.Position + _skyColorLineText.Size with { Y = 0 } + new Vector2(16.0f, 2.0f); + _skyColorLineText.GlobalPosition = _background.GlobalPosition + new Vector2(8.0f, 16.0f); + _skyColorLine.GlobalPosition = _skyColorLineText.GlobalPosition + _skyColorLineText.Size with { Y = 0 } + new Vector2(16.0f, 2.0f); } } \ No newline at end of file From 216d21162fe50e31238ff8279cf9ac6d0435c948 Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 15 Jan 2024 17:47:10 +0200 Subject: [PATCH 074/107] add fraction to render texture area --- UI/Element.cs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/UI/Element.cs b/UI/Element.cs index e10b7a3..1b93f72 100644 --- a/UI/Element.cs +++ b/UI/Element.cs @@ -188,22 +188,22 @@ public void Draw() _ => new Vector2(0, 0) }; - BeginTextureMode(_controlTexture); - ClearBackground(Color.BLANK); + BeginTextureMode(_controlTexture); + ClearBackground(Color.BLANK); - Render(); + Render(); - EndTextureMode(); + EndTextureMode(); - DrawTexturePro( - _controlTexture.Texture, - new Rectangle( - 0, 0, - _Area.Width, -_Area.Height // we need to negate render texture height because opengl uses bottom-left instead of top-left - ), - _Area, offset, Rotation, - Color.WHITE - ); + DrawTexturePro( + _controlTexture.Texture, + new Rectangle( + 0.25f, 0.25f, + _Area.Width - 0.25f, -_Area.Height + 0.25f // we need to negate render texture height because opengl uses bottom-left instead of top-left + ), + _Area, offset, Rotation, + Color.WHITE + ); } protected virtual void Render() From 1a7f1570e18da8dc8d3a09202cabb13ace5ef996 Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 15 Jan 2024 17:47:16 +0200 Subject: [PATCH 075/107] update ui --- UI/Interfaces/BlockUI.cs | 62 +++++++++++++++++-------------------- UI/Interfaces/PauseUI.cs | 20 ++++++------ UI/Interfaces/SettingsUI.cs | 11 ++++--- 3 files changed, 45 insertions(+), 48 deletions(-) diff --git a/UI/Interfaces/BlockUI.cs b/UI/Interfaces/BlockUI.cs index dc971fa..40427da 100644 --- a/UI/Interfaces/BlockUI.cs +++ b/UI/Interfaces/BlockUI.cs @@ -21,6 +21,7 @@ public override void Initialize() _background = new Panel(new ElementId("blockMenu", "background")) { Brush = new GradientBrush(new Color(0, 0, 25, 100), new Color(0, 0, 0, 200)), + Size = new Vector2(680, 420), ZIndex = -1 }; Elements.Add(_background); @@ -30,7 +31,9 @@ public override void Initialize() Text = translation.GetTranslatedName("block_ui_title"), TextColor = Color.WHITE, TextSize = 32, - TextAlignment = Alignment.Center + TextAlignment = Alignment.Center, + Parent = _background, + ZIndex = 1 }; Elements.Add(_menuTitle); @@ -40,9 +43,12 @@ public override void Initialize() // TextColor = BLACK, // MaxCharacters = 128 // }; - + Tile[] tiles = Tiles.Tiles.GetTiles(); _tileButtons = new Button[tiles.Length]; + + float x = 20; + float y = 40; for (int i = 0; i < tiles.Length; i++) { @@ -51,7 +57,7 @@ public override void Initialize() float ratio = aspectX < aspectY ? aspectX : aspectY; - _tileButtons[i] = new Button(new ElementId("blockMenu", "tile_" + i)) + var tileButton = _tileButtons[i] = new Button(new ElementId("blockMenu", "tile_" + i)) { Size = new Vector2(1) * Tile.RealTileSize, BackgroundBrush = new TextureBrush(Resources.GetTexture("Atlas.png")) @@ -65,38 +71,11 @@ public override void Initialize() }, ShowHoverText = false, TooltipText = translation.GetTranslatedName(tiles[i].TranslationKey), - ZIndex = (short)(_background.ZIndex + 1) + Parent = _background, + ZIndex = 1, + LocalPosition = new Vector2(x, y) }; - Elements.Add(_tileButtons[i]); - } - - Visible = false; - Configure(); - } - - public override void Configure() - { - base.Configure(); - - Vector2 screenSize = new Vector2(GetScreenWidth(), GetScreenHeight()); - - _background.Size = new Vector2(680, 420); - _background.GlobalPosition = screenSize / 2 - _background.Size / 2; - - _menuTitle.GlobalPosition = _background.GlobalPosition; - _menuTitle.Size = _background.Size with { Y = 38 }; - - float x = 20; - float y = 40; - - for (int i = 0; i < _tileButtons.Length; i++) - { - Button tileButton = _tileButtons[i]; - Tile tile = Tiles.Tiles.GetTile((byte)(i + 1)); - - tileButton.GlobalPosition = _background.GlobalPosition + new Vector2(x, y); - int ii = i; tileButton.OnClick += () => { @@ -111,7 +90,24 @@ public override void Configure() x = 20; y += Tile.RealTileSize + 8; } + + Elements.Add(tileButton); } + + Configure(); + + Visible = false; + } + + public override void Configure() + { + base.Configure(); + + Vector2 screenSize = new Vector2(GetScreenWidth(), GetScreenHeight()); + + _background.GlobalPosition = screenSize / 2 - _background.Size / 2; + + _menuTitle.Size = _background.Size with { Y = 38 }; } public override void Resized() diff --git a/UI/Interfaces/PauseUI.cs b/UI/Interfaces/PauseUI.cs index c8201a8..33d1564 100644 --- a/UI/Interfaces/PauseUI.cs +++ b/UI/Interfaces/PauseUI.cs @@ -38,7 +38,8 @@ public override void Initialize() TextSize = 24, TextAlignment = Alignment.CenterLeft, IgnorePause = true, - ZIndex = 101 + ZIndex = 1, + Parent = _background }; _resumeButton.OnClick += () => { @@ -53,7 +54,9 @@ public override void Initialize() TextSize = 24, TextAlignment = Alignment.CenterLeft, IgnorePause = true, - ZIndex = 101 + ZIndex = 1, + Size = new Vector2(148, 24), + Parent = _background }; _settingsButton.OnClick += () => { @@ -67,7 +70,9 @@ public override void Initialize() TextSize = 24, TextAlignment = Alignment.CenterLeft, IgnorePause = true, - ZIndex = 101 + ZIndex = 1, + Size = new Vector2(148, 24), + Parent = _background }; _menuButton.OnClick += () => { @@ -90,13 +95,8 @@ public override void Configure() float buttonsOriginY = GetScreenHeight() / 2 - _resumeButton.TextSize; _resumeButton.Area = new Rectangle(buttonsOriginX, buttonsOriginY, 148, 24); - _settingsButton.Area = new Rectangle( - buttonsOriginX, _resumeButton.GlobalPosition.Y + _resumeButton.TextSize + 16, - 148, 24 - ); - _menuButton.Area = new Rectangle( - buttonsOriginX, _settingsButton.GlobalPosition.Y + _settingsButton.TextSize + 16, - 148, 24); + _settingsButton.GlobalPosition = new Vector2(buttonsOriginX, _resumeButton.GlobalPosition.Y + _resumeButton.TextSize + 16); + _menuButton.GlobalPosition = new Vector2(buttonsOriginX, _settingsButton.GlobalPosition.Y + _settingsButton.TextSize + 16); } public override void Resized() diff --git a/UI/Interfaces/SettingsUI.cs b/UI/Interfaces/SettingsUI.cs index 2c03a22..1a767dd 100644 --- a/UI/Interfaces/SettingsUI.cs +++ b/UI/Interfaces/SettingsUI.cs @@ -27,15 +27,17 @@ public override void Initialize() Text = translation.GetTranslatedName("sky_color_line"), Size = new Vector2(128.0f, 20.0f), TextSize = 16.0f, - ZIndex = 201 + ZIndex = 1, + Parent = _background }; Elements.Add(_skyColorLineText); _skyColorLine = new ColorLine(new ElementId("settings", "skyColorLine")) { - ZIndex = 201, Color = Settings.SkyColor, - DefaultColor = Color.SKYBLUE + DefaultColor = Color.SKYBLUE, + Parent = _skyColorLineText, + LocalPosition = new Vector2(_skyColorLineText.Size.X + 16.0f, 2.0f) }; _skyColorLine.OnColorUpdate += color => { @@ -55,7 +57,6 @@ public override void Resized() public override void Configure() { _background.Area = new Rectangle(50.0f, 50.0f, GetScreenWidth() - 100.0f, GetScreenHeight() - 100.0f); - _skyColorLineText.GlobalPosition = _background.GlobalPosition + new Vector2(8.0f, 16.0f); - _skyColorLine.GlobalPosition = _skyColorLineText.GlobalPosition + _skyColorLineText.Size with { Y = 0 } + new Vector2(16.0f, 2.0f); + _skyColorLineText.GlobalPosition = _background.GlobalPosition + new Vector2(8.0f, 16.0f); } } \ No newline at end of file From f93a78f2a82891236d8678d6cf3235cb4491611f Mon Sep 17 00:00:00 2001 From: danil Date: Wed, 17 Jan 2024 10:46:59 +0200 Subject: [PATCH 076/107] fix listbox not selecting first element --- UI/Elements/ListBox.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/Elements/ListBox.cs b/UI/Elements/ListBox.cs index 37c9dca..3d94762 100644 --- a/UI/Elements/ListBox.cs +++ b/UI/Elements/ListBox.cs @@ -47,7 +47,7 @@ public override void Update() if (IsClicked()) { - if (_highlightIndex > 0) + if (_highlightIndex >= 0) { _selectedIndex = _highlightIndex; OnItemSelect?.Invoke(Items[_selectedIndex]); From 09247a662a85bbeec24fdecd432648529a3c7426 Mon Sep 17 00:00:00 2001 From: danil Date: Wed, 17 Jan 2024 10:47:11 +0200 Subject: [PATCH 077/107] update listbox color scheme --- UI/Elements/ListBox.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/UI/Elements/ListBox.cs b/UI/Elements/ListBox.cs index 3d94762..d2ca2e9 100644 --- a/UI/Elements/ListBox.cs +++ b/UI/Elements/ListBox.cs @@ -10,9 +10,9 @@ public class ListBox : Element public List Items = new List(); public event Action? OnItemSelect; - public IBrush? BackgroundBrush = new SolidBrush(Color.WHITE); - public IBrush? HighlightBrush = new SolidBrush(new Color(212, 245, 255, 255)); - public IBrush? SelectionBrush = new SolidBrush(new Color(122, 214, 255, 255)); + public IBrush? BackgroundBrush = null; + public IBrush? HighlightBrush = new SolidBrush(new Color(90, 95, 100, 255)); + public IBrush? SelectionBrush = new SolidBrush(new Color(60, 70, 80, 255)); public float ItemTextSize = 12; public float ItemPadding = 4; From 26df183b868204b3416bebc628f90d74cc66145b Mon Sep 17 00:00:00 2001 From: danil Date: Thu, 18 Jan 2024 13:06:12 +0200 Subject: [PATCH 078/107] make listbox work as expected --- UI/Elements/ListBox.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/UI/Elements/ListBox.cs b/UI/Elements/ListBox.cs index d2ca2e9..178f0dc 100644 --- a/UI/Elements/ListBox.cs +++ b/UI/Elements/ListBox.cs @@ -36,13 +36,18 @@ public override void Update() _highlightIndex = index; // list scrolling - float boxHeight = Items.Count * ItemTextSize - Area.Height + ItemPadding; + float boxHeight = Items.Count * ItemTextSize + Items.Count * ItemPadding; float wheel = GetMouseWheelMove(); float wheelAxis = wheel * ScrollSpeed * GetFrameTime(); - _scroll += wheelAxis; - if (_scroll > 0) _scroll = 0; - if (_scroll <= -boxHeight) _scroll = -boxHeight; + if (boxHeight > Area.Height) + { + _scroll += wheelAxis; + if (_scroll > 0) _scroll = 0; + if (_scroll <= -boxHeight / 2) _scroll = -boxHeight / 2; + } + + Console.WriteLine(_scroll); } if (IsClicked()) From a1d41fcc89fa9ab8f435ec7fc8ccfc987637a87e Mon Sep 17 00:00:00 2001 From: danil Date: Thu, 18 Jan 2024 14:11:14 +0200 Subject: [PATCH 079/107] make selected item index visible --- UI/Elements/ListBox.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/UI/Elements/ListBox.cs b/UI/Elements/ListBox.cs index 178f0dc..f00ec91 100644 --- a/UI/Elements/ListBox.cs +++ b/UI/Elements/ListBox.cs @@ -17,10 +17,10 @@ public class ListBox : Element public float ItemTextSize = 12; public float ItemPadding = 4; public Color ItemColor = Color.WHITE; + public int SelectedItem = -1; private float _scroll = 0; private int _highlightIndex = -1; - private int _selectedIndex = -1; public ListBox(ElementId id) : base(id) { @@ -54,8 +54,8 @@ public override void Update() { if (_highlightIndex >= 0) { - _selectedIndex = _highlightIndex; - OnItemSelect?.Invoke(Items[_selectedIndex]); + SelectedItem = _highlightIndex; + OnItemSelect?.Invoke(Items[SelectedItem]); } } } @@ -71,7 +71,7 @@ protected override void Render() Area.Width, ItemTextSize ); - if (i == _selectedIndex) + if (i == SelectedItem) { SelectionBrush?.FillArea(area); } From 2daad864d984e681c47258d550a91374d3fa090b Mon Sep 17 00:00:00 2001 From: danil Date: Thu, 18 Jan 2024 19:40:34 +0200 Subject: [PATCH 080/107] implement world menu --- Assets/Translation.yaml | 7 +- Tiles/Data/WorldInfo.cs | 6 + Tiles/World.cs | 10 +- Tiles/WorldManager.cs | 104 ++++++++++++++++++ UI/Elements/ListBox.cs | 10 +- UI/Interfaces/CreateWorldUI.cs | 85 +++++++++++++++ UI/Interfaces/MenuUI.cs | 2 +- UI/Interfaces/WorldMenuUI.cs | 170 +++++++++++++++++++++++++++++ UI/Screens/CreateWorldScreen.cs | 26 +++++ UI/Screens/GameScreen.cs | 19 +++- UI/Screens/WorldSelectionScreen.cs | 25 +++++ 11 files changed, 454 insertions(+), 10 deletions(-) create mode 100644 Tiles/Data/WorldInfo.cs create mode 100644 Tiles/WorldManager.cs create mode 100644 UI/Interfaces/CreateWorldUI.cs create mode 100644 UI/Interfaces/WorldMenuUI.cs create mode 100644 UI/Screens/CreateWorldScreen.cs create mode 100644 UI/Screens/WorldSelectionScreen.cs diff --git a/Assets/Translation.yaml b/Assets/Translation.yaml index e0cbaab..61db633 100644 --- a/Assets/Translation.yaml +++ b/Assets/Translation.yaml @@ -65,4 +65,9 @@ menu_button: "menu" block_ui_title: "Select a tile" -reset_button: "reset" \ No newline at end of file +reset_button: "reset" + +default_world_title: "select world pls" +play_time_format: "played {0}" # {0} - TimeSpan +create_world_button: "create" +delete_world_button: "delete" \ No newline at end of file diff --git a/Tiles/Data/WorldInfo.cs b/Tiles/Data/WorldInfo.cs new file mode 100644 index 0000000..df21dd7 --- /dev/null +++ b/Tiles/Data/WorldInfo.cs @@ -0,0 +1,6 @@ +namespace BuildingGame.Tiles.Data; + +public record struct WorldInfo(string Path, WorldInfo.InfoRecord Info) +{ + public record struct InfoRecord(string Name, TimeSpan PlayTime); +} \ No newline at end of file diff --git a/Tiles/World.cs b/Tiles/World.cs index b8c439c..854888d 100644 --- a/Tiles/World.cs +++ b/Tiles/World.cs @@ -14,7 +14,7 @@ public class World public readonly int ChunkHeight; public Vector2 PlayerPosition; - public float PlayerZoom; + public float PlayerZoom = 1.0f; private Chunk[][] _chunks; @@ -75,9 +75,9 @@ public ChunkPosition WorldToChunk(int x, int y) return new ChunkPosition(cx, cy); } - public void Load() + public void Load(string path) { - if (!WorldIO.TryDeserializeWorld("level.dat", out var world)) return; + if (!WorldIO.TryDeserializeWorld(path, out var world)) return; if (Width != world.Width || Height != world.Height) return; PlayerPosition = world.PlayerPosition; @@ -92,9 +92,9 @@ public void Load() } } - public void Save() + public void Save(string path) { - WorldIO.TrySerializeWorld("level.dat", this); + WorldIO.TrySerializeWorld(path, this); } public TileInfo this[int x, int y] diff --git a/Tiles/WorldManager.cs b/Tiles/WorldManager.cs new file mode 100644 index 0000000..45eafc7 --- /dev/null +++ b/Tiles/WorldManager.cs @@ -0,0 +1,104 @@ +using BuildingGame.Tiles.Data; +using BuildingGame.Tiles.IO; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; + +namespace BuildingGame.Tiles; + +public static class WorldManager +{ + public const string WorldsPath = "Worlds"; + public const string WorldInfoFile = "Info"; + public const string WorldLevelFile = "Level.dat"; + + public static readonly List Worlds = new List(); + + private static readonly IDeserializer _deserializer = new DeserializerBuilder() + .WithNamingConvention(UnderscoredNamingConvention.Instance) + .IgnoreUnmatchedProperties() + .Build(); + + private static readonly ISerializer _serializer = new SerializerBuilder() + .WithNamingConvention(UnderscoredNamingConvention.Instance) + .Build(); + + public static void ReadWorlds() + { + Worlds.Clear(); + + foreach (var dir in Directory.EnumerateDirectories(WorldsPath)) + { + foreach (var file in Directory.EnumerateFiles(dir)) + { + var fileName = Path.GetFileNameWithoutExtension(file).ToLower(); + if (fileName != WorldInfoFile.ToLower()) continue; + + var ext = Path.GetExtension(file).ToLower(); + + var content = File.ReadAllText(file); + + switch (ext) + { + case ".txt": + Worlds.Add(new WorldInfo(dir, new WorldInfo.InfoRecord(content, TimeSpan.Zero))); + break; + + case ".yaml": + var deserialized = _deserializer.Deserialize(content); + Worlds.Add(new WorldInfo(dir, deserialized)); + break; + + default: + continue; + } + + break; + } + } + } + + public static WorldInfo CreateInfo(string name) + { + var invalidChars = Path.GetInvalidPathChars(); + var pathChars = name.Select(c => Array.IndexOf(invalidChars, c) >= 0 ? ' ' : c); + var path = Path.Join(WorldsPath, new string(pathChars.ToArray())); + + var info = new WorldInfo(path, new WorldInfo.InfoRecord(name, TimeSpan.Zero)); + + return info; + } + + public static WorldInfo Find(string path) + { + return Worlds.FirstOrDefault(i => + string.Equals(i.Path, path, StringComparison.CurrentCultureIgnoreCase)); + } + + public static void LoadWorld(ref World world, string name) + { + var info = Find(name); + if (string.IsNullOrWhiteSpace(info.Path)) return; + + world.Load(Path.Join(info.Path, WorldLevelFile)); + } + + public static void WriteWorld(World world, WorldInfo info) + { + WriteInfo(info); + world.Save(Path.Join(info.Path, WorldLevelFile)); + } + + public static void WriteInfo(WorldInfo info) + { + Directory.CreateDirectory(info.Path); + + var content = _serializer.Serialize(info.Info); + File.WriteAllText(Path.Join(info.Path, WorldInfoFile + ".yaml"), content); + } + + public static void DeleteWorld(WorldInfo info) + { + Directory.Delete(info.Path, true); + Worlds.Remove(info); + } +} \ No newline at end of file diff --git a/UI/Elements/ListBox.cs b/UI/Elements/ListBox.cs index f00ec91..abd9b84 100644 --- a/UI/Elements/ListBox.cs +++ b/UI/Elements/ListBox.cs @@ -55,7 +55,15 @@ public override void Update() if (_highlightIndex >= 0) { SelectedItem = _highlightIndex; - OnItemSelect?.Invoke(Items[SelectedItem]); + + if (SelectedItem >= 0 && SelectedItem < Items.Count) + { + OnItemSelect?.Invoke(Items[SelectedItem]); + } + else + { + OnItemSelect?.Invoke(string.Empty); + } } } } diff --git a/UI/Interfaces/CreateWorldUI.cs b/UI/Interfaces/CreateWorldUI.cs new file mode 100644 index 0000000..c73bd86 --- /dev/null +++ b/UI/Interfaces/CreateWorldUI.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using BuildingGame.Tiles; +using BuildingGame.UI.Elements; +using BuildingGame.UI.Screens; + +namespace BuildingGame.UI.Interfaces; +public class CreateWorldUI : UIInterface +{ + private TextBox _worldNameTextBox; + private TextElement _maxCharacterText; + private Button _createButton; + private Button _backButton; + + public override void Initialize() + { + base.Initialize(); + + _worldNameTextBox = new TextBox(new ElementId("createWorldScreen", "worldNameTextBox")) + { + TextSize = 28.0f, + Size = new Vector2(512.0f, 32.0f) + }; + Elements.Add(_worldNameTextBox); + + _maxCharacterText = new TextElement(new ElementId("createWorldScreen", "maxCharacterText")) + { + Text = "(max. 16 characters)", + TextSize = 20.0f, + Size = _worldNameTextBox.Size with { Y = 24.0f }, + TextAlignment = Alignment.CenterLeft + }; + Elements.Add(_maxCharacterText); + + _createButton = new Button(new ElementId("createWorldScreen", "createButton")) + { + Text = "create", + TextSize = 24.0f, + Size = _worldNameTextBox.Size with { Y = 28.0f }, + TextAlignment = Alignment.Center + }; + _createButton.OnClick += () => + { + if (string.IsNullOrWhiteSpace(_worldNameTextBox.Text)) return; + if (WorldManager.Find(Path.Join(WorldManager.WorldsPath, _worldNameTextBox.Text)).Path != null) return; + + var info = WorldManager.CreateInfo(_worldNameTextBox.Text); + WorldManager.WriteWorld(new World(), info); + ScreenManager.Switch(new WorldSelectionScreen()); + }; + Elements.Add(_createButton); + + _backButton = new Button(new ElementId("createWorldScreen", "backButton")) + { + Text = "back", + TextSize = 24.0f, + Size = _worldNameTextBox.Size with { Y = 28.0f }, + TextAlignment = Alignment.Center + }; + _backButton.OnClick += () => + { + ScreenManager.Switch(new WorldSelectionScreen()); + }; + Elements.Add(_backButton); + + Configure(); + } + + public override void Configure() + { + _worldNameTextBox.GlobalPosition = new Vector2(GetScreenWidth() / 2 - _worldNameTextBox.Size.X / 2, GetScreenHeight() / 2 - 64.0f); + _maxCharacterText.GlobalPosition = _worldNameTextBox.GlobalPosition + new Vector2(0.0f, _worldNameTextBox.Size.Y); + _createButton.GlobalPosition = _maxCharacterText.GlobalPosition + new Vector2(0.0f, 40.0f); + _backButton.GlobalPosition = _createButton.GlobalPosition + new Vector2(0.0f, _createButton.Size.Y); + } + + public override void Resized() + { + Configure(); + } +} diff --git a/UI/Interfaces/MenuUI.cs b/UI/Interfaces/MenuUI.cs index 9b9287d..30c3513 100644 --- a/UI/Interfaces/MenuUI.cs +++ b/UI/Interfaces/MenuUI.cs @@ -35,7 +35,7 @@ public override void Initialize() }; _playButton.OnClick += () => { - ScreenManager.Switch(new GameScreen()); + ScreenManager.Switch(new WorldSelectionScreen()); }; Elements.Add(_playButton); diff --git a/UI/Interfaces/WorldMenuUI.cs b/UI/Interfaces/WorldMenuUI.cs new file mode 100644 index 0000000..f47e34c --- /dev/null +++ b/UI/Interfaces/WorldMenuUI.cs @@ -0,0 +1,170 @@ +using System.Numerics; +using BuildingGame.Tiles; +using BuildingGame.Translation; +using BuildingGame.UI.Brushes; +using BuildingGame.UI.Elements; +using BuildingGame.UI.Screens; + +namespace BuildingGame.UI.Interfaces; + +public class WorldMenuUI : UIInterface +{ + private ListBox _worldList; + private Panel _sidePanel; + private Panel _bottomPanel; + private TextElement _selectedWorldTitle; + private TextElement _selectedWorldPlayTime; + private Button _playWorldButton; + private Button _menuButton; + private Button _createWorldButton; + private Button _deleteWorldButton; + + private string[] _paths; + + public override void Initialize() + { + var translation = TranslationContainer.Default; + + _paths = WorldManager.Worlds.Select(w => w.Path).ToArray(); + + _worldList = new ListBox(new ElementId("worldScreen", "list")) + { + ItemTextSize = 20.0f, + GlobalPosition = new Vector2(0.0f, 0.0f), + BackgroundBrush = null, + ItemColor = Color.WHITE, + Items = WorldManager.Worlds.Select(w => $"{w.Info.Name} ['{Path.GetFileName(w.Path)}']").ToList() + }; + _worldList.OnItemSelect += (item) => + { + if (string.IsNullOrWhiteSpace(item)) + { + _selectedWorldTitle.Text = translation.GetTranslatedName("default_world_title"); + + _selectedWorldPlayTime.Visible = false; + _playWorldButton.Visible = false; + _deleteWorldButton.Visible = false; + + return; + } + + _selectedWorldTitle.Text = item; + + _selectedWorldPlayTime.Visible = true; + _playWorldButton.Visible = true; + _deleteWorldButton.Visible = true; + + var world = WorldManager.Find(_paths[_worldList.SelectedItem]); + _selectedWorldPlayTime.Text = string.Format(translation.GetTranslatedName("play_time_format"), world.Info.PlayTime); + }; + Elements.Add(_worldList); + + _sidePanel = new Panel(new ElementId("worldScreen", "sidePanel")); + Elements.Add(_sidePanel); + + _bottomPanel = new Panel(new ElementId("worldScreen", "bottomPanel")); + Elements.Add(_bottomPanel); + + _selectedWorldTitle = new TextElement(new ElementId(_sidePanel.Id, "title")) + { + Text = translation.GetTranslatedName("default_world_title"), + TextSize = 28.0f, + TextAlignment = Alignment.Center, + Parent = _sidePanel + }; + + _selectedWorldPlayTime = new TextElement(new ElementId(_sidePanel.Id, "playTime")) + { + Text = string.Format(translation.GetTranslatedName("play_time_format"), TimeSpan.Zero), + TextSize = 20.0f, + TextAlignment = Alignment.TopCenter, + Parent = _sidePanel, + LocalPosition = new Vector2(0.0f, 40.0f), + Visible = false + }; + + _playWorldButton = new Button(new ElementId(_sidePanel.Id, "playButton")) + { + Text = translation.GetTranslatedName("play_button"), + TextSize = 32.0f, + TextAlignment = Alignment.Center, + Parent = _sidePanel, + LocalPosition = new Vector2(0.0f, 100.0f), + Visible = false + }; + _playWorldButton.OnClick += () => + { + ScreenManager.Switch(new GameScreen(_paths[_worldList.SelectedItem])); + }; + + _menuButton = new Button(new ElementId(_bottomPanel.Id, "menuButton")) + { + Text = translation.GetTranslatedName("menu_button"), + TextSize = 24.0f, + Size = new Vector2(64.0f, 28.0f), + TextAlignment = Alignment.Center, + Parent = _bottomPanel + }; + _menuButton.OnClick += () => + { + ScreenManager.Switch(new MenuScreen()); + }; + + _createWorldButton = new Button(new ElementId(_bottomPanel.Id, "createWorldButton")) + { + Text = translation.GetTranslatedName("create_world_button"), + TextSize = 24.0f, + Size = new Vector2(100.0f, 28.0f), + TextAlignment = Alignment.Center, + Parent = _bottomPanel + }; + _createWorldButton.OnClick += () => + { + ScreenManager.Switch(new CreateWorldScreen()); + }; + + _deleteWorldButton = new Button(new ElementId(_bottomPanel.Id, "deleteWorldButton")) + { + Text = translation.GetTranslatedName("delete_world_button"), + TextSize = 24.0f, + Size = new Vector2(100.0f, 28.0f), + TextAlignment = Alignment.Center, + Visible = false, + Parent = _bottomPanel, + }; + _deleteWorldButton.OnClick += () => + { + var world = WorldManager.Find(_paths[_worldList.SelectedItem]); + WorldManager.DeleteWorld(world); + _worldList.Items.RemoveAt(_worldList.SelectedItem); + _deleteWorldButton.Visible = false; + }; + + Configure(); + } + + public override void Configure() + { + _worldList.Size = new Vector2(GetScreenWidth() / 2.0f, GetScreenHeight() - 64.0f); + + _bottomPanel.Size = new Vector2(GetScreenWidth(), 64.0f); + _bottomPanel.GlobalPosition = new Vector2(0.0f, GetScreenHeight() - 64.0f); + + _sidePanel.Size = (new Vector2(GetScreenWidth(), GetScreenHeight()) - _worldList.Size) with { Y = GetScreenHeight() - _bottomPanel.Size.Y }; + _sidePanel.GlobalPosition = _worldList.Size with { Y = 0 }; + + _selectedWorldTitle.Size = new Vector2(_sidePanel.Size.X, 40.0f); + _selectedWorldPlayTime.Size = new Vector2(_sidePanel.Size.X, 24.0f); + _playWorldButton.Size = new Vector2(_sidePanel.Size.X, 36.0f); + + _menuButton.LocalPosition = new Vector2(_bottomPanel.Size.X - _menuButton.Size.X - 32.0f, _bottomPanel.Size.Y / 2 - _menuButton.Size.Y / 2); + + _createWorldButton.LocalPosition = new Vector2(8.0f, _bottomPanel.Size.Y / 2 - _createWorldButton.Size.Y / 2); + _deleteWorldButton.LocalPosition = _createWorldButton.LocalPosition + _createWorldButton.Size with { Y = 0 } + new Vector2(16.0f, 0.0f); + } + + public override void Resized() + { + Configure(); + } +} \ No newline at end of file diff --git a/UI/Screens/CreateWorldScreen.cs b/UI/Screens/CreateWorldScreen.cs new file mode 100644 index 0000000..16d4975 --- /dev/null +++ b/UI/Screens/CreateWorldScreen.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using BuildingGame.UI.Interfaces; + +namespace BuildingGame.UI.Screens; +public class CreateWorldScreen : Screen +{ + private CreateWorldUI _ui; + + public override void Initialize() + { + base.Initialize(); + + _ui = new CreateWorldUI(); + } + + public override void Draw() + { + ClearBackground(new Color(20, 20, 20, 255)); + + base.Draw(); + } +} diff --git a/UI/Screens/GameScreen.cs b/UI/Screens/GameScreen.cs index 3858ff9..213a0b0 100644 --- a/UI/Screens/GameScreen.cs +++ b/UI/Screens/GameScreen.cs @@ -1,4 +1,5 @@ using BuildingGame.Tiles; +using BuildingGame.Tiles.Data; using BuildingGame.UI.Interfaces; namespace BuildingGame.UI.Screens; @@ -6,17 +7,26 @@ namespace BuildingGame.UI.Screens; public class GameScreen : Screen { private World _world; + private WorldInfo _info; + private Player _player; private BlockUI _blockUi; private GameUI _ui; private PauseUI _pause; + private TimeSpan _playTime = TimeSpan.Zero; + + public GameScreen(string worldPath) + { + _info = WorldManager.Find(worldPath); + _playTime = _info.Info.PlayTime; + } public override void Initialize() { base.Initialize(); _world = new World(); - _world.Load(); + WorldManager.LoadWorld(ref _world, _info.Path); _player = new Player(_world, _world.PlayerPosition, _world.PlayerZoom, 50, 0.1f); @@ -34,6 +44,8 @@ public override void Update() if (!Program.Paused) { + _playTime += TimeSpan.FromSeconds(GetFrameTime()); + _player.Update(); _world.Update(); } @@ -60,6 +72,9 @@ protected override void Dispose(bool disposing) if (!disposing) return; _player.PushCameraInfo(); - _world.Save(); + + _info.Info = new WorldInfo.InfoRecord(_info.Info.Name, _playTime); + + WorldManager.WriteWorld(_world, _info); } } \ No newline at end of file diff --git a/UI/Screens/WorldSelectionScreen.cs b/UI/Screens/WorldSelectionScreen.cs new file mode 100644 index 0000000..35f30bc --- /dev/null +++ b/UI/Screens/WorldSelectionScreen.cs @@ -0,0 +1,25 @@ +using BuildingGame.Tiles; +using BuildingGame.UI.Elements; +using BuildingGame.UI.Interfaces; + +namespace BuildingGame.UI.Screens; + +public class WorldSelectionScreen : Screen +{ + private WorldMenuUI _ui; + + public override void Initialize() + { + base.Initialize(); + + WorldManager.ReadWorlds(); + _ui = new WorldMenuUI(); + } + + public override void Draw() + { + ClearBackground(new Color(20, 20, 20, 255)); + + base.Draw(); + } +} \ No newline at end of file From e5463e8ef3658c5b66e9191ea0cd82f628064050 Mon Sep 17 00:00:00 2001 From: danil Date: Thu, 18 Jan 2024 20:57:18 +0200 Subject: [PATCH 081/107] move project to Sources --- BuildingGame.sln | 10 +++++----- {Assets => Sources/Assets}/Atlas.png | Bin {Assets => Sources/Assets}/Atlas.yaml | 0 {Assets => Sources/Assets}/Checkmark.png | Bin {Assets => Sources/Assets}/Font.ttf | Bin {Assets => Sources/Assets}/Icon.ico | Bin {Assets => Sources/Assets}/Icon.png | Bin {Assets => Sources/Assets}/Translation.yaml | 0 BuildingGame.csproj => Sources/BuildingGame.csproj | 0 Player.cs => Sources/Player.cs | 0 Program.cs => Sources/Program.cs | 0 .../Raylib.ExtraMethods.cs | 0 Resources.cs => Sources/Resources.cs | 0 Settings.cs => Sources/Settings.cs | 0 {Tiles => Sources/Tiles}/Atlas/AtlasLoader.cs | 0 {Tiles => Sources/Tiles}/Atlas/AtlasTile.cs | 0 {Tiles => Sources/Tiles}/Atlas/AtlasTileKey.cs | 0 {Tiles => Sources/Tiles}/Atlas/AtlasVec2.cs | 0 {Tiles => Sources/Tiles}/Chunk.cs | 0 {Tiles => Sources/Tiles}/Data/ChunkPosition.cs | 0 {Tiles => Sources/Tiles}/Data/TileFlags.cs | 0 {Tiles => Sources/Tiles}/Data/TileInfo.cs | 0 {Tiles => Sources/Tiles}/Data/TileRotation.cs | 0 {Tiles => Sources/Tiles}/Data/WorldInfo.cs | 0 {Tiles => Sources/Tiles}/IO/BGWorld21Format.cs | 0 {Tiles => Sources/Tiles}/IO/BGWorld2Format.cs | 0 {Tiles => Sources/Tiles}/IO/IWorldDeserializer.cs | 0 {Tiles => Sources/Tiles}/IO/IWorldSerializer.cs | 0 {Tiles => Sources/Tiles}/IO/LvlFormat.cs | 0 {Tiles => Sources/Tiles}/IO/WorldIO.cs | 0 {Tiles => Sources/Tiles}/Tile.cs | 0 {Tiles => Sources/Tiles}/Tiles.cs | 0 {Tiles => Sources/Tiles}/World.cs | 0 {Tiles => Sources/Tiles}/WorldManager.cs | 0 .../Translation}/TranslationContainer.cs | 0 .../Translation}/TranslationLoader.cs | 0 {UI => Sources/UI}/Alignment.cs | 0 {UI => Sources/UI}/Brushes/GradientBrush.cs | 0 {UI => Sources/UI}/Brushes/GradientDirection.cs | 0 {UI => Sources/UI}/Brushes/IBrush.cs | 0 {UI => Sources/UI}/Brushes/LineBrush.cs | 0 {UI => Sources/UI}/Brushes/OutlineBrush.cs | 0 {UI => Sources/UI}/Brushes/SolidBrush.cs | 0 {UI => Sources/UI}/Brushes/TextureBrush.cs | 0 {UI => Sources/UI}/Element.cs | 0 {UI => Sources/UI}/ElementComparer.cs | 0 {UI => Sources/UI}/ElementId.cs | 0 {UI => Sources/UI}/Elements/Button.cs | 0 {UI => Sources/UI}/Elements/CheckBox.cs | 0 {UI => Sources/UI}/Elements/ColorLine.cs | 0 {UI => Sources/UI}/Elements/ListBox.cs | 0 {UI => Sources/UI}/Elements/Panel.cs | 0 {UI => Sources/UI}/Elements/TextBox.cs | 0 {UI => Sources/UI}/Elements/TextElement.cs | 0 {UI => Sources/UI}/Elements/Tooltip.cs | 0 {UI => Sources/UI}/GuiManager.cs | 0 {UI => Sources/UI}/Interfaces/BlockUI.cs | 0 {UI => Sources/UI}/Interfaces/CreateWorldUI.cs | 0 {UI => Sources/UI}/Interfaces/GameUI.cs | 0 {UI => Sources/UI}/Interfaces/MenuUI.cs | 0 {UI => Sources/UI}/Interfaces/PauseUI.cs | 0 {UI => Sources/UI}/Interfaces/SettingsUI.cs | 0 {UI => Sources/UI}/Interfaces/UIInterface.cs | 0 {UI => Sources/UI}/Interfaces/UIInterfaceManager.cs | 0 {UI => Sources/UI}/Interfaces/WorldMenuUI.cs | 0 {UI => Sources/UI}/Screens/CreateWorldScreen.cs | 0 {UI => Sources/UI}/Screens/GameScreen.cs | 0 {UI => Sources/UI}/Screens/MenuScreen.cs | 0 {UI => Sources/UI}/Screens/Screen.cs | 0 {UI => Sources/UI}/Screens/ScreenManager.cs | 0 {UI => Sources/UI}/Screens/WorldSelectionScreen.cs | 0 71 files changed, 5 insertions(+), 5 deletions(-) rename {Assets => Sources/Assets}/Atlas.png (100%) rename {Assets => Sources/Assets}/Atlas.yaml (100%) rename {Assets => Sources/Assets}/Checkmark.png (100%) rename {Assets => Sources/Assets}/Font.ttf (100%) rename {Assets => Sources/Assets}/Icon.ico (100%) rename {Assets => Sources/Assets}/Icon.png (100%) rename {Assets => Sources/Assets}/Translation.yaml (100%) rename BuildingGame.csproj => Sources/BuildingGame.csproj (100%) rename Player.cs => Sources/Player.cs (100%) rename Program.cs => Sources/Program.cs (100%) rename Raylib.ExtraMethods.cs => Sources/Raylib.ExtraMethods.cs (100%) rename Resources.cs => Sources/Resources.cs (100%) rename Settings.cs => Sources/Settings.cs (100%) rename {Tiles => Sources/Tiles}/Atlas/AtlasLoader.cs (100%) rename {Tiles => Sources/Tiles}/Atlas/AtlasTile.cs (100%) rename {Tiles => Sources/Tiles}/Atlas/AtlasTileKey.cs (100%) rename {Tiles => Sources/Tiles}/Atlas/AtlasVec2.cs (100%) rename {Tiles => Sources/Tiles}/Chunk.cs (100%) rename {Tiles => Sources/Tiles}/Data/ChunkPosition.cs (100%) rename {Tiles => Sources/Tiles}/Data/TileFlags.cs (100%) rename {Tiles => Sources/Tiles}/Data/TileInfo.cs (100%) rename {Tiles => Sources/Tiles}/Data/TileRotation.cs (100%) rename {Tiles => Sources/Tiles}/Data/WorldInfo.cs (100%) rename {Tiles => Sources/Tiles}/IO/BGWorld21Format.cs (100%) rename {Tiles => Sources/Tiles}/IO/BGWorld2Format.cs (100%) rename {Tiles => Sources/Tiles}/IO/IWorldDeserializer.cs (100%) rename {Tiles => Sources/Tiles}/IO/IWorldSerializer.cs (100%) rename {Tiles => Sources/Tiles}/IO/LvlFormat.cs (100%) rename {Tiles => Sources/Tiles}/IO/WorldIO.cs (100%) rename {Tiles => Sources/Tiles}/Tile.cs (100%) rename {Tiles => Sources/Tiles}/Tiles.cs (100%) rename {Tiles => Sources/Tiles}/World.cs (100%) rename {Tiles => Sources/Tiles}/WorldManager.cs (100%) rename {Translation => Sources/Translation}/TranslationContainer.cs (100%) rename {Translation => Sources/Translation}/TranslationLoader.cs (100%) rename {UI => Sources/UI}/Alignment.cs (100%) rename {UI => Sources/UI}/Brushes/GradientBrush.cs (100%) rename {UI => Sources/UI}/Brushes/GradientDirection.cs (100%) rename {UI => Sources/UI}/Brushes/IBrush.cs (100%) rename {UI => Sources/UI}/Brushes/LineBrush.cs (100%) rename {UI => Sources/UI}/Brushes/OutlineBrush.cs (100%) rename {UI => Sources/UI}/Brushes/SolidBrush.cs (100%) rename {UI => Sources/UI}/Brushes/TextureBrush.cs (100%) rename {UI => Sources/UI}/Element.cs (100%) rename {UI => Sources/UI}/ElementComparer.cs (100%) rename {UI => Sources/UI}/ElementId.cs (100%) rename {UI => Sources/UI}/Elements/Button.cs (100%) rename {UI => Sources/UI}/Elements/CheckBox.cs (100%) rename {UI => Sources/UI}/Elements/ColorLine.cs (100%) rename {UI => Sources/UI}/Elements/ListBox.cs (100%) rename {UI => Sources/UI}/Elements/Panel.cs (100%) rename {UI => Sources/UI}/Elements/TextBox.cs (100%) rename {UI => Sources/UI}/Elements/TextElement.cs (100%) rename {UI => Sources/UI}/Elements/Tooltip.cs (100%) rename {UI => Sources/UI}/GuiManager.cs (100%) rename {UI => Sources/UI}/Interfaces/BlockUI.cs (100%) rename {UI => Sources/UI}/Interfaces/CreateWorldUI.cs (100%) rename {UI => Sources/UI}/Interfaces/GameUI.cs (100%) rename {UI => Sources/UI}/Interfaces/MenuUI.cs (100%) rename {UI => Sources/UI}/Interfaces/PauseUI.cs (100%) rename {UI => Sources/UI}/Interfaces/SettingsUI.cs (100%) rename {UI => Sources/UI}/Interfaces/UIInterface.cs (100%) rename {UI => Sources/UI}/Interfaces/UIInterfaceManager.cs (100%) rename {UI => Sources/UI}/Interfaces/WorldMenuUI.cs (100%) rename {UI => Sources/UI}/Screens/CreateWorldScreen.cs (100%) rename {UI => Sources/UI}/Screens/GameScreen.cs (100%) rename {UI => Sources/UI}/Screens/MenuScreen.cs (100%) rename {UI => Sources/UI}/Screens/Screen.cs (100%) rename {UI => Sources/UI}/Screens/ScreenManager.cs (100%) rename {UI => Sources/UI}/Screens/WorldSelectionScreen.cs (100%) diff --git a/BuildingGame.sln b/BuildingGame.sln index 4e48369..7670508 100644 --- a/BuildingGame.sln +++ b/BuildingGame.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.002.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildingGame", "BuildingGame.csproj", "{602CEEA8-83AB-4D74-974F-308F1BEFB3E5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildingGame", "Sources\BuildingGame.csproj", "{0E5DFCAE-A388-4045-B463-B114D934BCE6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -11,10 +11,10 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {602CEEA8-83AB-4D74-974F-308F1BEFB3E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {602CEEA8-83AB-4D74-974F-308F1BEFB3E5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {602CEEA8-83AB-4D74-974F-308F1BEFB3E5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {602CEEA8-83AB-4D74-974F-308F1BEFB3E5}.Release|Any CPU.Build.0 = Release|Any CPU + {0E5DFCAE-A388-4045-B463-B114D934BCE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E5DFCAE-A388-4045-B463-B114D934BCE6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E5DFCAE-A388-4045-B463-B114D934BCE6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E5DFCAE-A388-4045-B463-B114D934BCE6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Assets/Atlas.png b/Sources/Assets/Atlas.png similarity index 100% rename from Assets/Atlas.png rename to Sources/Assets/Atlas.png diff --git a/Assets/Atlas.yaml b/Sources/Assets/Atlas.yaml similarity index 100% rename from Assets/Atlas.yaml rename to Sources/Assets/Atlas.yaml diff --git a/Assets/Checkmark.png b/Sources/Assets/Checkmark.png similarity index 100% rename from Assets/Checkmark.png rename to Sources/Assets/Checkmark.png diff --git a/Assets/Font.ttf b/Sources/Assets/Font.ttf similarity index 100% rename from Assets/Font.ttf rename to Sources/Assets/Font.ttf diff --git a/Assets/Icon.ico b/Sources/Assets/Icon.ico similarity index 100% rename from Assets/Icon.ico rename to Sources/Assets/Icon.ico diff --git a/Assets/Icon.png b/Sources/Assets/Icon.png similarity index 100% rename from Assets/Icon.png rename to Sources/Assets/Icon.png diff --git a/Assets/Translation.yaml b/Sources/Assets/Translation.yaml similarity index 100% rename from Assets/Translation.yaml rename to Sources/Assets/Translation.yaml diff --git a/BuildingGame.csproj b/Sources/BuildingGame.csproj similarity index 100% rename from BuildingGame.csproj rename to Sources/BuildingGame.csproj diff --git a/Player.cs b/Sources/Player.cs similarity index 100% rename from Player.cs rename to Sources/Player.cs diff --git a/Program.cs b/Sources/Program.cs similarity index 100% rename from Program.cs rename to Sources/Program.cs diff --git a/Raylib.ExtraMethods.cs b/Sources/Raylib.ExtraMethods.cs similarity index 100% rename from Raylib.ExtraMethods.cs rename to Sources/Raylib.ExtraMethods.cs diff --git a/Resources.cs b/Sources/Resources.cs similarity index 100% rename from Resources.cs rename to Sources/Resources.cs diff --git a/Settings.cs b/Sources/Settings.cs similarity index 100% rename from Settings.cs rename to Sources/Settings.cs diff --git a/Tiles/Atlas/AtlasLoader.cs b/Sources/Tiles/Atlas/AtlasLoader.cs similarity index 100% rename from Tiles/Atlas/AtlasLoader.cs rename to Sources/Tiles/Atlas/AtlasLoader.cs diff --git a/Tiles/Atlas/AtlasTile.cs b/Sources/Tiles/Atlas/AtlasTile.cs similarity index 100% rename from Tiles/Atlas/AtlasTile.cs rename to Sources/Tiles/Atlas/AtlasTile.cs diff --git a/Tiles/Atlas/AtlasTileKey.cs b/Sources/Tiles/Atlas/AtlasTileKey.cs similarity index 100% rename from Tiles/Atlas/AtlasTileKey.cs rename to Sources/Tiles/Atlas/AtlasTileKey.cs diff --git a/Tiles/Atlas/AtlasVec2.cs b/Sources/Tiles/Atlas/AtlasVec2.cs similarity index 100% rename from Tiles/Atlas/AtlasVec2.cs rename to Sources/Tiles/Atlas/AtlasVec2.cs diff --git a/Tiles/Chunk.cs b/Sources/Tiles/Chunk.cs similarity index 100% rename from Tiles/Chunk.cs rename to Sources/Tiles/Chunk.cs diff --git a/Tiles/Data/ChunkPosition.cs b/Sources/Tiles/Data/ChunkPosition.cs similarity index 100% rename from Tiles/Data/ChunkPosition.cs rename to Sources/Tiles/Data/ChunkPosition.cs diff --git a/Tiles/Data/TileFlags.cs b/Sources/Tiles/Data/TileFlags.cs similarity index 100% rename from Tiles/Data/TileFlags.cs rename to Sources/Tiles/Data/TileFlags.cs diff --git a/Tiles/Data/TileInfo.cs b/Sources/Tiles/Data/TileInfo.cs similarity index 100% rename from Tiles/Data/TileInfo.cs rename to Sources/Tiles/Data/TileInfo.cs diff --git a/Tiles/Data/TileRotation.cs b/Sources/Tiles/Data/TileRotation.cs similarity index 100% rename from Tiles/Data/TileRotation.cs rename to Sources/Tiles/Data/TileRotation.cs diff --git a/Tiles/Data/WorldInfo.cs b/Sources/Tiles/Data/WorldInfo.cs similarity index 100% rename from Tiles/Data/WorldInfo.cs rename to Sources/Tiles/Data/WorldInfo.cs diff --git a/Tiles/IO/BGWorld21Format.cs b/Sources/Tiles/IO/BGWorld21Format.cs similarity index 100% rename from Tiles/IO/BGWorld21Format.cs rename to Sources/Tiles/IO/BGWorld21Format.cs diff --git a/Tiles/IO/BGWorld2Format.cs b/Sources/Tiles/IO/BGWorld2Format.cs similarity index 100% rename from Tiles/IO/BGWorld2Format.cs rename to Sources/Tiles/IO/BGWorld2Format.cs diff --git a/Tiles/IO/IWorldDeserializer.cs b/Sources/Tiles/IO/IWorldDeserializer.cs similarity index 100% rename from Tiles/IO/IWorldDeserializer.cs rename to Sources/Tiles/IO/IWorldDeserializer.cs diff --git a/Tiles/IO/IWorldSerializer.cs b/Sources/Tiles/IO/IWorldSerializer.cs similarity index 100% rename from Tiles/IO/IWorldSerializer.cs rename to Sources/Tiles/IO/IWorldSerializer.cs diff --git a/Tiles/IO/LvlFormat.cs b/Sources/Tiles/IO/LvlFormat.cs similarity index 100% rename from Tiles/IO/LvlFormat.cs rename to Sources/Tiles/IO/LvlFormat.cs diff --git a/Tiles/IO/WorldIO.cs b/Sources/Tiles/IO/WorldIO.cs similarity index 100% rename from Tiles/IO/WorldIO.cs rename to Sources/Tiles/IO/WorldIO.cs diff --git a/Tiles/Tile.cs b/Sources/Tiles/Tile.cs similarity index 100% rename from Tiles/Tile.cs rename to Sources/Tiles/Tile.cs diff --git a/Tiles/Tiles.cs b/Sources/Tiles/Tiles.cs similarity index 100% rename from Tiles/Tiles.cs rename to Sources/Tiles/Tiles.cs diff --git a/Tiles/World.cs b/Sources/Tiles/World.cs similarity index 100% rename from Tiles/World.cs rename to Sources/Tiles/World.cs diff --git a/Tiles/WorldManager.cs b/Sources/Tiles/WorldManager.cs similarity index 100% rename from Tiles/WorldManager.cs rename to Sources/Tiles/WorldManager.cs diff --git a/Translation/TranslationContainer.cs b/Sources/Translation/TranslationContainer.cs similarity index 100% rename from Translation/TranslationContainer.cs rename to Sources/Translation/TranslationContainer.cs diff --git a/Translation/TranslationLoader.cs b/Sources/Translation/TranslationLoader.cs similarity index 100% rename from Translation/TranslationLoader.cs rename to Sources/Translation/TranslationLoader.cs diff --git a/UI/Alignment.cs b/Sources/UI/Alignment.cs similarity index 100% rename from UI/Alignment.cs rename to Sources/UI/Alignment.cs diff --git a/UI/Brushes/GradientBrush.cs b/Sources/UI/Brushes/GradientBrush.cs similarity index 100% rename from UI/Brushes/GradientBrush.cs rename to Sources/UI/Brushes/GradientBrush.cs diff --git a/UI/Brushes/GradientDirection.cs b/Sources/UI/Brushes/GradientDirection.cs similarity index 100% rename from UI/Brushes/GradientDirection.cs rename to Sources/UI/Brushes/GradientDirection.cs diff --git a/UI/Brushes/IBrush.cs b/Sources/UI/Brushes/IBrush.cs similarity index 100% rename from UI/Brushes/IBrush.cs rename to Sources/UI/Brushes/IBrush.cs diff --git a/UI/Brushes/LineBrush.cs b/Sources/UI/Brushes/LineBrush.cs similarity index 100% rename from UI/Brushes/LineBrush.cs rename to Sources/UI/Brushes/LineBrush.cs diff --git a/UI/Brushes/OutlineBrush.cs b/Sources/UI/Brushes/OutlineBrush.cs similarity index 100% rename from UI/Brushes/OutlineBrush.cs rename to Sources/UI/Brushes/OutlineBrush.cs diff --git a/UI/Brushes/SolidBrush.cs b/Sources/UI/Brushes/SolidBrush.cs similarity index 100% rename from UI/Brushes/SolidBrush.cs rename to Sources/UI/Brushes/SolidBrush.cs diff --git a/UI/Brushes/TextureBrush.cs b/Sources/UI/Brushes/TextureBrush.cs similarity index 100% rename from UI/Brushes/TextureBrush.cs rename to Sources/UI/Brushes/TextureBrush.cs diff --git a/UI/Element.cs b/Sources/UI/Element.cs similarity index 100% rename from UI/Element.cs rename to Sources/UI/Element.cs diff --git a/UI/ElementComparer.cs b/Sources/UI/ElementComparer.cs similarity index 100% rename from UI/ElementComparer.cs rename to Sources/UI/ElementComparer.cs diff --git a/UI/ElementId.cs b/Sources/UI/ElementId.cs similarity index 100% rename from UI/ElementId.cs rename to Sources/UI/ElementId.cs diff --git a/UI/Elements/Button.cs b/Sources/UI/Elements/Button.cs similarity index 100% rename from UI/Elements/Button.cs rename to Sources/UI/Elements/Button.cs diff --git a/UI/Elements/CheckBox.cs b/Sources/UI/Elements/CheckBox.cs similarity index 100% rename from UI/Elements/CheckBox.cs rename to Sources/UI/Elements/CheckBox.cs diff --git a/UI/Elements/ColorLine.cs b/Sources/UI/Elements/ColorLine.cs similarity index 100% rename from UI/Elements/ColorLine.cs rename to Sources/UI/Elements/ColorLine.cs diff --git a/UI/Elements/ListBox.cs b/Sources/UI/Elements/ListBox.cs similarity index 100% rename from UI/Elements/ListBox.cs rename to Sources/UI/Elements/ListBox.cs diff --git a/UI/Elements/Panel.cs b/Sources/UI/Elements/Panel.cs similarity index 100% rename from UI/Elements/Panel.cs rename to Sources/UI/Elements/Panel.cs diff --git a/UI/Elements/TextBox.cs b/Sources/UI/Elements/TextBox.cs similarity index 100% rename from UI/Elements/TextBox.cs rename to Sources/UI/Elements/TextBox.cs diff --git a/UI/Elements/TextElement.cs b/Sources/UI/Elements/TextElement.cs similarity index 100% rename from UI/Elements/TextElement.cs rename to Sources/UI/Elements/TextElement.cs diff --git a/UI/Elements/Tooltip.cs b/Sources/UI/Elements/Tooltip.cs similarity index 100% rename from UI/Elements/Tooltip.cs rename to Sources/UI/Elements/Tooltip.cs diff --git a/UI/GuiManager.cs b/Sources/UI/GuiManager.cs similarity index 100% rename from UI/GuiManager.cs rename to Sources/UI/GuiManager.cs diff --git a/UI/Interfaces/BlockUI.cs b/Sources/UI/Interfaces/BlockUI.cs similarity index 100% rename from UI/Interfaces/BlockUI.cs rename to Sources/UI/Interfaces/BlockUI.cs diff --git a/UI/Interfaces/CreateWorldUI.cs b/Sources/UI/Interfaces/CreateWorldUI.cs similarity index 100% rename from UI/Interfaces/CreateWorldUI.cs rename to Sources/UI/Interfaces/CreateWorldUI.cs diff --git a/UI/Interfaces/GameUI.cs b/Sources/UI/Interfaces/GameUI.cs similarity index 100% rename from UI/Interfaces/GameUI.cs rename to Sources/UI/Interfaces/GameUI.cs diff --git a/UI/Interfaces/MenuUI.cs b/Sources/UI/Interfaces/MenuUI.cs similarity index 100% rename from UI/Interfaces/MenuUI.cs rename to Sources/UI/Interfaces/MenuUI.cs diff --git a/UI/Interfaces/PauseUI.cs b/Sources/UI/Interfaces/PauseUI.cs similarity index 100% rename from UI/Interfaces/PauseUI.cs rename to Sources/UI/Interfaces/PauseUI.cs diff --git a/UI/Interfaces/SettingsUI.cs b/Sources/UI/Interfaces/SettingsUI.cs similarity index 100% rename from UI/Interfaces/SettingsUI.cs rename to Sources/UI/Interfaces/SettingsUI.cs diff --git a/UI/Interfaces/UIInterface.cs b/Sources/UI/Interfaces/UIInterface.cs similarity index 100% rename from UI/Interfaces/UIInterface.cs rename to Sources/UI/Interfaces/UIInterface.cs diff --git a/UI/Interfaces/UIInterfaceManager.cs b/Sources/UI/Interfaces/UIInterfaceManager.cs similarity index 100% rename from UI/Interfaces/UIInterfaceManager.cs rename to Sources/UI/Interfaces/UIInterfaceManager.cs diff --git a/UI/Interfaces/WorldMenuUI.cs b/Sources/UI/Interfaces/WorldMenuUI.cs similarity index 100% rename from UI/Interfaces/WorldMenuUI.cs rename to Sources/UI/Interfaces/WorldMenuUI.cs diff --git a/UI/Screens/CreateWorldScreen.cs b/Sources/UI/Screens/CreateWorldScreen.cs similarity index 100% rename from UI/Screens/CreateWorldScreen.cs rename to Sources/UI/Screens/CreateWorldScreen.cs diff --git a/UI/Screens/GameScreen.cs b/Sources/UI/Screens/GameScreen.cs similarity index 100% rename from UI/Screens/GameScreen.cs rename to Sources/UI/Screens/GameScreen.cs diff --git a/UI/Screens/MenuScreen.cs b/Sources/UI/Screens/MenuScreen.cs similarity index 100% rename from UI/Screens/MenuScreen.cs rename to Sources/UI/Screens/MenuScreen.cs diff --git a/UI/Screens/Screen.cs b/Sources/UI/Screens/Screen.cs similarity index 100% rename from UI/Screens/Screen.cs rename to Sources/UI/Screens/Screen.cs diff --git a/UI/Screens/ScreenManager.cs b/Sources/UI/Screens/ScreenManager.cs similarity index 100% rename from UI/Screens/ScreenManager.cs rename to Sources/UI/Screens/ScreenManager.cs diff --git a/UI/Screens/WorldSelectionScreen.cs b/Sources/UI/Screens/WorldSelectionScreen.cs similarity index 100% rename from UI/Screens/WorldSelectionScreen.cs rename to Sources/UI/Screens/WorldSelectionScreen.cs From 1e47672e127b5fa8b8f375d0f0b4666efd0f692a Mon Sep 17 00:00:00 2001 From: danil Date: Thu, 18 Jan 2024 21:07:19 +0200 Subject: [PATCH 082/107] removed comically sitting .vscode folder --- .vscode/launch.json | 27 --------------------------- .vscode/tasks.json | 41 ----------------------------------------- 2 files changed, 68 deletions(-) delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index cfac8aa..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - // Use IntelliSense to find out which attributes exist for C# debugging - // Use hover for the description of the existing attributes - // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md - "name": "run building game", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/bin/Debug/net7.0-windows/BuildingGame.dll", - "args": [], - "requireExactSource": false, - "cwd": "${workspaceFolder}/bin/Debug/net7.0-windows/", - // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console - "console": "internalConsole", - "stopAtEntry": false - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach" - } - ] -} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 5996fd7..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "build", - "command": "dotnet", - "type": "process", - "args": [ - "build", - "${workspaceFolder}/BuildingGame.csproj", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "problemMatcher": "$msCompile" - }, - { - "label": "publish", - "command": "dotnet", - "type": "process", - "args": [ - "publish", - "${workspaceFolder}/BuildingGame.csproj", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "problemMatcher": "$msCompile" - }, - { - "label": "watch", - "command": "dotnet", - "type": "process", - "args": [ - "watch", - "run", - "--project", - "${workspaceFolder}/BuildingGame.csproj" - ], - "problemMatcher": "$msCompile" - } - ] -} \ No newline at end of file From 87e135c0d0e909c329f1b215a42d91bb64f87dc0 Mon Sep 17 00:00:00 2001 From: danil Date: Thu, 18 Jan 2024 21:17:52 +0200 Subject: [PATCH 083/107] create swag readme --- Assets/IconLarge.png | Bin 0 -> 6503 bytes Assets/TheWorld.png | Bin 0 -> 65952 bytes README.md | 29 ++++++++++++++++++++++++++--- 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 Assets/IconLarge.png create mode 100644 Assets/TheWorld.png diff --git a/Assets/IconLarge.png b/Assets/IconLarge.png new file mode 100644 index 0000000000000000000000000000000000000000..a57e92170ba37bbce04f1acb3d678868c803e4b2 GIT binary patch literal 6503 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 F{|9kS03iSX literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 70cee3c..ebe5ebb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,26 @@ -# BuildingGame -game where you can just place tiles -> Warning: this is temporairy branch and may become main after 21 years + + +**building game** +a game, where you just place tiles + +![the world](Assets/TheWorld.png) + +### rewriting progress +- [x] the world!!! +- [x] pause +- [x] settings +- [x] main menu +- [ ] tile packs +- [ ] dynamic tiles +- [ ] infection ~~block~~ tile + +### new features +- bugs +- better camera +- localization +- bad, but more stable than previous, ui framework +- dynamic tile atlas (reloadable ingame) +- world menu but better + + +#### made with 🐛🐛🐛 by danilwhale (rooster) :3 \ No newline at end of file From 860cd38d53a08724befe8933b26efcbd9383895f Mon Sep 17 00:00:00 2001 From: danil Date: Thu, 18 Jan 2024 21:20:38 +0200 Subject: [PATCH 084/107] update redmi --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ebe5ebb..500a0c2 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ - + + +### building game -**building game** a game, where you just place tiles +--- + ![the world](Assets/TheWorld.png) ### rewriting progress From a9b2012decb039f16c1d4e02479a41899e687f18 Mon Sep 17 00:00:00 2001 From: danil Date: Fri, 19 Jan 2024 14:23:12 +0200 Subject: [PATCH 085/107] remove debug code from list box --- Sources/UI/Elements/ListBox.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Sources/UI/Elements/ListBox.cs b/Sources/UI/Elements/ListBox.cs index abd9b84..840a651 100644 --- a/Sources/UI/Elements/ListBox.cs +++ b/Sources/UI/Elements/ListBox.cs @@ -46,8 +46,6 @@ public override void Update() if (_scroll > 0) _scroll = 0; if (_scroll <= -boxHeight / 2) _scroll = -boxHeight / 2; } - - Console.WriteLine(_scroll); } if (IsClicked()) From 09b2d3d1fb03013abe38da5d5436be2aa2bc2370 Mon Sep 17 00:00:00 2001 From: danil Date: Fri, 19 Jan 2024 14:29:47 +0200 Subject: [PATCH 086/107] invert update loops --- Sources/Tiles/Chunk.cs | 4 ++-- Sources/Tiles/World.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/Tiles/Chunk.cs b/Sources/Tiles/Chunk.cs index 1a20b4e..39c6e06 100644 --- a/Sources/Tiles/Chunk.cs +++ b/Sources/Tiles/Chunk.cs @@ -31,9 +31,9 @@ public Chunk(World world, int x, int y) public void Update() { - for (int x = 0; x < Size; x++) + for (int x = Size - 1; x >= 0; x--) { - for (int y = 0; y < Size; y++) + for (int y = Size - 1; y >= 0; y--) { TileInfo tile = _tiles[x][y]; if (tile == 0) continue; diff --git a/Sources/Tiles/World.cs b/Sources/Tiles/World.cs index 854888d..b720c49 100644 --- a/Sources/Tiles/World.cs +++ b/Sources/Tiles/World.cs @@ -44,9 +44,9 @@ public World(int width, int height) public void Update() { - for (int x = 0; x < ChunkWidth; x++) + for (int x = ChunkWidth - 1; x >= 0; x--) { - for (int y = 0; y < ChunkHeight; y++) + for (int y = ChunkHeight - 1; y >= 0; y--) { _chunks[x][y].Update(); } From 29d7d202588bdb6960266c805dbcb43ec5f5e3da Mon Sep 17 00:00:00 2001 From: danil Date: Fri, 19 Jan 2024 14:30:19 +0200 Subject: [PATCH 087/107] add ability to get tile id by name --- Sources/Tiles/Tiles.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Sources/Tiles/Tiles.cs b/Sources/Tiles/Tiles.cs index e3797cf..cc63a49 100644 --- a/Sources/Tiles/Tiles.cs +++ b/Sources/Tiles/Tiles.cs @@ -23,6 +23,12 @@ public static Tile GetTile(string name) return _Tiles.First(kv => string.Equals(kv.Key.Name, name, StringComparison.CurrentCultureIgnoreCase)).Value; } + public static byte GetId(Tile tile) + { + var key = _Tiles.FirstOrDefault(kv => kv.Value == tile).Key; + return key.Id; + } + public static Tile[] GetTiles() { return _Tiles.Values.ToArray(); From ae5382deeac44912858150707ee8301d1840e73b Mon Sep 17 00:00:00 2001 From: danil Date: Fri, 19 Jan 2024 14:30:39 +0200 Subject: [PATCH 088/107] fix registering custom tile --- Sources/Tiles/Tile.cs | 6 +++--- Sources/Tiles/Tiles.cs | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Sources/Tiles/Tile.cs b/Sources/Tiles/Tile.cs index 5daa4c9..0406d74 100644 --- a/Sources/Tiles/Tile.cs +++ b/Sources/Tiles/Tile.cs @@ -10,9 +10,9 @@ public class Tile public const float RealTileSize = TileSize * TileUpscale; public const float AtlasFraction = 0.25f; - public readonly Vector2 TexCoord; - public readonly Vector2 Size = Vector2.One; - public readonly string TranslationKey = ""; + public Vector2 TexCoord; + public Vector2 Size = Vector2.One; + public string TranslationKey = ""; public Tile() { diff --git a/Sources/Tiles/Tiles.cs b/Sources/Tiles/Tiles.cs index cc63a49..1f95cc8 100644 --- a/Sources/Tiles/Tiles.cs +++ b/Sources/Tiles/Tiles.cs @@ -37,6 +37,12 @@ public static Tile[] GetTiles() public static void RegisterCustomTile(string name, T tile) where T : Tile { var key = _Tiles.Keys.First(k => string.Equals(k.Name, name, StringComparison.CurrentCultureIgnoreCase)); + var value = _Tiles[key]; + + tile.Size = value.Size; + tile.TexCoord = value.TexCoord; + tile.TranslationKey = value.TranslationKey; + _Tiles[key] = tile; } From 53d9e0fb6013e8dfca6b993c13a79b0b4caa5b08 Mon Sep 17 00:00:00 2001 From: danil Date: Fri, 19 Jan 2024 14:31:18 +0200 Subject: [PATCH 089/107] add static tile updates --- Sources/Tiles/Tile.cs | 5 +++++ Sources/Tiles/Tiles.cs | 14 ++++++++++++++ Sources/UI/Screens/GameScreen.cs | 4 +++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Sources/Tiles/Tile.cs b/Sources/Tiles/Tile.cs index 0406d74..6ce42c7 100644 --- a/Sources/Tiles/Tile.cs +++ b/Sources/Tiles/Tile.cs @@ -46,6 +46,11 @@ public virtual void Update(World world, TileInfo info, int x, int y) { } + public virtual void StaticUpdate() + { + + } + public virtual void Draw(World world, TileInfo info, float x, float y, Color tint) { DrawTexturePro(Resources.GetTexture("Atlas.png"), diff --git a/Sources/Tiles/Tiles.cs b/Sources/Tiles/Tiles.cs index 1f95cc8..5309293 100644 --- a/Sources/Tiles/Tiles.cs +++ b/Sources/Tiles/Tiles.cs @@ -34,6 +34,14 @@ public static Tile[] GetTiles() return _Tiles.Values.ToArray(); } + public static void Update() + { + foreach (var kv in _Tiles) + { + kv.Value.StaticUpdate(); + } + } + public static void RegisterCustomTile(string name, T tile) where T : Tile { var key = _Tiles.Keys.First(k => string.Equals(k.Name, name, StringComparison.CurrentCultureIgnoreCase)); @@ -49,6 +57,12 @@ public static void RegisterCustomTile(string name, T tile) where T : Tile public static void RegisterCustomTile(byte id, T tile) where T : Tile { var key = _Tiles.Keys.First(k => k.Id == id); + var value = _Tiles[key]; + + tile.Size = value.Size; + tile.TexCoord = value.TexCoord; + tile.TranslationKey = value.TranslationKey; + _Tiles[key] = tile; } } \ No newline at end of file diff --git a/Sources/UI/Screens/GameScreen.cs b/Sources/UI/Screens/GameScreen.cs index 213a0b0..1e46ab4 100644 --- a/Sources/UI/Screens/GameScreen.cs +++ b/Sources/UI/Screens/GameScreen.cs @@ -45,7 +45,9 @@ public override void Update() if (!Program.Paused) { _playTime += TimeSpan.FromSeconds(GetFrameTime()); - + + Tiles.Tiles.Update(); + _player.Update(); _world.Update(); } From e549999cdacec94fffbdd8750ce68f0021e7222e Mon Sep 17 00:00:00 2001 From: danil Date: Fri, 19 Jan 2024 15:46:11 +0200 Subject: [PATCH 090/107] check translation key for equality too --- Sources/Tiles/Tile.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Tiles/Tile.cs b/Sources/Tiles/Tile.cs index 6ce42c7..59997b8 100644 --- a/Sources/Tiles/Tile.cs +++ b/Sources/Tiles/Tile.cs @@ -78,7 +78,7 @@ public virtual void DrawPreview(World world, TileInfo info, float x, float y) public override bool Equals(object? obj) { - return obj is Tile t && t.TexCoord == TexCoord && t.Size == Size; + return obj is Tile t && t.TexCoord == TexCoord && t.Size == Size && string.Equals(t.TranslationKey, TranslationKey, StringComparison.CurrentCultureIgnoreCase); } public override int GetHashCode() From 3a65946aa685d03b4b161925864c89d0448fb012 Mon Sep 17 00:00:00 2001 From: danil Date: Thu, 15 Feb 2024 12:32:17 +0200 Subject: [PATCH 091/107] add and use Tiles.TryGetTile --- Sources/Player.cs | 4 ++-- Sources/Tiles/Chunk.cs | 19 +++++++++++++------ Sources/Tiles/Tiles.cs | 22 ++++++++++++++++++---- Sources/UI/Interfaces/GameUI.cs | 3 ++- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/Sources/Player.cs b/Sources/Player.cs index b4fae45..87f4a28 100644 --- a/Sources/Player.cs +++ b/Sources/Player.cs @@ -68,9 +68,9 @@ public void Update() public void Draw() { - if (!GuiManager.IsMouseOverElement()) + if (!GuiManager.IsMouseOverElement() && Tiles.Tiles.TryGetTile(CurrentTile.Id, out var tile)) { - Tiles.Tiles.GetTile(CurrentTile.Id).DrawPreview( + tile.DrawPreview( World, CurrentTile, _tileX, _tileY ); diff --git a/Sources/Tiles/Chunk.cs b/Sources/Tiles/Chunk.cs index 39c6e06..4fb8722 100644 --- a/Sources/Tiles/Chunk.cs +++ b/Sources/Tiles/Chunk.cs @@ -31,13 +31,17 @@ public Chunk(World world, int x, int y) public void Update() { + + for (int x = Size - 1; x >= 0; x--) { for (int y = Size - 1; y >= 0; y--) { - TileInfo tile = _tiles[x][y]; - if (tile == 0) continue; - Tiles.GetTile(tile).Update(World, tile, X * Size + x, Y * Size + y); + TileInfo info = _tiles[x][y]; + if (info == 0) continue; + if (!Tiles.TryGetTile(info, out var tile)) continue; + + tile.Update(World, info, X * Size + x, Y * Size + y); } } } @@ -48,9 +52,11 @@ public void Draw() { for (int y = 0; y < Size; y++) { - TileInfo tile = _tiles[x][y]; - if (tile == 0) continue; - Tiles.GetTile(tile).Draw(World, tile, X * Size + x, Y * Size + y, Color.WHITE); + TileInfo info = _tiles[x][y]; + if (info== 0) continue; + if (!Tiles.TryGetTile(info, out var tile)) continue; + + tile.Draw(World, info, X * Size + x, Y * Size + y, Color.WHITE); } } } @@ -67,6 +73,7 @@ public void Draw() { if (x < 0 || x >= Size || y < 0 || y >= Size) return; + _tiles[x][y] = value; } } diff --git a/Sources/Tiles/Tiles.cs b/Sources/Tiles/Tiles.cs index 5309293..80d7cdf 100644 --- a/Sources/Tiles/Tiles.cs +++ b/Sources/Tiles/Tiles.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using BuildingGame.Tiles.Atlas; using BuildingGame.Translation; @@ -12,15 +13,28 @@ public static void Reload() _Tiles = AtlasLoader.ConvertTiles(AtlasLoader.LoadTiles()); } + [Obsolete("use TryGetTile instead pls ty", true)] public static Tile GetTile(byte id) { - if (id < 1) throw new ArgumentException("Id mustn't be an air (0)", nameof(id)); - return _Tiles.First(kv => kv.Key.Id == id).Value; + throw new Exception("use TryGetTile instead pls ty"); } - + + [Obsolete("use TryGetTile instead pls ty", true)] public static Tile GetTile(string name) { - return _Tiles.First(kv => string.Equals(kv.Key.Name, name, StringComparison.CurrentCultureIgnoreCase)).Value; + throw new Exception("use TryGetTile instead pls ty"); + } + + public static bool TryGetTile(byte id, [NotNullWhen(true)] out Tile? tile) + { + tile = _Tiles.FirstOrDefault(kv => kv.Key.Id == id).Value; + return tile != null; + } + + public static bool TryGetTile(string name, [NotNullWhen(true)] out Tile? tile) + { + tile = _Tiles.FirstOrDefault(kv => string.Equals(kv.Key.Name, name, StringComparison.CurrentCultureIgnoreCase)).Value; + return tile != null; } public static byte GetId(Tile tile) diff --git a/Sources/UI/Interfaces/GameUI.cs b/Sources/UI/Interfaces/GameUI.cs index 9b22b7f..d42da67 100644 --- a/Sources/UI/Interfaces/GameUI.cs +++ b/Sources/UI/Interfaces/GameUI.cs @@ -52,8 +52,9 @@ public override void Update() { base.Update(); + if (!Tiles.Tiles.TryGetTile(Player.CurrentTile, out var tile)) return; + var brush = (TextureBrush)_tileMenuButton.BackgroundBrush!; - var tile = Tiles.Tiles.GetTile(Player.CurrentTile); (brush.CropArea.X, brush.CropArea.Y) = (tile.TexCoord.X * Tile.TileSize, tile.TexCoord.Y * Tile.TileSize); } From 243c22946ee805f65a51c8f70d565d4d90e72352 Mon Sep 17 00:00:00 2001 From: danil Date: Thu, 15 Feb 2024 12:32:53 +0200 Subject: [PATCH 092/107] update libraries --- Sources/BuildingGame.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/BuildingGame.csproj b/Sources/BuildingGame.csproj index 9fb64f2..61cbc36 100644 --- a/Sources/BuildingGame.csproj +++ b/Sources/BuildingGame.csproj @@ -27,11 +27,11 @@ - - - + + + - + From 0e36b9dd336e29b9db23f8671c87e105285b5f1a Mon Sep 17 00:00:00 2001 From: danil Date: Thu, 15 Feb 2024 12:55:23 +0200 Subject: [PATCH 093/107] update to raylib-cs 6.0 --- Sources/Player.cs | 18 +++++++++--------- Sources/Program.cs | 6 +++--- Sources/Settings.cs | 2 +- Sources/Tiles/Chunk.cs | 2 +- Sources/UI/Brushes/TextureBrush.cs | 2 +- Sources/UI/Element.cs | 12 ++++++------ Sources/UI/Elements/CheckBox.cs | 6 +++--- Sources/UI/Elements/ColorLine.cs | 4 ++-- Sources/UI/Elements/ListBox.cs | 2 +- Sources/UI/Elements/TextBox.cs | 10 +++++----- Sources/UI/Elements/TextElement.cs | 2 +- Sources/UI/Elements/Tooltip.cs | 2 +- Sources/UI/Interfaces/BlockUI.cs | 6 +++--- Sources/UI/Interfaces/PauseUI.cs | 4 ++-- Sources/UI/Interfaces/SettingsUI.cs | 2 +- Sources/UI/Interfaces/WorldMenuUI.cs | 2 +- Sources/UI/Screens/GameScreen.cs | 2 +- 17 files changed, 42 insertions(+), 42 deletions(-) diff --git a/Sources/Player.cs b/Sources/Player.cs index 87f4a28..2bbe8df 100644 --- a/Sources/Player.cs +++ b/Sources/Player.cs @@ -45,17 +45,17 @@ public void Update() if (scrollDelta > 0) ZoomIn(Speed * 0.075f); // get speed depending if user is sprinting or not - float speed = IsKeyDown(KeyboardKey.KEY_LEFT_CONTROL) || IsKeyDown(KeyboardKey.KEY_LEFT_SHIFT) + float speed = IsKeyDown(KeyboardKey.LeftControl) || IsKeyDown(KeyboardKey.LeftShift) ? Speed * 1.25f : Speed * 0.5f; speed /= Camera.Zoom; speed = Math.Clamp(speed, 0, Speed * 2); // move camera - if (IsKeyDown(KeyboardKey.KEY_W) && !GuiManager.IsFocused) Move(0, -speed); - if (IsKeyDown(KeyboardKey.KEY_S) && !GuiManager.IsFocused) Move(0, speed); - if (IsKeyDown(KeyboardKey.KEY_A) && !GuiManager.IsFocused) Move(-speed, 0); - if (IsKeyDown(KeyboardKey.KEY_D) && !GuiManager.IsFocused) Move(speed, 0); + if (IsKeyDown(KeyboardKey.W) && !GuiManager.IsFocused) Move(0, -speed); + if (IsKeyDown(KeyboardKey.S) && !GuiManager.IsFocused) Move(0, speed); + if (IsKeyDown(KeyboardKey.A) && !GuiManager.IsFocused) Move(-speed, 0); + if (IsKeyDown(KeyboardKey.D) && !GuiManager.IsFocused) Move(speed, 0); // adapt camera center when windows is resized if (IsWindowResized()) @@ -84,24 +84,24 @@ private void UpdateTileControls() _tileX = (int)(worldMousePos.X / Tile.RealTileSize); _tileY = (int)(worldMousePos.Y / Tile.RealTileSize); - if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_LEFT) && !GuiManager.IsMouseOverElement()) + if (IsMouseButtonDown(MouseButton.Left) && !GuiManager.IsMouseOverElement()) { World[_tileX, _tileY] = CurrentTile; } - if (IsMouseButtonDown(MouseButton.MOUSE_BUTTON_RIGHT) && !GuiManager.IsMouseOverElement()) + if (IsMouseButtonDown(MouseButton.Right) && !GuiManager.IsMouseOverElement()) { World[_tileX, _tileY] = 0; } - if (IsKeyReleased(KeyboardKey.KEY_R)) + if (IsKeyReleased(KeyboardKey.R)) { CurrentTile.Flags.Rotation = (TileRotation)(CurrentTile.Flags.Rotation + 1); if ((int)CurrentTile.Flags.Rotation > (int)TileRotation.Right) CurrentTile.Flags.Rotation = TileRotation.Up; } - if (IsKeyReleased(KeyboardKey.KEY_T)) + if (IsKeyReleased(KeyboardKey.T)) { CurrentTile.Flags.FlipRotation(); } diff --git a/Sources/Program.cs b/Sources/Program.cs index b3172d3..2f1cbad 100644 --- a/Sources/Program.cs +++ b/Sources/Program.cs @@ -22,10 +22,10 @@ internal class Program public static void Main(string[] args) { - SetConfigFlags(ConfigFlags.FLAG_VSYNC_HINT); - SetConfigFlags(ConfigFlags.FLAG_WINDOW_RESIZABLE); + SetConfigFlags(ConfigFlags.VSyncHint); + SetConfigFlags(ConfigFlags.ResizableWindow); InitWindow(1024, 768, "building game"); - SetExitKey(KeyboardKey.KEY_NULL); + SetExitKey(KeyboardKey.Null); // set window icon Image icon = LoadImage("Assets/Icon.png"); diff --git a/Sources/Settings.cs b/Sources/Settings.cs index 7cf3f6e..98ae3b8 100644 --- a/Sources/Settings.cs +++ b/Sources/Settings.cs @@ -17,7 +17,7 @@ public record struct Record(Color SkyColor); .WithNamingConvention(UnderscoredNamingConvention.Instance) .Build(); - public static Color SkyColor = Color.SKYBLUE; + public static Color SkyColor = Color.SkyBlue; public static void Load() { diff --git a/Sources/Tiles/Chunk.cs b/Sources/Tiles/Chunk.cs index 4fb8722..089fa3e 100644 --- a/Sources/Tiles/Chunk.cs +++ b/Sources/Tiles/Chunk.cs @@ -56,7 +56,7 @@ public void Draw() if (info== 0) continue; if (!Tiles.TryGetTile(info, out var tile)) continue; - tile.Draw(World, info, X * Size + x, Y * Size + y, Color.WHITE); + tile.Draw(World, info, X * Size + x, Y * Size + y, Color.White); } } } diff --git a/Sources/UI/Brushes/TextureBrush.cs b/Sources/UI/Brushes/TextureBrush.cs index 6865787..e4d9730 100644 --- a/Sources/UI/Brushes/TextureBrush.cs +++ b/Sources/UI/Brushes/TextureBrush.cs @@ -5,7 +5,7 @@ namespace BuildingGame.UI.Brushes; public class TextureBrush : IBrush { public Texture2D Texture; - public Color Tint = Color.WHITE; + public Color Tint = Color.White; public Rectangle CropArea; public TextureBrush(Texture2D texture) diff --git a/Sources/UI/Element.cs b/Sources/UI/Element.cs index 1b93f72..ee7443e 100644 --- a/Sources/UI/Element.cs +++ b/Sources/UI/Element.cs @@ -189,7 +189,7 @@ public void Draw() }; BeginTextureMode(_controlTexture); - ClearBackground(Color.BLANK); + ClearBackground(Color.Blank); Render(); @@ -202,14 +202,14 @@ public void Draw() _Area.Width - 0.25f, -_Area.Height + 0.25f // we need to negate render texture height because opengl uses bottom-left instead of top-left ), _Area, offset, Rotation, - Color.WHITE + Color.White ); } protected virtual void Render() { - ClearBackground(Color.BLACK); - DrawText(":(", 0, 0, 16, Color.WHITE); + ClearBackground(Color.Black); + DrawText(":(", 0, 0, 16, Color.White); } public bool IsUnderMouse() @@ -219,12 +219,12 @@ public bool IsUnderMouse() public bool IsClicked() { - return IsUnderMouse() && IsMouseButtonReleased(MouseButton.MOUSE_BUTTON_LEFT) && Visible && Active; + return IsUnderMouse() && IsMouseButtonReleased(MouseButton.Left) && Visible && Active; } public bool IsPressed() { - return IsUnderMouse() && IsMouseButtonDown(MouseButton.MOUSE_BUTTON_LEFT) && Visible && Active; + return IsUnderMouse() && IsMouseButtonDown(MouseButton.Left) && Visible && Active; } public void Dispose() diff --git a/Sources/UI/Elements/CheckBox.cs b/Sources/UI/Elements/CheckBox.cs index 5b29e81..3d964ef 100644 --- a/Sources/UI/Elements/CheckBox.cs +++ b/Sources/UI/Elements/CheckBox.cs @@ -7,12 +7,12 @@ public class CheckBox : Element { public bool Checked; - public IBrush? CheckBoxBrush = new OutlineBrush(Color.GRAY, Color.LIGHTGRAY); + public IBrush? CheckBoxBrush = new OutlineBrush(Color.Gray, Color.LightGray); public float BoxScale = 1f; public string Text = string.Empty; public float TextSize = 12; - public Color TextColor = Color.WHITE; + public Color TextColor = Color.White; public CheckBox(ElementId id) : base(id) @@ -39,7 +39,7 @@ protected override void Render() Resources.GetTexture("Checkmark.png"), new Rectangle(0, 0, 18, 18), boxArea, - Vector2.Zero, 0, Color.WHITE); + Vector2.Zero, 0, Color.White); } DrawText(Text, 8 + 18 * BoxScale, Area.Height / 2 - TextSize / 2f, TextSize, TextColor); diff --git a/Sources/UI/Elements/ColorLine.cs b/Sources/UI/Elements/ColorLine.cs index abb5186..906aa7b 100644 --- a/Sources/UI/Elements/ColorLine.cs +++ b/Sources/UI/Elements/ColorLine.cs @@ -54,7 +54,7 @@ public Color Color set => (R, G, B) = (value.R, value.G, value.B); } - public Color DefaultColor = Color.WHITE; + public Color DefaultColor = Color.White; private Panel _colorPreview; private TextBox _redBox; @@ -70,7 +70,7 @@ public ColorLine(ElementId id) : base(id) _colorPreview = new Panel(new ElementId(id, "colorPreview")) { - Brush = new OutlineBrush(Color.DARKGRAY, DefaultColor), + Brush = new OutlineBrush(Color.DarkGray, DefaultColor), LocalPosition = new Vector2(0, 0), Parent = this, Size = new Vector2(40.0f, 20.0f) diff --git a/Sources/UI/Elements/ListBox.cs b/Sources/UI/Elements/ListBox.cs index 840a651..7e1f8aa 100644 --- a/Sources/UI/Elements/ListBox.cs +++ b/Sources/UI/Elements/ListBox.cs @@ -16,7 +16,7 @@ public class ListBox : Element public float ItemTextSize = 12; public float ItemPadding = 4; - public Color ItemColor = Color.WHITE; + public Color ItemColor = Color.White; public int SelectedItem = -1; private float _scroll = 0; diff --git a/Sources/UI/Elements/TextBox.cs b/Sources/UI/Elements/TextBox.cs index a83e399..8d7c27a 100644 --- a/Sources/UI/Elements/TextBox.cs +++ b/Sources/UI/Elements/TextBox.cs @@ -16,18 +16,18 @@ public class TextBox : TextElement public TextBox(ElementId id) : base(id) { - _brush = new OutlineBrush(Color.BLACK, Color.LIGHTGRAY); - TextColor = Color.BLACK; + _brush = new OutlineBrush(Color.Black, Color.LightGray); + TextColor = Color.Black; } public override void Update() { base.Update(); - if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT)) + if (IsMouseButtonPressed(MouseButton.Left)) { _focused = IsUnderMouse(); - _brush.LineColor = _focused ? Color.GRAY : Color.BLACK; + _brush.LineColor = _focused ? Color.Gray : Color.Black; // _brush.LineThick = _focused ? 1.5f : 1; GuiManager.IsFocused = _focused; @@ -46,7 +46,7 @@ private void GatherInput() if (c >= CharacterRange.Start.Value && c <= CharacterRange.End.Value && Text.Length < MaxCharacters) Text += char.ConvertFromUtf32(c); - if (IsKeyPressed(KeyboardKey.KEY_BACKSPACE) && Text.Length > 0) + if (IsKeyPressedRepeat(KeyboardKey.Backspace) && Text.Length > 0) Text = Text.Remove(Text.Length - 1); OnTextUpdate?.Invoke(Text); diff --git a/Sources/UI/Elements/TextElement.cs b/Sources/UI/Elements/TextElement.cs index cb2c43e..114f257 100644 --- a/Sources/UI/Elements/TextElement.cs +++ b/Sources/UI/Elements/TextElement.cs @@ -7,7 +7,7 @@ public class TextElement : Element { public IBrush? BackgroundBrush; - public Color TextColor = Color.WHITE; + public Color TextColor = Color.White; public string Text = string.Empty; public float TextSize = 10; public Alignment TextAlignment = Alignment.TopLeft; diff --git a/Sources/UI/Elements/Tooltip.cs b/Sources/UI/Elements/Tooltip.cs index bda891d..5504d9e 100644 --- a/Sources/UI/Elements/Tooltip.cs +++ b/Sources/UI/Elements/Tooltip.cs @@ -38,6 +38,6 @@ public override void Update() protected override void Render() { _brush.FillArea(new Rectangle(0, 0, Size.X, Size.Y)); - DrawText(Text, 8.0f, 8.0f, TextSize, Color.WHITE); + DrawText(Text, 8.0f, 8.0f, TextSize, Color.White); } } \ No newline at end of file diff --git a/Sources/UI/Interfaces/BlockUI.cs b/Sources/UI/Interfaces/BlockUI.cs index 40427da..c51353c 100644 --- a/Sources/UI/Interfaces/BlockUI.cs +++ b/Sources/UI/Interfaces/BlockUI.cs @@ -29,7 +29,7 @@ public override void Initialize() _menuTitle = new TextElement(new ElementId("blockMenu", "title")) { Text = translation.GetTranslatedName("block_ui_title"), - TextColor = Color.WHITE, + TextColor = Color.White, TextSize = 32, TextAlignment = Alignment.Center, Parent = _background, @@ -121,8 +121,8 @@ public override void Update() { base.Update(); - if (IsKeyPressed(KeyboardKey.KEY_B)) Visible = !Visible; - if (IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT) && !_background.IsUnderMouse() && + if (IsKeyPressed(KeyboardKey.B)) Visible = !Visible; + if (IsMouseButtonPressed(MouseButton.Left) && !_background.IsUnderMouse() && GuiManager.GetElementUnderMouse()?.Id != "gameHud::tileMenuButton") // 🤟😏 Visible = false; } diff --git a/Sources/UI/Interfaces/PauseUI.cs b/Sources/UI/Interfaces/PauseUI.cs index 33d1564..ac49ae7 100644 --- a/Sources/UI/Interfaces/PauseUI.cs +++ b/Sources/UI/Interfaces/PauseUI.cs @@ -26,7 +26,7 @@ public override void Initialize() _background = new Panel(new ElementId("pauseScreen", "background")) { - Brush = new GradientBrush(Color.BLANK, Color.BLACK), + Brush = new GradientBrush(Color.Blank, Color.Black), IgnorePause = true, ZIndex = 100 }; @@ -110,7 +110,7 @@ public override void Update() { base.Update(); - if (IsKeyPressed(KeyboardKey.KEY_ESCAPE)) + if (IsKeyPressed(KeyboardKey.Escape)) { Visible = !Visible; Program.Paused = !Program.Paused; diff --git a/Sources/UI/Interfaces/SettingsUI.cs b/Sources/UI/Interfaces/SettingsUI.cs index 1a767dd..037f182 100644 --- a/Sources/UI/Interfaces/SettingsUI.cs +++ b/Sources/UI/Interfaces/SettingsUI.cs @@ -35,7 +35,7 @@ public override void Initialize() _skyColorLine = new ColorLine(new ElementId("settings", "skyColorLine")) { Color = Settings.SkyColor, - DefaultColor = Color.SKYBLUE, + DefaultColor = Color.SkyBlue, Parent = _skyColorLineText, LocalPosition = new Vector2(_skyColorLineText.Size.X + 16.0f, 2.0f) }; diff --git a/Sources/UI/Interfaces/WorldMenuUI.cs b/Sources/UI/Interfaces/WorldMenuUI.cs index f47e34c..ae3fa1b 100644 --- a/Sources/UI/Interfaces/WorldMenuUI.cs +++ b/Sources/UI/Interfaces/WorldMenuUI.cs @@ -32,7 +32,7 @@ public override void Initialize() ItemTextSize = 20.0f, GlobalPosition = new Vector2(0.0f, 0.0f), BackgroundBrush = null, - ItemColor = Color.WHITE, + ItemColor = Color.White, Items = WorldManager.Worlds.Select(w => $"{w.Info.Name} ['{Path.GetFileName(w.Path)}']").ToList() }; _worldList.OnItemSelect += (item) => diff --git a/Sources/UI/Screens/GameScreen.cs b/Sources/UI/Screens/GameScreen.cs index 1e46ab4..7d9a5e0 100644 --- a/Sources/UI/Screens/GameScreen.cs +++ b/Sources/UI/Screens/GameScreen.cs @@ -39,7 +39,7 @@ public override void Update() { base.Update(); - if (IsKeyPressed(KeyboardKey.KEY_R)) + if (IsKeyPressed(KeyboardKey.R)) Tiles.Tiles.Reload(); if (!Program.Paused) From 61b0d1ec60772bc6d34f2e79ca3ae3b6ebc14420 Mon Sep 17 00:00:00 2001 From: danil Date: Thu, 15 Feb 2024 14:36:35 +0200 Subject: [PATCH 094/107] update hashcode method --- Sources/Tiles/Tile.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Tiles/Tile.cs b/Sources/Tiles/Tile.cs index 59997b8..77d5acd 100644 --- a/Sources/Tiles/Tile.cs +++ b/Sources/Tiles/Tile.cs @@ -83,6 +83,6 @@ public override bool Equals(object? obj) public override int GetHashCode() { - return TexCoord.GetHashCode() ^ Size.GetHashCode(); + return HashCode.Combine(TexCoord, Size, TranslationKey); } } \ No newline at end of file From 3f24847f7e9d9f222fc22d08cf4f9f4136ac4a7f Mon Sep 17 00:00:00 2001 From: danil Date: Fri, 16 Feb 2024 19:19:54 +0200 Subject: [PATCH 095/107] update tile events --- Sources/Tiles/Chunk.cs | 45 +++++++++++++++++++++++++++++++- Sources/Tiles/Tile.cs | 21 ++++++++++++++- Sources/Tiles/Tiles.cs | 8 ------ Sources/UI/Screens/GameScreen.cs | 2 -- 4 files changed, 64 insertions(+), 12 deletions(-) diff --git a/Sources/Tiles/Chunk.cs b/Sources/Tiles/Chunk.cs index 089fa3e..2c96de3 100644 --- a/Sources/Tiles/Chunk.cs +++ b/Sources/Tiles/Chunk.cs @@ -41,9 +41,21 @@ public void Update() if (info == 0) continue; if (!Tiles.TryGetTile(info, out var tile)) continue; - tile.Update(World, info, X * Size + x, Y * Size + y); + tile.OnUpdate(World, info, X * Size + x, Y * Size + y); } } + + for (var i = 0; i < Size * Size; i++) + { + var x = Random.Shared.Next(0, Size); + var y = Random.Shared.Next(0, Size); + + TileInfo info = _tiles[x][y]; + if (info == 0) continue; + if (!Tiles.TryGetTile(info, out var tile)) continue; + + tile.OnRandomUpdate(World, info, x, y); + } } public void Draw() @@ -67,6 +79,7 @@ public void Draw() { if (x < 0 || x >= Size || y < 0 || y >= Size) return 0; + return _tiles[x][y]; } set @@ -74,7 +87,37 @@ public void Draw() if (x < 0 || x >= Size || y < 0 || y >= Size) return; + var oldTileInfo = _tiles[x][y]; + _tiles[x][y] = value; + + if (!Tiles.TryGetTile(oldTileInfo, out var oldTile)) return; + if (!Tiles.TryGetTile(value, out var tile)) return; + + oldTile.OnInfoUpdate(World, oldTileInfo, value, x, y); + tile.OnPlace(World, value, x, y); + + NotifyTileInfoUpdate(value, oldTileInfo, x, y, x - 1, y); + NotifyTileInfoUpdate(value, oldTileInfo, x, y, x + 1, y); + NotifyTileInfoUpdate(value, oldTileInfo, x, y, x, y - 1); + NotifyTileInfoUpdate(value, oldTileInfo, x, y, x, y + 1); } } + + private void NotifyTileInfoUpdate(TileInfo newInfo, TileInfo oldInfo, int x, int y, int nx, int ny) + { + var tileInfo = World[Size * X + nx, Size * Y + ny]; + + if (!Tiles.TryGetTile(tileInfo, out var tile)) return; + + tile.OnNeighbourInfoUpdate( + World, + oldInfo, + newInfo, + Size * X + nx, + Size * Y + ny, + Size * X + x, + Size * Y + y + ); + } } \ No newline at end of file diff --git a/Sources/Tiles/Tile.cs b/Sources/Tiles/Tile.cs index 77d5acd..cd7774d 100644 --- a/Sources/Tiles/Tile.cs +++ b/Sources/Tiles/Tile.cs @@ -5,6 +5,7 @@ namespace BuildingGame.Tiles; public class Tile { + public const int TickCount = 20; public const int TileSize = 16; public const float TileUpscale = 3; public const float RealTileSize = TileSize * TileUpscale; @@ -43,14 +44,32 @@ public Tile(float tx, float ty) } public virtual void Update(World world, TileInfo info, int x, int y) + public virtual void OnPlace(World world, TileInfo info, int x, int y) { } - public virtual void StaticUpdate() + public virtual void OnUpdate(World world, TileInfo info, int x, int y) { } + public virtual void OnRandomUpdate(World world, TileInfo info, int x, int y) + { + } + + protected virtual void OnTick(World world, TileInfo info, int x, int y) + { + } + + public virtual void OnNeighbourInfoUpdate(World world, TileInfo oldInfo, TileInfo newInfo, int x, int y, + int neighbourX, int neighbourY) + { + } + + public virtual void OnInfoUpdate(World world, TileInfo oldInfo, TileInfo newInfo, int x, int y) + { + } + public virtual void Draw(World world, TileInfo info, float x, float y, Color tint) { DrawTexturePro(Resources.GetTexture("Atlas.png"), diff --git a/Sources/Tiles/Tiles.cs b/Sources/Tiles/Tiles.cs index 80d7cdf..da8cee4 100644 --- a/Sources/Tiles/Tiles.cs +++ b/Sources/Tiles/Tiles.cs @@ -48,14 +48,6 @@ public static Tile[] GetTiles() return _Tiles.Values.ToArray(); } - public static void Update() - { - foreach (var kv in _Tiles) - { - kv.Value.StaticUpdate(); - } - } - public static void RegisterCustomTile(string name, T tile) where T : Tile { var key = _Tiles.Keys.First(k => string.Equals(k.Name, name, StringComparison.CurrentCultureIgnoreCase)); diff --git a/Sources/UI/Screens/GameScreen.cs b/Sources/UI/Screens/GameScreen.cs index 7d9a5e0..f6fb9ca 100644 --- a/Sources/UI/Screens/GameScreen.cs +++ b/Sources/UI/Screens/GameScreen.cs @@ -46,8 +46,6 @@ public override void Update() { _playTime += TimeSpan.FromSeconds(GetFrameTime()); - Tiles.Tiles.Update(); - _player.Update(); _world.Update(); } From 1ff401ea536295b3f655399f7822f846bfc2fd60 Mon Sep 17 00:00:00 2001 From: danil Date: Fri, 16 Feb 2024 22:16:20 +0200 Subject: [PATCH 096/107] add util method to world --- Sources/Tiles/World.Utils.cs | 12 ++++++++++++ Sources/Tiles/World.cs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Sources/Tiles/World.Utils.cs diff --git a/Sources/Tiles/World.Utils.cs b/Sources/Tiles/World.Utils.cs new file mode 100644 index 0000000..257d48e --- /dev/null +++ b/Sources/Tiles/World.Utils.cs @@ -0,0 +1,12 @@ +namespace BuildingGame.Tiles; + +public partial class World +{ + public bool IsTileNear(int x, int y, byte nearTileId) + { + return this[x - 1, y] == nearTileId || + this[x + 1, y] == nearTileId || + this[x, y - 1] == nearTileId || + this[x, y + 1] == nearTileId; + } +} \ No newline at end of file diff --git a/Sources/Tiles/World.cs b/Sources/Tiles/World.cs index b720c49..4de0569 100644 --- a/Sources/Tiles/World.cs +++ b/Sources/Tiles/World.cs @@ -4,7 +4,7 @@ namespace BuildingGame.Tiles; -public class World +public partial class World { public const int DefaultSize = 256; From 7dfed81a28ca5286207534b0bd9b2f2088eb0d34 Mon Sep 17 00:00:00 2001 From: danil Date: Fri, 16 Feb 2024 22:18:07 +0200 Subject: [PATCH 097/107] make tiles tickable --- Sources/Tiles/Data/TileData.cs | 9 +++++++++ Sources/Tiles/Data/TileInfo.cs | 1 + Sources/Tiles/Tile.cs | 10 ++++++++-- 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 Sources/Tiles/Data/TileData.cs diff --git a/Sources/Tiles/Data/TileData.cs b/Sources/Tiles/Data/TileData.cs new file mode 100644 index 0000000..c7204cd --- /dev/null +++ b/Sources/Tiles/Data/TileData.cs @@ -0,0 +1,9 @@ +using BuildingGame.Tiles.Dynamic; + +namespace BuildingGame.Tiles.Data; + +public class TileData +{ + public int CurrentTick = 0; + public float TickTimer = 1.0f / Tile.TickCount; +} \ No newline at end of file diff --git a/Sources/Tiles/Data/TileInfo.cs b/Sources/Tiles/Data/TileInfo.cs index dc85118..02bc373 100644 --- a/Sources/Tiles/Data/TileInfo.cs +++ b/Sources/Tiles/Data/TileInfo.cs @@ -4,6 +4,7 @@ public struct TileInfo { public byte Id; public TileFlags Flags; + public TileData Data = new TileData(); public TileInfo(byte id, TileFlags flags) { diff --git a/Sources/Tiles/Tile.cs b/Sources/Tiles/Tile.cs index cd7774d..03cd3ec 100644 --- a/Sources/Tiles/Tile.cs +++ b/Sources/Tiles/Tile.cs @@ -43,14 +43,20 @@ public Tile(float tx, float ty) TexCoord = new Vector2(tx, ty); } - public virtual void Update(World world, TileInfo info, int x, int y) public virtual void OnPlace(World world, TileInfo info, int x, int y) { } public virtual void OnUpdate(World world, TileInfo info, int x, int y) { - + info.Data.TickTimer -= GetFrameTime(); + + if (info.Data.TickTimer > 0.0f) return; + + info.Data.TickTimer = 1.0f / TickCount; + info.Data.CurrentTick--; + if (info.Data.CurrentTick < 0) info.Data.CurrentTick = TickCount; + OnTick(world, info, x, y); } public virtual void OnRandomUpdate(World world, TileInfo info, int x, int y) From 05bc2057590674e775bd63f41d339cf0ad69fa54 Mon Sep 17 00:00:00 2001 From: danil Date: Fri, 16 Feb 2024 22:37:01 +0200 Subject: [PATCH 098/107] add GetId overload with tile name --- Sources/Tiles/Tiles.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sources/Tiles/Tiles.cs b/Sources/Tiles/Tiles.cs index da8cee4..7068e2d 100644 --- a/Sources/Tiles/Tiles.cs +++ b/Sources/Tiles/Tiles.cs @@ -43,6 +43,11 @@ public static byte GetId(Tile tile) return key.Id; } + public static byte GetId(string name) + { + return !TryGetTile(name, out var tile) ? (byte)0 : GetId(tile); + } + public static Tile[] GetTiles() { return _Tiles.Values.ToArray(); From d96b9f8cb30953c9d0fcb9ef229f10c335906d7b Mon Sep 17 00:00:00 2001 From: danil Date: Fri, 16 Feb 2024 23:11:14 +0200 Subject: [PATCH 099/107] add clone method to tileinfo --- Sources/Tiles/Data/TileInfo.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sources/Tiles/Data/TileInfo.cs b/Sources/Tiles/Data/TileInfo.cs index 02bc373..cb1b514 100644 --- a/Sources/Tiles/Data/TileInfo.cs +++ b/Sources/Tiles/Data/TileInfo.cs @@ -11,6 +11,11 @@ public TileInfo(byte id, TileFlags flags) Id = id; Flags = flags; } + + public TileInfo Clone() + { + return new TileInfo(Id, Flags); + } public static implicit operator TileInfo(byte id) => new TileInfo(id, TileFlags.Default); public static implicit operator byte(TileInfo info) => info.Id; From 1002e4ce6d4d38482190119e711c5c9614211e78 Mon Sep 17 00:00:00 2001 From: danil Date: Fri, 16 Feb 2024 23:34:06 +0200 Subject: [PATCH 100/107] add OnCheck event to check box --- Sources/UI/Elements/CheckBox.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Sources/UI/Elements/CheckBox.cs b/Sources/UI/Elements/CheckBox.cs index 3d964ef..4fe2824 100644 --- a/Sources/UI/Elements/CheckBox.cs +++ b/Sources/UI/Elements/CheckBox.cs @@ -13,7 +13,7 @@ public class CheckBox : Element public string Text = string.Empty; public float TextSize = 12; public Color TextColor = Color.White; - + public event Action? OnCheck; public CheckBox(ElementId id) : base(id) { @@ -21,7 +21,11 @@ public CheckBox(ElementId id) : base(id) public override void Update() { - if (IsClicked()) Checked = !Checked; + if (IsClicked()) + { + Checked = !Checked; + OnCheck?.Invoke(Checked); + } } protected override void Render() From b919af6ae8f4ae2514c1058c69800b655224a3c5 Mon Sep 17 00:00:00 2001 From: danil Date: Fri, 16 Feb 2024 23:37:33 +0200 Subject: [PATCH 101/107] add (buggy) dynamic tiles --- Sources/Assets/Translation.yaml | 1 + Sources/Program.cs | 5 ++++ Sources/Settings.cs | 5 ++-- Sources/Tiles/Dynamic/LavaTile.cs | 9 ++++++++ Sources/Tiles/Dynamic/LiquidTile.cs | 36 +++++++++++++++++++++++++++++ Sources/Tiles/Dynamic/SandTile.cs | 36 +++++++++++++++++++++++++++++ Sources/Tiles/Dynamic/WaterTile.cs | 30 ++++++++++++++++++++++++ Sources/UI/Interfaces/SettingsUI.cs | 18 ++++++++++++++- 8 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 Sources/Tiles/Dynamic/LavaTile.cs create mode 100644 Sources/Tiles/Dynamic/LiquidTile.cs create mode 100644 Sources/Tiles/Dynamic/SandTile.cs create mode 100644 Sources/Tiles/Dynamic/WaterTile.cs diff --git a/Sources/Assets/Translation.yaml b/Sources/Assets/Translation.yaml index 61db633..8b7e9df 100644 --- a/Sources/Assets/Translation.yaml +++ b/Sources/Assets/Translation.yaml @@ -59,6 +59,7 @@ packs_button: "packs" exit_button: "exit" sky_color_line: "sky color (RGB): " +enable_dynamic_tiles: "enable dynamic tiles" resume_button: "resume" menu_button: "menu" diff --git a/Sources/Program.cs b/Sources/Program.cs index 2f1cbad..bd13d20 100644 --- a/Sources/Program.cs +++ b/Sources/Program.cs @@ -5,6 +5,7 @@ using System.Runtime.CompilerServices; using BuildingGame; using BuildingGame.Tiles; +using BuildingGame.Tiles.Dynamic; using BuildingGame.Tiles.IO; using BuildingGame.UI; using BuildingGame.UI.Brushes; @@ -54,6 +55,10 @@ private static void Initialize() WorldIO.AddDeserializerAsBackupable(new BGWorld2Format.Deserializer()); WorldIO.AddDeserializerAsBackupable(new LvlFormat.Deserializer()); + + Tiles.RegisterCustomTile("sand", new SandTile()); + Tiles.RegisterCustomTile("water", new WaterTile()); + Tiles.RegisterCustomTile("lava", new LavaTile()); ScreenManager.CurrentScreen = new MenuScreen(); diff --git a/Sources/Settings.cs b/Sources/Settings.cs index 98ae3b8..5df2186 100644 --- a/Sources/Settings.cs +++ b/Sources/Settings.cs @@ -5,7 +5,7 @@ namespace BuildingGame; public static class Settings { - public record struct Record(Color SkyColor); + public record struct Record(Color SkyColor, bool EnableDynamicTiles); public const string SettingsFile = "Settings.yaml"; @@ -18,6 +18,7 @@ public record struct Record(Color SkyColor); .Build(); public static Color SkyColor = Color.SkyBlue; + public static bool EnableDynamicTiles = true; public static void Load() { @@ -42,7 +43,7 @@ public static void Save() { try { - var record = new Record(SkyColor); + var record = new Record(SkyColor, EnableDynamicTiles); var content = _serializer.Serialize(record); File.WriteAllText(SettingsFile, content); diff --git a/Sources/Tiles/Dynamic/LavaTile.cs b/Sources/Tiles/Dynamic/LavaTile.cs new file mode 100644 index 0000000..7442194 --- /dev/null +++ b/Sources/Tiles/Dynamic/LavaTile.cs @@ -0,0 +1,9 @@ +namespace BuildingGame.Tiles.Dynamic; + +public class LavaTile : LiquidTile +{ + public LavaTile() + { + SpreadSpeed = 3; + } +} \ No newline at end of file diff --git a/Sources/Tiles/Dynamic/LiquidTile.cs b/Sources/Tiles/Dynamic/LiquidTile.cs new file mode 100644 index 0000000..2ca32b1 --- /dev/null +++ b/Sources/Tiles/Dynamic/LiquidTile.cs @@ -0,0 +1,36 @@ +using BuildingGame.Tiles.Data; + +namespace BuildingGame.Tiles.Dynamic; + +public class LiquidTile : Tile +{ + public int SpreadSpeed = 1; + + protected override void OnTick(World world, TileInfo info, int x, int y) + { + if (!Settings.EnableDynamicTiles) return; + + if (info.Data.CurrentTick % (TickCount - SpreadSpeed) != 0) return; + if (world[x, y + 1] == info.Id) return; + + if (CanExtendTo(world, info, x, y + 1)) + { + world[x, y + 1] = info.Clone(); + } + else if (CanExtendTo(world, info, x + 1, y)) + { + world[x + 1, y] = info.Clone(); + } + else if (CanExtendTo(world, info, x - 1, y)) + { + world[x - 1, y] = info.Clone(); + } + } + + private static bool CanExtendTo(World world, TileInfo info, int toX, int toY) + { + var toInfo = world[toX, toY]; + + return toInfo.Id == 0; + } +} \ No newline at end of file diff --git a/Sources/Tiles/Dynamic/SandTile.cs b/Sources/Tiles/Dynamic/SandTile.cs new file mode 100644 index 0000000..d8fb509 --- /dev/null +++ b/Sources/Tiles/Dynamic/SandTile.cs @@ -0,0 +1,36 @@ +using BuildingGame.Tiles.Data; + +namespace BuildingGame.Tiles.Dynamic; + +public class SandTile : Tile +{ + private static readonly byte WaterId; + private static readonly byte LavaId; + private static readonly byte GlassId; + + static SandTile() + { + WaterId = Tiles.GetId("water"); + LavaId = Tiles.GetId("lava"); + GlassId = Tiles.GetId("glass"); + } + + protected override void OnTick(World world, TileInfo info, int x, int y) + { + if (!Settings.EnableDynamicTiles) return; + + if (world.IsTileNear(x, y, LavaId)) + { + world[x, y] = GlassId; + return; + } + + var tileBelow = world[x, y + 1]; + + if (y >= world.Height - 1) return; + if (tileBelow == info.Id || (tileBelow != 0 && tileBelow != WaterId)) return; + + world[x, y] = 0; + world[x, y + 1] = info.Clone(); + } +} \ No newline at end of file diff --git a/Sources/Tiles/Dynamic/WaterTile.cs b/Sources/Tiles/Dynamic/WaterTile.cs new file mode 100644 index 0000000..98feef9 --- /dev/null +++ b/Sources/Tiles/Dynamic/WaterTile.cs @@ -0,0 +1,30 @@ +using BuildingGame.Tiles.Data; + +namespace BuildingGame.Tiles.Dynamic; + +public class WaterTile : LiquidTile +{ + private static readonly byte LavaId; + private static readonly byte ObsidianId; + + static WaterTile() + { + LavaId = Tiles.GetId("lava"); + ObsidianId = Tiles.GetId("obsidian"); + } + + public WaterTile() + { + SpreadSpeed = 10; + } + + protected override void OnTick(World world, TileInfo info, int x, int y) + { + base.OnTick(world, info, x, y); + + if (world.IsTileNear(x, y, LavaId)) + { + world[x, y] = ObsidianId; + } + } +} \ No newline at end of file diff --git a/Sources/UI/Interfaces/SettingsUI.cs b/Sources/UI/Interfaces/SettingsUI.cs index 037f182..772e928 100644 --- a/Sources/UI/Interfaces/SettingsUI.cs +++ b/Sources/UI/Interfaces/SettingsUI.cs @@ -10,6 +10,7 @@ public class SettingsUI : UIInterface private Panel _background; private TextElement _skyColorLineText; private ColorLine _skyColorLine; + private CheckBox _enableDynamicTilesBox; public override void Initialize() { @@ -44,6 +45,20 @@ public override void Initialize() Settings.SkyColor = color; }; Elements.Add(_skyColorLine); + + _enableDynamicTilesBox = new CheckBox(new ElementId("settings", "enableDynamicTilesBox")) + { + Text = translation.GetTranslatedName("enable_dynamic_tiles"), + Size = new Vector2(512.0f, 20.0f), + TextSize = 16.0f, + ZIndex = 1, + Parent = _background + }; + _enableDynamicTilesBox.OnCheck += @checked => + { + Settings.EnableDynamicTiles = @checked; + }; + Elements.Add(_enableDynamicTilesBox); Configure(); Visible = false; @@ -57,6 +72,7 @@ public override void Resized() public override void Configure() { _background.Area = new Rectangle(50.0f, 50.0f, GetScreenWidth() - 100.0f, GetScreenHeight() - 100.0f); - _skyColorLineText.GlobalPosition = _background.GlobalPosition + new Vector2(8.0f, 16.0f); + _skyColorLineText.GlobalPosition = _background.GlobalPosition + new Vector2(8.0f, 16.0f); + _enableDynamicTilesBox.GlobalPosition = _skyColorLineText.GlobalPosition + new Vector2(0.0f, _skyColorLineText.Size.Y + 8.0f); } } \ No newline at end of file From bc8f9bfb4d6b1ce1d5ddb771271123cf99b98312 Mon Sep 17 00:00:00 2001 From: danil Date: Sat, 17 Feb 2024 10:39:50 +0200 Subject: [PATCH 102/107] add infection tile --- Sources/Assets/Translation.yaml | 1 + Sources/Program.cs | 1 + Sources/Settings.cs | 5 +++-- Sources/Tiles/Dynamic/InfectionTile.cs | 18 ++++++++++++++++++ Sources/UI/Interfaces/SettingsUI.cs | 19 +++++++++++++++++++ 5 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 Sources/Tiles/Dynamic/InfectionTile.cs diff --git a/Sources/Assets/Translation.yaml b/Sources/Assets/Translation.yaml index 8b7e9df..fb2827d 100644 --- a/Sources/Assets/Translation.yaml +++ b/Sources/Assets/Translation.yaml @@ -60,6 +60,7 @@ exit_button: "exit" sky_color_line: "sky color (RGB): " enable_dynamic_tiles: "enable dynamic tiles" +enable_infection_tile: "enable infection tile" resume_button: "resume" menu_button: "menu" diff --git a/Sources/Program.cs b/Sources/Program.cs index bd13d20..05a6cf1 100644 --- a/Sources/Program.cs +++ b/Sources/Program.cs @@ -59,6 +59,7 @@ private static void Initialize() Tiles.RegisterCustomTile("sand", new SandTile()); Tiles.RegisterCustomTile("water", new WaterTile()); Tiles.RegisterCustomTile("lava", new LavaTile()); + Tiles.RegisterCustomTile("infection_block", new InfectionTile()); ScreenManager.CurrentScreen = new MenuScreen(); diff --git a/Sources/Settings.cs b/Sources/Settings.cs index 5df2186..71e8a7d 100644 --- a/Sources/Settings.cs +++ b/Sources/Settings.cs @@ -5,7 +5,7 @@ namespace BuildingGame; public static class Settings { - public record struct Record(Color SkyColor, bool EnableDynamicTiles); + public record struct Record(Color SkyColor, bool EnableDynamicTiles, bool EnableInfectionTile); public const string SettingsFile = "Settings.yaml"; @@ -19,6 +19,7 @@ public record struct Record(Color SkyColor, bool EnableDynamicTiles); public static Color SkyColor = Color.SkyBlue; public static bool EnableDynamicTiles = true; + public static bool EnableInfectionTile = true; public static void Load() { @@ -43,7 +44,7 @@ public static void Save() { try { - var record = new Record(SkyColor, EnableDynamicTiles); + var record = new Record(SkyColor, EnableDynamicTiles, EnableInfectionTile); var content = _serializer.Serialize(record); File.WriteAllText(SettingsFile, content); diff --git a/Sources/Tiles/Dynamic/InfectionTile.cs b/Sources/Tiles/Dynamic/InfectionTile.cs new file mode 100644 index 0000000..7ea9404 --- /dev/null +++ b/Sources/Tiles/Dynamic/InfectionTile.cs @@ -0,0 +1,18 @@ +using BuildingGame.Tiles.Data; + +namespace BuildingGame.Tiles.Dynamic; + +public class InfectionTile : Tile +{ + protected override void OnTick(World world, TileInfo info, int x, int y) + { + if (!Settings.EnableInfectionTile) return; + + if (info.Data.CurrentTick % 3 != 0) return; + + if (world[x - 1, y] != 0) world[x - 1, y] = info.Clone(); + if (world[x + 1, y] != 0) world[x + 1, y] = info.Clone(); + if (world[x, y - 1] != 0) world[x, y - 1] = info.Clone(); + if (world[x, y + 1] != 0) world[x, y + 1] = info.Clone(); + } +} \ No newline at end of file diff --git a/Sources/UI/Interfaces/SettingsUI.cs b/Sources/UI/Interfaces/SettingsUI.cs index 772e928..0d1b27a 100644 --- a/Sources/UI/Interfaces/SettingsUI.cs +++ b/Sources/UI/Interfaces/SettingsUI.cs @@ -11,6 +11,7 @@ public class SettingsUI : UIInterface private TextElement _skyColorLineText; private ColorLine _skyColorLine; private CheckBox _enableDynamicTilesBox; + private CheckBox _enableInfectionTileBox; public override void Initialize() { @@ -52,6 +53,7 @@ public override void Initialize() Size = new Vector2(512.0f, 20.0f), TextSize = 16.0f, ZIndex = 1, + Checked = Settings.EnableDynamicTiles, Parent = _background }; _enableDynamicTilesBox.OnCheck += @checked => @@ -59,6 +61,21 @@ public override void Initialize() Settings.EnableDynamicTiles = @checked; }; Elements.Add(_enableDynamicTilesBox); + + _enableInfectionTileBox = new CheckBox(new ElementId("settings", "enableInfectionTileBox")) + { + Text = translation.GetTranslatedName("enable_infection_tile"), + Size = new Vector2(512.0f, 20.0f), + TextSize = 16.0f, + ZIndex = 1, + Checked = Settings.EnableInfectionTile, + Parent = _background + }; + _enableInfectionTileBox.OnCheck += @checked => + { + Settings.EnableInfectionTile = @checked; + }; + Elements.Add(_enableInfectionTileBox); Configure(); Visible = false; @@ -74,5 +91,7 @@ public override void Configure() _background.Area = new Rectangle(50.0f, 50.0f, GetScreenWidth() - 100.0f, GetScreenHeight() - 100.0f); _skyColorLineText.GlobalPosition = _background.GlobalPosition + new Vector2(8.0f, 16.0f); _enableDynamicTilesBox.GlobalPosition = _skyColorLineText.GlobalPosition + new Vector2(0.0f, _skyColorLineText.Size.Y + 8.0f); + _enableInfectionTileBox.GlobalPosition = _enableDynamicTilesBox.GlobalPosition + + new Vector2(0.0f, _enableInfectionTileBox.Size.Y + 8.0f); } } \ No newline at end of file From 6d3455824f693a631b0dcbcdb3f8b9aea7401aa9 Mon Sep 17 00:00:00 2001 From: danil Date: Sat, 17 Feb 2024 10:48:10 +0200 Subject: [PATCH 103/107] fix pause --- Sources/UI/Interfaces/GameUI.cs | 5 +++++ Sources/UI/Interfaces/PauseUI.cs | 21 +++++++++++++++++---- Sources/UI/Screens/GameScreen.cs | 2 +- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Sources/UI/Interfaces/GameUI.cs b/Sources/UI/Interfaces/GameUI.cs index d42da67..b34767b 100644 --- a/Sources/UI/Interfaces/GameUI.cs +++ b/Sources/UI/Interfaces/GameUI.cs @@ -52,6 +52,11 @@ public override void Update() { base.Update(); + if (!_blockUi.Visible && IsKeyPressed(KeyboardKey.Escape)) + { + _blockUi.Visible = false; + } + if (!Tiles.Tiles.TryGetTile(Player.CurrentTile, out var tile)) return; var brush = (TextureBrush)_tileMenuButton.BackgroundBrush!; diff --git a/Sources/UI/Interfaces/PauseUI.cs b/Sources/UI/Interfaces/PauseUI.cs index ac49ae7..0faf3b0 100644 --- a/Sources/UI/Interfaces/PauseUI.cs +++ b/Sources/UI/Interfaces/PauseUI.cs @@ -14,10 +14,12 @@ public class PauseUI : UIInterface private Button _settingsButton; private SettingsUI _settingsUi = new SettingsUI(); + private BlockUI _blockUi; - public PauseUI() + public PauseUI(BlockUI blockUi) { IgnorePause = true; + _blockUi = blockUi; } public override void Initialize() @@ -110,10 +112,21 @@ public override void Update() { base.Update(); - if (IsKeyPressed(KeyboardKey.Escape)) + if (!IsKeyPressed(KeyboardKey.Escape)) return; + + if (Visible && _settingsUi.Visible) { - Visible = !Visible; - Program.Paused = !Program.Paused; + _settingsUi.Visible = false; + return; } + + if (!Visible && _blockUi.Visible) + { + _blockUi.Visible = false; + return; + } + + Visible = !Visible; + Program.Paused = !Program.Paused; } } \ No newline at end of file diff --git a/Sources/UI/Screens/GameScreen.cs b/Sources/UI/Screens/GameScreen.cs index f6fb9ca..58a49cd 100644 --- a/Sources/UI/Screens/GameScreen.cs +++ b/Sources/UI/Screens/GameScreen.cs @@ -32,7 +32,7 @@ public override void Initialize() _blockUi = new BlockUI(); _ui = new GameUI(_blockUi); - _pause = new PauseUI(); + _pause = new PauseUI(_blockUi); } public override void Update() From 8d82b53fe8d70b5345694cee376cfc399c9bf678 Mon Sep 17 00:00:00 2001 From: danil Date: Sat, 17 Feb 2024 10:48:50 +0200 Subject: [PATCH 104/107] update rewriting progress --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 500a0c2..0ebac45 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ a game, where you just place tiles - [x] settings - [x] main menu - [ ] tile packs -- [ ] dynamic tiles -- [ ] infection ~~block~~ tile +- [x] dynamic tiles +- [x] infection ~~block~~ tile ### new features - bugs From dd3c2fe94c63e47262069118a42409b39873bd79 Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 19 Feb 2024 17:10:24 +0200 Subject: [PATCH 105/107] fix some of settings not saving --- Sources/Settings.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/Settings.cs b/Sources/Settings.cs index 71e8a7d..2fd0726 100644 --- a/Sources/Settings.cs +++ b/Sources/Settings.cs @@ -29,6 +29,8 @@ public static void Load() var record = _deserializer.Deserialize(content); SkyColor = record.SkyColor; + EnableDynamicTiles = record.EnableDynamicTiles; + EnableInfectionTile = record.EnableInfectionTile; } catch (FileNotFoundException) { From ecf367b554516cddcf7e770dc52a5a6d7eb01f11 Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 19 Feb 2024 17:56:26 +0200 Subject: [PATCH 106/107] add tile packs --- Sources/BuildingGame.csproj | 6 ++ Sources/Program.cs | 25 ++++-- Sources/Resources.cs | 48 +++++++++++- Sources/Settings.cs | 6 +- Sources/TilePacks/Default/Pack.yaml | 2 + Sources/Tiles/Packs/TilePack.cs | 3 + Sources/Tiles/Packs/TilePackInfo.cs | 3 + Sources/Tiles/Packs/TilePackManager.cs | 68 ++++++++++++++++ Sources/Translation/TranslationContainer.cs | 23 ++++-- Sources/Translation/TranslationLoader.cs | 6 +- Sources/UI/Interfaces/MenuUI.cs | 4 + Sources/UI/Interfaces/TilePacksMenuUI.cs | 87 +++++++++++++++++++++ Sources/UI/Screens/TilePacksScreen.cs | 24 ++++++ 13 files changed, 287 insertions(+), 18 deletions(-) create mode 100644 Sources/TilePacks/Default/Pack.yaml create mode 100644 Sources/Tiles/Packs/TilePack.cs create mode 100644 Sources/Tiles/Packs/TilePackInfo.cs create mode 100644 Sources/Tiles/Packs/TilePackManager.cs create mode 100644 Sources/UI/Interfaces/TilePacksMenuUI.cs create mode 100644 Sources/UI/Screens/TilePacksScreen.cs diff --git a/Sources/BuildingGame.csproj b/Sources/BuildingGame.csproj index 61cbc36..63d28d2 100644 --- a/Sources/BuildingGame.csproj +++ b/Sources/BuildingGame.csproj @@ -44,4 +44,10 @@ <_DeploymentManifestIconFile Remove="assets\icon.ico" /> + + + Always + + + diff --git a/Sources/Program.cs b/Sources/Program.cs index 05a6cf1..2eafc1b 100644 --- a/Sources/Program.cs +++ b/Sources/Program.cs @@ -7,6 +7,7 @@ using BuildingGame.Tiles; using BuildingGame.Tiles.Dynamic; using BuildingGame.Tiles.IO; +using BuildingGame.Tiles.Packs; using BuildingGame.UI; using BuildingGame.UI.Brushes; using BuildingGame.UI.Elements; @@ -27,14 +28,10 @@ public static void Main(string[] args) SetConfigFlags(ConfigFlags.ResizableWindow); InitWindow(1024, 768, "building game"); SetExitKey(KeyboardKey.Null); - - // set window icon - Image icon = LoadImage("Assets/Icon.png"); - SetWindowIcon(icon); - UnloadImage(icon); - + Initialize(); + while (Running && !WindowShouldClose()) { Update(); @@ -45,10 +42,26 @@ public static void Main(string[] args) CloseWindow(); } + public static void LoadWindowIcon() + { + var icon = Resources.GetImage("Icon.png"); + SetWindowIcon(icon); + } + private static void Initialize() { Settings.Load(); + TilePackManager.Load(); + + var pack = TilePackManager.Find(Settings.CurrentTilePack); + if (string.IsNullOrWhiteSpace(pack.Path)) + { + pack = TilePackManager.Find("Default"); + } + + TilePackManager.Apply(pack); + BGWorld21Format.Register(); BGWorld2Format.Register(); LvlFormat.Register(); diff --git a/Sources/Resources.cs b/Sources/Resources.cs index 34db0c6..52db6e4 100644 --- a/Sources/Resources.cs +++ b/Sources/Resources.cs @@ -2,18 +2,58 @@ namespace BuildingGame; public static class Resources { + public static string ResourcesPath = FallbackResourcesPath; + public const string FallbackResourcesPath = "Assets/"; + private static Dictionary _textures = new Dictionary(); + private static Dictionary _images = new Dictionary(); public static Texture2D GetTexture(string key) { key = key.ToLower(); if (_textures.TryGetValue(key, out var texture)) return texture; - texture = LoadTexture("Assets/" + key); + texture = LoadTexture(GetPath(key)); _textures[key] = texture; return texture; } + public static Image GetImage(string key) + { + key = key.ToLower(); + if (_images.TryGetValue(key, out var image)) return image; + + image = LoadImage(GetPath(key)); + _images[key] = image; + return image; + } + + public static string GetText(string key) + { + return File.ReadAllText(GetPath(key)); + } + + public static string GetPath(string key) + { + var root = !File.Exists(Path.Join(ResourcesPath, key)) ? FallbackResourcesPath : ResourcesPath; + return Path.Join(root, key); + } + + public static void Reload(string newResourcesPath) + { + ResourcesPath = newResourcesPath; + + foreach (var texture in _textures) + { + _textures[texture.Key] = LoadTexture(GetPath(texture.Key)); + } + + foreach (var image in _images) + { + _images[image.Key] = LoadImage(GetPath(image.Key)); + } + } + public static void Free() { foreach (var texture in _textures) @@ -21,5 +61,11 @@ public static void Free() UnloadTexture(texture.Value); } _textures.Clear(); + + foreach (var image in _images) + { + UnloadImage(image.Value); + } + _images.Clear(); } } \ No newline at end of file diff --git a/Sources/Settings.cs b/Sources/Settings.cs index 2fd0726..b45e350 100644 --- a/Sources/Settings.cs +++ b/Sources/Settings.cs @@ -5,7 +5,7 @@ namespace BuildingGame; public static class Settings { - public record struct Record(Color SkyColor, bool EnableDynamicTiles, bool EnableInfectionTile); + public record struct Record(Color SkyColor, bool EnableDynamicTiles, bool EnableInfectionTile, string CurrentTilePack); public const string SettingsFile = "Settings.yaml"; @@ -20,6 +20,7 @@ public record struct Record(Color SkyColor, bool EnableDynamicTiles, bool Enable public static Color SkyColor = Color.SkyBlue; public static bool EnableDynamicTiles = true; public static bool EnableInfectionTile = true; + public static string CurrentTilePack = "Default"; public static void Load() { @@ -31,6 +32,7 @@ public static void Load() SkyColor = record.SkyColor; EnableDynamicTiles = record.EnableDynamicTiles; EnableInfectionTile = record.EnableInfectionTile; + CurrentTilePack = record.CurrentTilePack; } catch (FileNotFoundException) { @@ -46,7 +48,7 @@ public static void Save() { try { - var record = new Record(SkyColor, EnableDynamicTiles, EnableInfectionTile); + var record = new Record(SkyColor, EnableDynamicTiles, EnableInfectionTile, CurrentTilePack); var content = _serializer.Serialize(record); File.WriteAllText(SettingsFile, content); diff --git a/Sources/TilePacks/Default/Pack.yaml b/Sources/TilePacks/Default/Pack.yaml new file mode 100644 index 0000000..5b8f4bf --- /dev/null +++ b/Sources/TilePacks/Default/Pack.yaml @@ -0,0 +1,2 @@ +name: "Default" +assets_path: "../../Assets" \ No newline at end of file diff --git a/Sources/Tiles/Packs/TilePack.cs b/Sources/Tiles/Packs/TilePack.cs new file mode 100644 index 0000000..9db049d --- /dev/null +++ b/Sources/Tiles/Packs/TilePack.cs @@ -0,0 +1,3 @@ +namespace BuildingGame.Tiles.Packs; + +public record struct TilePack(string Path, TilePackInfo Info); \ No newline at end of file diff --git a/Sources/Tiles/Packs/TilePackInfo.cs b/Sources/Tiles/Packs/TilePackInfo.cs new file mode 100644 index 0000000..af64751 --- /dev/null +++ b/Sources/Tiles/Packs/TilePackInfo.cs @@ -0,0 +1,3 @@ +namespace BuildingGame.Tiles.Packs; + +public record struct TilePackInfo(string Name, string AssetsPath); \ No newline at end of file diff --git a/Sources/Tiles/Packs/TilePackManager.cs b/Sources/Tiles/Packs/TilePackManager.cs new file mode 100644 index 0000000..d051c56 --- /dev/null +++ b/Sources/Tiles/Packs/TilePackManager.cs @@ -0,0 +1,68 @@ +using BuildingGame.Translation; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; + +namespace BuildingGame.Tiles.Packs; + +public static class TilePackManager +{ + private const string TilePacksPath = "TilePacks"; + private const string PackFileName = "pack"; + + public static List TilePacks = new(); + + private static readonly IDeserializer _yaml = new DeserializerBuilder() + .WithNamingConvention(UnderscoredNamingConvention.Instance) + .IgnoreUnmatchedProperties() + .Build(); + + public static void Load() + { + TilePacks.Clear(); + + if (!Directory.Exists(TilePacksPath)) + { + Directory.CreateDirectory(TilePacksPath); + return; + } + + foreach (var dir in Directory.EnumerateDirectories(TilePacksPath)) + foreach (var file in Directory.EnumerateFiles(dir)) + { + if (Path.GetExtension(file) is not (".yaml" or ".yml") || + Path.GetFileNameWithoutExtension(file).ToLower() != PackFileName) continue; + + try + { + var tilePack = _yaml.Deserialize(File.ReadAllText(file)); + TilePacks.Add(new TilePack(dir, tilePack)); + break; + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + } + + public static void Apply(TilePack pack) + { + Resources.Reload(Path.Join(pack.Path, pack.Info.AssetsPath)); + TranslationContainer.Default.Reload(TranslationLoader.TranslationPath); + + Settings.CurrentTilePack = pack.Path.Split('/', '\\').Last(); + + Program.LoadWindowIcon(); + } + + public static TilePack Find(string path) + { + return TilePacks.FirstOrDefault(i => + { + var packDirectoryName = i.Path.Split('/', '\\').Last(); + var pathDirectoryName = path.Split('/', '\\').Last(); + + return string.Equals(packDirectoryName, pathDirectoryName, StringComparison.CurrentCultureIgnoreCase); + }); + } +} \ No newline at end of file diff --git a/Sources/Translation/TranslationContainer.cs b/Sources/Translation/TranslationContainer.cs index c4833a0..68897ab 100644 --- a/Sources/Translation/TranslationContainer.cs +++ b/Sources/Translation/TranslationContainer.cs @@ -1,8 +1,8 @@ namespace BuildingGame.Translation; -public readonly struct TranslationContainer +public class TranslationContainer { - private static TranslationContainer _default; + private static TranslationContainer _default = new(); public static TranslationContainer Default { @@ -10,12 +10,17 @@ public static TranslationContainer Default { if (!_default.IsEmpty()) return _default; - TranslationLoader.TryLoadTranslation(TranslationLoader.DefaultTranslationPath, out _default); + TranslationLoader.TryLoadTranslation(TranslationLoader.TranslationPath, out _default); return _default; } } - private readonly Dictionary _translations = new Dictionary(); + private Dictionary _translations; + public TranslationContainer() + { + _translations = new Dictionary(); + } + public TranslationContainer(Dictionary translations) { _translations = translations; @@ -26,8 +31,14 @@ public string GetTranslatedName(string name) return _translations.GetValueOrDefault(name) ?? name; } - public bool IsEmpty() + public void Reload(string path) + { + TranslationLoader.TryLoadTranslation(path, out var translation); + _translations = translation._translations; + } + + private bool IsEmpty() { - return _translations == null || _translations.Count < 1; + return _translations is { Count: > 0 }; } } \ No newline at end of file diff --git a/Sources/Translation/TranslationLoader.cs b/Sources/Translation/TranslationLoader.cs index f61d488..edb82a7 100644 --- a/Sources/Translation/TranslationLoader.cs +++ b/Sources/Translation/TranslationLoader.cs @@ -6,7 +6,7 @@ namespace BuildingGame.Translation; public static class TranslationLoader { - public const string DefaultTranslationPath = "Assets/Translation.yaml"; + public static readonly string TranslationPath = "Translation.yaml"; private static readonly IDeserializer _yaml = new DeserializerBuilder() .WithNamingConvention(UnderscoredNamingConvention.Instance) @@ -17,9 +17,9 @@ public static bool TryLoadTranslation(string path, out TranslationContainer tran { translation = new TranslationContainer(); - if (!File.Exists(path)) return false; + if (!File.Exists(Resources.GetPath(path))) return false; - var content = File.ReadAllText(path); + var content = Resources.GetText(path); var translationMap = _yaml.Deserialize>(content); translation = new TranslationContainer(translationMap); diff --git a/Sources/UI/Interfaces/MenuUI.cs b/Sources/UI/Interfaces/MenuUI.cs index 30c3513..22f808a 100644 --- a/Sources/UI/Interfaces/MenuUI.cs +++ b/Sources/UI/Interfaces/MenuUI.cs @@ -57,6 +57,10 @@ public override void Initialize() TextSize = 24.0f, Size = new Vector2(100.0f, 28.0f) }; + _packsButton.OnClick += () => + { + ScreenManager.Switch(new TilePacksScreen()); + }; Elements.Add(_packsButton); _exitButton = new Button(new ElementId("menuUi", "exitButton")) diff --git a/Sources/UI/Interfaces/TilePacksMenuUI.cs b/Sources/UI/Interfaces/TilePacksMenuUI.cs new file mode 100644 index 0000000..b5d53a0 --- /dev/null +++ b/Sources/UI/Interfaces/TilePacksMenuUI.cs @@ -0,0 +1,87 @@ +using System.Numerics; +using BuildingGame.Tiles.Packs; +using BuildingGame.Translation; +using BuildingGame.UI.Brushes; +using BuildingGame.UI.Elements; +using BuildingGame.UI.Screens; + +namespace BuildingGame.UI.Interfaces; + +public class TilePacksMenuUI : UIInterface +{ + private ListBox _tilePacksList; + private Button _menuButton; + + private string[] _paths; + + public override void Initialize() + { + _paths = TilePackManager.TilePacks.Select(t => t.Path).ToArray(); + + var translation = TranslationContainer.Default; + + _tilePacksList = new ListBox(new ElementId("tilePacksMenu", "tilePacksList")) + { + ItemTextSize = 24.0f, + BackgroundBrush = null, + ItemColor = Color.White, + Items = TilePackManager.TilePacks.Select(t => t.Info.Name).ToList() + }; + _tilePacksList.OnItemSelect += item => + { + var index = _tilePacksList.SelectedItem; + + if (index < 0 || index >= _paths.Length) return; + + var oldTilePack = TilePackManager.Find(Settings.CurrentTilePack); + SetTilePackActive(oldTilePack, false); + + var tilePack = TilePackManager.Find(_paths[index]); + TilePackManager.Apply(tilePack); + + SetTilePackActive(tilePack, true); + }; + Elements.Add(_tilePacksList); + + _menuButton = new Button(new ElementId("tilePacksMenu", "menuButton")) + { + Text = translation.GetTranslatedName("menu_button"), + TextSize = 24.0f, + Size = new Vector2(256.0f, 32.0f), + TextAlignment = Alignment.Center + }; + _menuButton.OnClick += () => + { + ScreenManager.Switch(new MenuScreen()); + }; + Elements.Add(_menuButton); + + SetTilePackActive(TilePackManager.Find(Settings.CurrentTilePack), true); + + Configure(); + } + + private void SetTilePackActive(TilePack tilePack, bool isActive) + { + if (string.IsNullOrWhiteSpace(tilePack.Path)) return; + + var index = Array.IndexOf(_paths, tilePack.Path); + if (index < 0) return; + + _tilePacksList.Items[index] = (isActive ? "> " : string.Empty) + tilePack.Info.Name; + } + + public override void Configure() + { + _tilePacksList.Size = new Vector2(GetScreenWidth() / 3.0f, GetScreenHeight() - _menuButton.Size.Y - 8.0f); + _tilePacksList.GlobalPosition = new Vector2(GetScreenWidth() / 2.0f - _tilePacksList.Size.X / 2.0f, 0.0f); + + _menuButton.GlobalPosition = new Vector2(GetScreenWidth() / 2.0f - _menuButton.Size.X / 2.0f, + GetScreenHeight() - _menuButton.Size.Y - 8.0f); + } + + public override void Resized() + { + Configure(); + } +} \ No newline at end of file diff --git a/Sources/UI/Screens/TilePacksScreen.cs b/Sources/UI/Screens/TilePacksScreen.cs new file mode 100644 index 0000000..c7d26cc --- /dev/null +++ b/Sources/UI/Screens/TilePacksScreen.cs @@ -0,0 +1,24 @@ +using BuildingGame.Tiles.Packs; +using BuildingGame.UI.Interfaces; + +namespace BuildingGame.UI.Screens; + +public class TilePacksScreen : Screen +{ + private TilePacksMenuUI _tilePacksMenu; + + public override void Initialize() + { + base.Initialize(); + + TilePackManager.Load(); + _tilePacksMenu = new TilePacksMenuUI(); + } + + public override void Draw() + { + ClearBackground(new Color(20, 20, 20, 255)); + + base.Draw(); + } +} \ No newline at end of file From ce1bc51c7a2360cd65f3caa3702b8e09283b4895 Mon Sep 17 00:00:00 2001 From: danil Date: Mon, 19 Feb 2024 17:56:51 +0200 Subject: [PATCH 107/107] update rewriting progress --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ebac45..ac343ba 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,12 @@ a game, where you just place tiles - [x] pause - [x] settings - [x] main menu -- [ ] tile packs +- [x] tile packs - [x] dynamic tiles - [x] infection ~~block~~ tile +its finished!!!!! + ### new features - bugs - better camera