Okay, this is where I’m at.
#include "raylib.h"
struct AnimData
{
Rectangle Rec;
Vector2 Pos;
int Frame;
float UpdateTime;
float RunningTime;
};
bool IsOnGround(AnimData Data, int WindowHeight)
{
return Data.Pos.y >= WindowHeight - Data.Rec.height;
}
AnimData UpdateAnimData(AnimData Data, float DeltaTime, int MaxFrame)
{
// update running time
Data.RunningTime += DeltaTime;
if (Data.RunningTime >= Data.UpdateTime)
{
Data.RunningTime = 0.0;
// update animation data
Data.Rec.x = Data.Frame * Data.Rec.width;
Data.Frame++;
if (Data.Frame > MaxFrame)
{
Data.Frame = 0;
}
}
return Data;
}
bool GameStarted = false;
int Score = 0; // Game Score
int Delay = 120; // 2 second timer
int Timer = Delay; // Working variable for timer
int main()
{
// window dimensions
const int WindowDimensions[]{512, 380};
// initialize the window
InitWindow(WindowDimensions[0], WindowDimensions[1], "Single Button Game");
// acceleration due to gravity (pixels/second)/second
const int Gravity = 1'000;
Texture2D Nebula = LoadTexture("textures/12_nebula_spritesheet.png");
const int SizeOfNebulae{6};
AnimData Nebulae[SizeOfNebulae]{};
// loop through the Nebulae array to initialize all values
for (int i = 0; i < SizeOfNebulae; i++)
{
Nebulae[i].Rec.x = 0.0;
Nebulae[i].Rec.y = 0.0;
Nebulae[i].Rec.width = Nebula.width/8;
Nebulae[i].Rec.height = Nebula.width/8;
Nebulae[i].Pos.x = WindowDimensions[0]+(i*300);
Nebulae[i].Pos.y = WindowDimensions[1] - Nebula.height/8;
Nebulae[i].Frame = 0;
Nebulae[i].RunningTime = 0.0;
Nebulae[i].UpdateTime = 0.0;
}
float FinishLine{Nebulae[SizeOfNebulae - 1].Pos.x};
// Nebula X velocity (pixels/sec)
int NebVel{-200};
//Scarfy variables
Texture2D Scarfy = LoadTexture("textures/scarfy.png");
AnimData ScarfyData;
ScarfyData.Rec.width = Scarfy.width/6;
ScarfyData.Rec.height = Scarfy.height;
ScarfyData.Rec.x = 0;
ScarfyData.Rec.y = 0;
ScarfyData.Pos.x = WindowDimensions[0]/2 - ScarfyData.Rec.width/2;
ScarfyData.Pos.y = WindowDimensions[1] - ScarfyData.Rec.height;
ScarfyData.Frame = 0;
ScarfyData.UpdateTime = 1.0/10.0;
ScarfyData.RunningTime = 0.0;
// is the rectangle in the air
bool IsInAir = false;
// jump velocity (pixels/second)
const int JumpVel = -600;
int Velocity = 0;
Texture2D Background = LoadTexture("textures/far-buildings.png");
float BgX{};
Texture2D Midground = LoadTexture("textures/back-buildings.png");
float MgX{};
Texture2D Foreground = LoadTexture("textures/foreground.png");
float FgX{};
bool Collision{}; // initialize collision as false
SetTargetFPS(60);
while (!WindowShouldClose())
{
// delta time (time since last frame)
const float dT = GetFrameTime();
//start drawing
BeginDrawing();
ClearBackground(WHITE);
if (!GameStarted) // if game has not started display title and keys and wait for input
{
// DisplayTitle(WindowWidth*.05, WindowHeight*.2, ObstacleColor, ScoreColor);
DrawText("Press Space", (WindowDimensions[0]*.4), (WindowDimensions[1]*.65), 15, BLACK);
if(IsKeyDown(KEY_SPACE))
{
GameStarted = true;
}
}
else
{
// move background
BgX -= 20 * dT;
if (BgX <= -Background.width * 2)
{
BgX = 0.0;
}
// move midground
MgX -= 40 * dT;
if (MgX <= -Background.width * 2)
{
MgX = 0.0;
}
// move foreground
FgX -= 80 * dT;
if (FgX <= -Foreground.width * 2)
{
FgX = 0.0;
}
// move finish line
FinishLine += NebVel * dT;
// draw background
Vector2 Bg1Pos{BgX, 0.0};
DrawTextureEx(Background, Bg1Pos, 0.0, 2.0, WHITE);
Vector2 Bg2Pos{BgX + Background.width*2, 0.0};
DrawTextureEx(Background, Bg2Pos, 0.0, 2.0, WHITE);
// draw midground
Vector2 Mg1Pos{MgX, 0.0};
DrawTextureEx(Midground, Mg1Pos, 0.0, 2.0, WHITE);
Vector2 Mg2Pos{MgX + Midground.width*2, 0.0};
DrawTextureEx(Midground, Mg2Pos, 0.0, 2.0, WHITE);
// draw foreground
Vector2 Fg1Pos{FgX, 0.0};
DrawTextureEx(Foreground, Fg1Pos, 0.0, 2.0, WHITE);
Vector2 Fg2Pos{FgX + Foreground.width*2, 0.0};
DrawTextureEx(Foreground, Fg2Pos, 0.0, 2.0, WHITE);
//ground check
if (IsOnGround(ScarfyData, WindowDimensions[1]))
{
// rectangle is on the ground
IsInAir = false;
Velocity = 0;
//PosY = WindowHeight-Height; // snap to floor
}
else
{
// apply gravity
Velocity += Gravity * dT;
// rectangle is in the air
IsInAir = true;
}
// check for jumping
if (IsKeyPressed(KEY_SPACE) && !IsInAir)
{
Velocity += JumpVel;
}
// Loop through nebulae to update position
for (int i=0; i < SizeOfNebulae; i++)
{
Nebulae[i].Pos.x += NebVel * dT;
}
// update Scarfy position and update animation frame
ScarfyData.Pos.y += Velocity * dT;
if (!IsInAir)
{
ScarfyData = UpdateAnimData(ScarfyData, dT, 5);
}
// Loop through nebulae to update animation
for (int i = 0; i < SizeOfNebulae; i++)
{
Nebulae[i] = UpdateAnimData(Nebulae[i], dT, 7);
}
// try to collide things
for (AnimData Nebula : Nebulae)
{
float Pad{50}; // eliminates white space around obstacle from collision
Rectangle NebRec{
Nebula.Pos.x + Pad,
Nebula.Pos.y + Pad,
Nebula.Rec.width - 2*Pad,
Nebula.Rec.height - 2*Pad
};
Rectangle ScarfyRec{
ScarfyData.Pos.x,
ScarfyData.Pos.y,
ScarfyData.Rec.width,
ScarfyData.Rec.height
};
if (CheckCollisionRecs(NebRec, ScarfyRec))
{
Collision = true;
}
}
if (Collision)
{
// lose the game
DrawText("Game Over", WindowDimensions[0]/5, 2*WindowDimensions[1]/5, 50, BLACK);
DrawText("Game Over", WindowDimensions[0]/5-4, 2*WindowDimensions[1]/5-3, 50, RED);
DrawText("Game Over", WindowDimensions[0]/5-5, 2*WindowDimensions[1]/5-4, 50, WHITE);
}
else if (FinishLine <= WindowDimensions[0]/5)
{
DrawText("You Win!", WindowDimensions[0]/5, 2*WindowDimensions[1]/5, 50, BLACK);
DrawText("You Win!", WindowDimensions[0]/5-4, 2*WindowDimensions[1]/5-3, 50, GREEN);
DrawText("You Win!", WindowDimensions[0]/5-5, 2*WindowDimensions[1]/5-4, 50, WHITE);
}
else
{
// Loop through nebulae to update animation
for (int i=0; i<SizeOfNebulae; i++)
{
DrawTextureRec(Nebula, Nebulae[i].Rec, Nebulae[i].Pos, WHITE);
}
// draw scarfy
DrawTextureRec(Scarfy, ScarfyData.Rec, ScarfyData.Pos, WHITE);
}
}
// stop drawing
EndDrawing();
}
UnloadTexture(Scarfy);
UnloadTexture(Nebula);
UnloadTexture(Background);
UnloadTexture(Midground);
UnloadTexture(Foreground);
CloseWindow();
}
It’s basically the project they have you build plus a start screen (No title yet) just so that I’m ready before I have to jump. I improved the text a little with an outline and shadow but need to consider how to really make this shine. I’ll start with observations:
- It’s kind of predictable and boring
- I’m not encouraged to play more
- I’d like to learn about 2D jumping
So what can I do?
- I definitely want to wrap this in a replay thing
- I think working in a pig mechanic could be ideal here
- The game is about jumping and sidescroll jumping has a lot to dig into
So I’m off to refactor and experiment with new features but if you have ideas, suggestions or ways I can figure this stuff out I’d love to hear them!