diff --git a/img/UFO.png b/img/UFO.png new file mode 100644 index 0000000..2b04884 Binary files /dev/null and b/img/UFO.png differ diff --git a/src/ballon_bounce.adb b/src/ballon_bounce.adb index acfca3e..3bf1717 100644 --- a/src/ballon_bounce.adb +++ b/src/ballon_bounce.adb @@ -16,15 +16,20 @@ use Sf.Window; use Sf.System; use Sf; -with Ada.Text_IO; use Ada.Text_IO; +with Ada.Text_IO; use Ada.Text_IO; +with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions; +with Ada.Numerics.Float_Random; use Ada.Numerics.Float_Random; +with Ada.Numerics.Discrete_Random; + +with Random_Functions; use Random_Functions; procedure Ballon_Bounce is -- Window structure - Width : sfUint32 := 1_000; - Height : sfUint32 := 750; - Width_Float : Float := 1_000.0; - Height_Float : Float := 750.0; + Width : constant sfUint32 := 1_000; + Height : constant sfUint32 := 750; + Width_Float : constant Float := 1_000.0; + Height_Float : constant Float := 750.0; Main_Window : sfRenderWindow_Ptr := RenderWindow.create ((Width, Height, 32), "Balloon Bouncer!"); Event_Hook : Event.sfEvent; @@ -35,42 +40,79 @@ procedure Ballon_Bounce is Background : sfSprite_Ptr := Sprite.create; -- Set platform - Platform_Texture : sfTexture_Ptr := + Platform_Texture : sfTexture_Ptr := Texture.createFromFile ("img/pipe.png"); - Platform : sfSprite_Ptr := Sprite.create; - Platform_Width : Float := 250.0; - Platform_Height : Float := 50.0; + Platform : sfSprite_Ptr := Sprite.create; + Platform_Width : constant Float := 250.0; + Platform_Height : constant Float := 50.0; -- Set Ball type Vector2 is record X : Float; Y : Float; end record; - Ball_Texture : sfTexture_Ptr := Texture.createFromFile ("img/ball.png"); - Ball : sfSprite_Ptr := Sprite.create; - Ball_Size : Float := 93.0; + Ball_Texture : sfTexture_Ptr := Texture.createFromFile ("img/ball.png"); + Ball : sfSprite_Ptr := Sprite.create; + Ball_Size : constant Float := 93.0; + + -- Set easy enemies + Enemy_1_Texture : sfTexture_Ptr := Texture.createFromFile ("img/UFO.png"); + Enemy_1 : sfSprite_Ptr := Sprite.create; + Enemy_1_Width : constant Float := 186.0; + Enemy_1_Height : constant Float := 77.0; + Enemy_1_Position : Vector2 := (-100.0, -100.0); -- Game Coordinates - -- subtype Platform_X_Position is - -- Float range 0.0 .. (Width_Float - Platform_Width); - Platform_X : Float := 0.0; + Platform_X : Float := (Width_Float / 2.0) - (Platform_Width / 2.0); Platform_Y : Float := Height_Float - Platform_Height; Platform_Speed : Float := 8.0; - Ball_X : Float := Width_Float / 2.0; - Ball_Y : Float := Height_Float / 2.0; - Ball_Direction : Vector2 := (1.0, -1.0); + Ball_X : Float := (Width_Float / 2.0) - (Ball_Size / 2.0); + Ball_Y : Float := (Height_Float / 2.0) - (Ball_Size / 2.0); + Ball_Direction : Vector2 := (0.0, 1.0); Ball_Speed : Float := 5.0; + Player_Score : Natural := 0; + + -- Random number generator + + function Rotate_Vector + (Crossing_Place : Float; Direction : Vector2) return Vector2 + is + Result : Vector2; + Angle : constant Float := Crossing_Place / 75.0; + Length : Float; + begin + + Result.X := Angle; + Result.Y := Direction.Y; + + Length := Sqrt ((Result.X * Result.X) + (Result.Y * Result.Y)); + + -- Norming the vector to prevent speed changes + while (Length > 1.2) or (Length < 0.8) loop + Result.X := Result.X / Length; + Result.Y := Result.Y / Length; + Length := Sqrt ((Result.X * Result.X) + (Result.Y * Result.Y)); + end loop; + + -- Prevent glitching down + if Result.Y >= -1.0 then + Result.Y := Result.Y - 1.0; + end if; + + return Result; + end Rotate_Vector; begin RenderWindow.setFramerateLimit (Main_Window, 30); - -- Background initialization + -- Background and position initialization Sprite.setTexture (Background, Background_Texture); Sprite.setPosition (Background, (Float (0), Float (0))); - -- Platform and Ball texture binding + -- Interactive element texture binding Sprite.setTexture (Platform, Platform_Texture); Sprite.setTexture (Ball, Ball_Texture); + Sprite.setTexture (Enemy_1, Enemy_1_Texture); while RenderWindow.isOpen (Main_Window) = sfTrue loop while RenderWindow.PollEvent (Main_Window, event => Event_Hook) = @@ -101,6 +143,7 @@ begin end loop; -- BEGIN: Computing area + -- BEGIN: Ball collision detection Ball_X := Ball_X + (Ball_Direction.X * Ball_Speed); Ball_Y := Ball_Y + (Ball_Direction.Y * Ball_Speed); @@ -114,26 +157,70 @@ begin -- Ball below platform! Possibly Lost! if ((Ball_Y + Ball_Size) >= Platform_Y) then - Put_Line ("INFO: The Ball was catched at Y = " & Ball_Y'Image); -- Check if platform was hit, or game is lost if ((Ball_X + (Ball_Size / 2.0)) >= Platform_X) and ((Ball_X + (Ball_Size / 2.0)) <= (Platform_X + Platform_Width)) then Ball_Direction.Y := Ball_Direction.Y * (-1.0); + + -- Change direction + Ball_Direction := + Rotate_Vector + ((Ball_X + (Ball_Size / 2.0)) - + (Platform_X + (Platform_Width / 2.0)), + Ball_Direction); + + -- The Ball seems to rebounce randomly, so we move it away quicker + Ball_Y := Ball_Y - (Ball_Speed * 1.5); + + -- Speed up the ball + Ball_Speed := Ball_Speed + 0.1; + + -- Check if no enemy is present, if so, maybe spawn one + if Enemy_1_Position.X = -100.0 then + if Spawn_Enemy then + Enemy_1_Position.X := + Generate_Coordinates (Width_Float - Enemy_1_Width); + Enemy_1_Position.Y := + Generate_Coordinates + ((Height_Float * 0.8) - Enemy_1_Height); + end if; + end if; else -- Game is Lost, reset for now Ball_X := Width_Float / 2.0; Ball_Y := Height_Float / 2.0; - Ball_Direction := (1.0, 1.0); + Ball_Direction := (0.0, 1.0); end if; end if; + -- END: Ball collision detection + + -- BEGIN: Enemy collision detection + + -- Check vertical collision + if ((Ball_Y + Ball_Size) >= Enemy_1_Position.Y) and + (Ball_Y <= (Enemy_1_Position.Y + Enemy_1_Height)) + then + -- Check horizontal collision + if ((Ball_X + Ball_Size) >= Enemy_1_Position.X) and + (Ball_X <= (Enemy_1_Position.X + Enemy_1_Width)) + then + -- Detected collision + Player_Score := Player_Score + 5; + Enemy_1_Position.X := -100.0; + Enemy_1_Position.Y := -100.0; + Put_Line (Player_Score'Image); + end if; + end if; + -- END: Enemy collision detection -- END: Computing area -- BEGIN: Update states Sprite.setPosition (Platform, (Platform_X, Platform_Y)); Sprite.setPosition (Ball, (Ball_X, Ball_y)); + Sprite.setPosition (Enemy_1, (Enemy_1_Position.X, Enemy_1_Position.Y)); -- END: Update states @@ -142,6 +229,9 @@ begin -- BEGIN: Draw area RenderWindow.drawSprite (Main_Window, Background); RenderWindow.drawSprite (Main_Window, Platform); + RenderWindow.drawSprite (Main_Window, Enemy_1); + + -- Always on Top RenderWindow.drawSprite (Main_Window, Ball); -- END: Draw area diff --git a/src/random_functions.adb b/src/random_functions.adb new file mode 100644 index 0000000..812a1f5 --- /dev/null +++ b/src/random_functions.adb @@ -0,0 +1,38 @@ +package body Random_Functions is + function Spawn_Enemy return Boolean is + subtype Die is Natural range 1 .. 6; + subtype Dice is Natural range 2 * Die'First .. 2 * Die'Last; + package Random_Die is new Ada.Numerics.Discrete_Random (Die); + use Random_Die; + G : Generator; + D : Dice; + Random_Number : Natural; + begin + Reset (G); + Random_Number := Random (G); + if Random_Number = 2 then + return True; + else + return False; + end if; + end Spawn_Enemy; + + function Generate_Coordinates (Limit : Float) return Float is + subtype Coordinate is Integer range 1 .. Integer (Limit); + subtype Coordinates is + Integer range 2 * Coordinate'First .. 2 * Coordinate'Last; + package Random_Coordinate is new Ada.Numerics.Discrete_Random + (Coordinate); + use Random_Coordinate; + G : Generator; + D : Coordinates; + Random_Number : Float; + begin + Reset (G); + Random_Number := Float (Random (G)); + if Random_Number < 0.0 then + Random_Number := Random_Number * (-1.0); + end if; + return Random_Number; + end Generate_Coordinates; +end Random_Functions; diff --git a/src/random_functions.ads b/src/random_functions.ads new file mode 100644 index 0000000..a315564 --- /dev/null +++ b/src/random_functions.ads @@ -0,0 +1,7 @@ +with Ada.Numerics.Discrete_Random; +with Ada.Numerics.Float_Random; + +package Random_Functions is + function Spawn_Enemy return Boolean; + function Generate_Coordinates (Limit : Float) return Float; +end Random_Functions;