diff options
author | rexim <reximkut@gmail.com> | 2024-03-08 23:53:18 +0700 |
---|---|---|
committer | rexim <reximkut@gmail.com> | 2024-03-08 23:53:18 +0700 |
commit | 943af780e66da1a24253a34365c6d6aa96a22fec (patch) | |
tree | b1f293f7dd8c98de809ed1e805eeb3e330748b91 /game.adb |
Ready. Set. Go!
Diffstat (limited to 'game.adb')
-rw-r--r-- | game.adb | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/game.adb b/game.adb new file mode 100644 index 0000000..bfa1c68 --- /dev/null +++ b/game.adb @@ -0,0 +1,280 @@ +with Text_IO; use Text_IO; +with Interfaces.C; use Interfaces.C; +with Interfaces.C.Strings; use Interfaces.C.Strings; +with Raylib; use Raylib; +with Raymath; use Raymath; +with Ada.Strings.Unbounded; +use Ada.Strings.Unbounded; +with Ada.Containers.Vectors; +with Ada.Unchecked_Deallocation; +with Ada.Containers.Hashed_Maps; +use Ada.Containers; + +procedure Game is + COLOR_BACKGROUND : constant Color := Get_Color(16#0b1424ff#); + COLOR_FLOOR : constant Color := Get_Color(16#2f2f2fFF#); + COLOR_WALL : constant Color := Get_Color(16#000000FF#); + COLOR_PLAYER : constant Color := Get_Color(16#3e89ffff#); + COLOR_RED : constant Color := Get_Color(16#FF0000FF#); + COLOR_DOOR : constant Color := Get_Color(16#ff9700ff#); + COLOR_KEY : constant Color := Get_Color(16#ff9700ff#); + + type Cell is (None, Floor, Wall, Barricade, Door); + Width : constant Integer := 20; + Height : constant Integer := 10; + Cell_Size : constant Vector2 := (x => 50.0, y => 50.0); + Cell_Colors : constant array (Cell) of Color := ( + None => COLOR_BACKGROUND, + Floor => COLOR_FLOOR, + Wall => COLOR_WALL, + Barricade => COLOR_RED, + Door => COLOR_DOOR + ); + + type Map is array (Positive range <>, Positive range <>) of Cell; + type Map_Access is access Map; + procedure Delete_Map is new Ada.Unchecked_Deallocation(Map, Map_Access); + + type IVector2 is record + X, Y: Integer; + end record; + + function "="(A, B: IVector2) return Boolean is + begin + return A.X = B.X and then A.Y = B.Y; + end; + + function Equivalent_IVector2(Left, Right: IVector2) return Boolean is + begin + return Left.X = Right.X and then Left.Y = Right.Y; + end; + + function Hash_IVector2(V: IVector2) return Hash_Type is + M31: constant Hash_Type := 2**31-1; -- a nice Mersenne prime + begin + return Hash_Type(V.X) * M31 + Hash_Type(V.Y); + end; + + type Item_Kind is (Key, Bomb); + + package Hashed_Map_Items is new + Ada.Containers.Hashed_Maps( + Key_Type => IVector2, + Element_Type => Item_Kind, + Hash => Hash_IVector2, + Equivalent_Keys => Equivalent_IVector2); + + function To_Vector2(iv: IVector2) return Vector2 is + begin + return (X => C_float(iv.X), Y => C_float(iv.Y)); + end; + + type Player_State is record + Position: IVector2; + Keys: Integer := 0; + Bombs: Integer := 0; + end record; + + type Game_State is record + Current_World: Map_Access := Null; + Player: Player_State; + Items: Hashed_Map_Items.Map; + Camera_Position: Vector2 := (x => 0.0, y => 0.0); + Camera_Velocity: Vector2 := (x => 0.0, y => 0.0); + end record; + + procedure Load_Game_From_File(File_Name: in String; Game: in out Game_State; Update_Player: Boolean) is + package Rows is new + Ada.Containers.Vectors( + Index_Type => Natural, + Element_Type => Unbounded_String); + F: File_Type; + Map_Rows: Rows.Vector; + Width: Integer := 0; + Height: Integer := 0; + begin + Open(F, In_File, File_Name); + while not End_Of_File(F) loop + declare + Line: String := Get_Line(F); + begin + if Line'Length > Width then + Width := Line'Length; + end if; + Map_Rows.Append(To_Unbounded_String(Line)); + Height := Height + 1; + end; + end loop; + Close(F); + + if Game.Current_World /= Null then + Delete_Map(Game.Current_World); + end if; + Game.Items.Clear; + + Game.Current_World := new Map(1..Height, 1..Width); + for Row in Game.Current_World'Range(1) loop + declare + Map_Row: Unbounded_String := Map_Rows(Row - 1); + begin + Put_Line(To_String(Map_Rows(Row - 1))); + for Column in Game.Current_World'Range(2) loop + if Column in 1..Length(Map_Row) then + case Element(Map_Row, Column) is + when '.' => Game.Current_World(Row, Column) := Floor; + when '#' => Game.Current_World(Row, Column) := Wall; + when '=' => Game.Current_World(Row, Column) := Door; + when '*' => + Game.Current_World(Row, Column) := Floor; + Game.Items.Insert((Column, Row), Bomb); + when '&' => + Game.Current_World(Row, Column) := Barricade; + when '%' => + Game.Current_World(Row, Column) := Floor; + Game.Items.Insert((Column, Row), Key); + when '@' => + Game.Current_World(Row, Column) := Floor; + if Update_Player then + Game.Player.Position.X := Column; + Game.Player.Position.Y := Row; + end if; + when others => Game.Current_World(Row, Column) := None; + end case; + else + Game.Current_World(Row, Column) := None; + end if; + end loop; + end; + end loop; + end; + + procedure Draw_Game(Game: in Game_State) is + begin + for Row in Game.Current_World'Range(1) loop + for Column in Game.Current_World'Range(2) loop + declare + Position: Vector2 := To_Vector2((Column, Row))*Cell_Size; + C: Color := + (if (Column, Row) = Game.Player.Position + then COLOR_PLAYER + else Cell_Colors(Game.Current_World(Row, Column))); + begin + Draw_Rectangle_V(position, cell_size, C); + end; + end loop; + end loop; + + declare + use Hashed_Map_Items; + begin + for C in Game.Items.Iterate loop + case Element(C) is + when Key => + Draw_Circle_V(To_Vector2(Key(C))*Cell_Size + Cell_Size*0.5, Cell_Size.X*0.25, COLOR_KEY); + when Bomb => + Draw_Circle_V(To_Vector2(Key(C))*Cell_Size + Cell_Size*0.5, Cell_Size.X*0.5, COLOR_RED); + end case; + end loop; + end; + end; + + type Direction is (Left, Right, Up, Down); + + procedure Step(D: in Direction; Position: in out IVector2) is + begin + case D is + when Left => Position.X := Position.X - 1; + when Right => Position.X := Position.X + 1; + when Up => Position.Y := Position.Y - 1; + when Down => Position.Y := Position.Y + 1; + end case; + end; + + function Opposite(D: Direction) return Direction is + begin + case D is + when Left => return Right; + when Right => return Left; + when Up => return Down; + when Down => return Up; + end case; + end; + + Keys: array (Direction) of int := ( + Left => KEY_A, + Right => KEY_D, + Up => KEY_W, + Down => KEY_S + ); + + Game: Game_State; +begin + Load_Game_From_File("map.txt", Game, True); + Put_Line("Keys: " & Integer'Image(Game.Player.Keys)); + Set_Config_Flags(FLAG_WINDOW_RESIZABLE); + Init_Window(800, 600, New_String("Hello, NSA")); + while Window_Should_Close = 0 loop + Begin_Drawing; + Clear_Background(COLOR_BACKGROUND); + for Dir in Direction loop + if Is_Key_Pressed(Keys(Dir)) /= 0 then + Step(Dir, Game.Player.Position); + case Game.Current_World(Game.Player.Position.Y, Game.Player.Position.X) is + when Floor => + declare + use Hashed_Map_Items; + C: Cursor := Game.Items.Find(Game.Player.Position); + begin + if Has_Element(C) then + case Element(C) is + when Key => + Game.Player.Keys := Game.Player.Keys + 1; + when Bomb => + Game.Player.Bombs := Game.Player.Bombs + 1; + end case; + Game.Items.Delete(C); + end if; + end; + when Door => + if Game.Player.Keys > 0 then + Game.Player.Keys := Game.Player.Keys - 1; + Game.Current_World(Game.Player.Position.Y, Game.Player.Position.X) := Floor; + else + Step(Opposite(Dir), Game.Player.Position); + end if; + when others => + Step(Opposite(Dir), Game.Player.Position); + end case; + end if; + end loop; + if Is_Key_Pressed(KEY_R) /= 0 then + Load_Game_From_File("map.txt", Game, False); + end if; + Game.Camera_Position := Game.Camera_Position + Game.Camera_Velocity*Get_Frame_Time; + declare + camera : Camera2D := ( + offset => Game.Camera_Position, + target => (x => 0.0, y => 0.0), + rotation => 0.0, + zoom => 1.0 + ); + Screen_Size: Vector2 := To_Vector2((Integer(Get_Screen_Width), Integer(Get_Screen_Height))); + Camera_Target: Vector2 := + Screen_Size*0.5 - To_Vector2(Game.Player.Position)*Cell_Size - Cell_Size*0.5; + begin + Game.Camera_Velocity := (Camera_Target - Game.Camera_Position)*2.0; + Begin_Mode2D(Camera); + Draw_Game(Game); + End_Mode2D; + for Index in 1..Game.Player.Keys loop + declare + Position: Vector2 := (100.0 + C_float(Index - 1)*Cell_Size.X, 100.0); + begin + Draw_Circle_V(Position, Cell_Size.X*0.25, COLOR_KEY); + end; + end loop; + end; + End_Drawing; + end loop; + Close_Window; +end; |