game
This commit is contained in:
commit
e2e27c3677
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.vscode
|
||||||
|
build
|
BIN
assets/fonts/C64.ttf
Normal file
BIN
assets/fonts/C64.ttf
Normal file
Binary file not shown.
BIN
assets/sounds/die.wav
Normal file
BIN
assets/sounds/die.wav
Normal file
Binary file not shown.
BIN
assets/sounds/hit.wav
Normal file
BIN
assets/sounds/hit.wav
Normal file
Binary file not shown.
BIN
assets/sounds/point.wav
Normal file
BIN
assets/sounds/point.wav
Normal file
Binary file not shown.
BIN
assets/sounds/wing.wav
Normal file
BIN
assets/sounds/wing.wav
Normal file
Binary file not shown.
BIN
assets/sprites/background.bmp
Normal file
BIN
assets/sprites/background.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 576 KiB |
BIN
assets/sprites/bird.bmp
Normal file
BIN
assets/sprites/bird.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 KiB |
BIN
assets/sprites/ground.bmp
Normal file
BIN
assets/sprites/ground.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
BIN
assets/sprites/pipe.bmp
Normal file
BIN
assets/sprites/pipe.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 65 KiB |
30
include/engine.h
Normal file
30
include/engine.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include "input.h"
|
||||||
|
#include "text.h"
|
||||||
|
#include "sprite.h"
|
||||||
|
#include "vector.h"
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "sound.h"
|
||||||
|
|
||||||
|
class Engine
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
const char* ctitle;
|
||||||
|
int frameStart = 0;
|
||||||
|
bool soundInitialized = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Input input;
|
||||||
|
int targetFrameRate = 60;
|
||||||
|
SDL_Window *window;
|
||||||
|
SDL_Renderer *renderer;
|
||||||
|
|
||||||
|
Engine(std::string title, int width, int height);
|
||||||
|
void initSound();
|
||||||
|
void clear(SDL_Color color);
|
||||||
|
void startFrame();
|
||||||
|
void render();
|
||||||
|
void update();
|
||||||
|
~Engine();
|
||||||
|
};
|
39
include/input.h
Normal file
39
include/input.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#include <SDL.h>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct Controller
|
||||||
|
{
|
||||||
|
SDL_GameController* controller;
|
||||||
|
std::string name;
|
||||||
|
std::map<Uint8, bool> buttons;
|
||||||
|
Sint16 leftStickX = 0;
|
||||||
|
Sint16 leftStickY = 0;
|
||||||
|
Sint16 rightStickX = 0;
|
||||||
|
Sint16 rightStickY = 0;
|
||||||
|
Sint16 leftTrigger = 0;
|
||||||
|
Sint16 rightTrigger = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Mouse
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int wheel;
|
||||||
|
std::map<int, bool> buttons;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Input
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
SDL_Event event;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool exit;
|
||||||
|
std::map<int, Controller> controllers;
|
||||||
|
std::map<SDL_Keycode, bool> activeKeys;
|
||||||
|
Mouse mouse;
|
||||||
|
|
||||||
|
Input();
|
||||||
|
void update();
|
||||||
|
};
|
26
include/sound.h
Normal file
26
include/sound.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include <SDL_mixer.h>
|
||||||
|
|
||||||
|
class Music
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Mix_Music* music;
|
||||||
|
public:
|
||||||
|
Music(const char* path);
|
||||||
|
void play(int loops = -1);
|
||||||
|
void pause();
|
||||||
|
void stop();
|
||||||
|
void resume();
|
||||||
|
void setVolume(int volume);
|
||||||
|
~Music();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Effect
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Mix_Chunk* effect;
|
||||||
|
public:
|
||||||
|
Effect(const char* path);
|
||||||
|
void setVolume(int volume);
|
||||||
|
void play(int loops = 0, int channel = -1);
|
||||||
|
~Effect();
|
||||||
|
};
|
67
include/sprite.h
Normal file
67
include/sprite.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include <SDL.h>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "vector.h"
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class Sprite
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::map<std::string, SDL_Rect> frames;
|
||||||
|
SDL_Surface* surface;
|
||||||
|
SDL_Texture* Texture;
|
||||||
|
int_vec2 size;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDL_Rect dstrect;
|
||||||
|
int_vec2 scale = { 1, 1 };
|
||||||
|
double angle = 0;
|
||||||
|
Sprite(SDL_Renderer* renderer, SDL_Surface* surface);
|
||||||
|
void draw(SDL_Renderer* renderer, std::string frame, bool autoRect = true, SDL_RendererFlip flip = SDL_FLIP_NONE);
|
||||||
|
void addFrame(std::string name, SDL_Rect rect);
|
||||||
|
void move(int_vec2 position);
|
||||||
|
void setPos(int_vec2 position);
|
||||||
|
int_vec2 getSize(std::string frame);
|
||||||
|
void autorect(std::string frame);
|
||||||
|
~Sprite();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Animation
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::vector<std::string> frames;
|
||||||
|
Sprite* sprite;
|
||||||
|
int currentFrame = 0;
|
||||||
|
int frameDuration = 0;
|
||||||
|
int frameCounter = 0;
|
||||||
|
std::string currentFrameName;
|
||||||
|
int frameIndex = 0;
|
||||||
|
int frameDirection = 1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool loop = true;
|
||||||
|
bool pingpong = false;
|
||||||
|
Animation(std::map<std::string, SDL_Rect> frames, Sprite* sprite, int frameDuration);
|
||||||
|
void update();
|
||||||
|
void reset(bool ifFinish = false);
|
||||||
|
void draw(SDL_Renderer* renderer, bool autoRect = true, bool flip = false);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AnimationManager
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::map<std::string, Animation*> animations;
|
||||||
|
std::map<std::string, bool> flip;
|
||||||
|
std::map<std::string, bool> autoRect;
|
||||||
|
std::string currentAnimation;
|
||||||
|
Sprite* sprite;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AnimationManager(Sprite* sprite);
|
||||||
|
void addAnimation(std::string name, std::map<std::string, SDL_Rect> animation, int frameDuration = 10, bool flip = false, bool autoRect = true, bool loop = true, bool pingpong = false);
|
||||||
|
void setAnimation(std::string name);
|
||||||
|
void update();
|
||||||
|
void play(std::string name);
|
||||||
|
void draw(SDL_Renderer* renderer);
|
||||||
|
};
|
19
include/text.h
Normal file
19
include/text.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_ttf.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Text
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
SDL_Surface* surface;
|
||||||
|
SDL_Texture* texture;
|
||||||
|
TTF_Font* font;
|
||||||
|
SDL_Color color;
|
||||||
|
SDL_Rect* rect;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Text(std::string font, int size, SDL_Color color);
|
||||||
|
~Text();
|
||||||
|
void update(std::string text, SDL_Renderer* renderer);
|
||||||
|
void draw(SDL_Renderer* renderer, int x, int y);
|
||||||
|
};
|
58
include/vector.h
Normal file
58
include/vector.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// prevent multiple inclusion
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// class for 2D float vector
|
||||||
|
class float_vec2
|
||||||
|
{
|
||||||
|
// public members
|
||||||
|
public:
|
||||||
|
// x and y coordinates
|
||||||
|
float x, y;
|
||||||
|
// operator functions
|
||||||
|
float_vec2 operator+(float_vec2 vec)
|
||||||
|
{
|
||||||
|
return { x + vec.x, y + vec.y };
|
||||||
|
}
|
||||||
|
float_vec2 operator*(float v)
|
||||||
|
{
|
||||||
|
return { x * v, y * v };
|
||||||
|
}
|
||||||
|
float_vec2 operator*(float_vec2 vec)
|
||||||
|
{
|
||||||
|
return { x * vec.x, y * vec.y };
|
||||||
|
}
|
||||||
|
float_vec2 operator-(float_vec2 vec)
|
||||||
|
{
|
||||||
|
return { x - vec.x, y - vec.y };
|
||||||
|
}
|
||||||
|
float_vec2 operator-(float v)
|
||||||
|
{
|
||||||
|
return { x - v, y - v };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// class for 2D integer vector
|
||||||
|
class int_vec2
|
||||||
|
{
|
||||||
|
// public members
|
||||||
|
public:
|
||||||
|
// x and y coordinates
|
||||||
|
int x, y;
|
||||||
|
// operator functions
|
||||||
|
int_vec2 operator+(int_vec2 vec)
|
||||||
|
{
|
||||||
|
return { x + vec.x, y + vec.y };
|
||||||
|
}
|
||||||
|
int_vec2 operator*(int v)
|
||||||
|
{
|
||||||
|
return { x * v, y * v };
|
||||||
|
}
|
||||||
|
int_vec2 operator*(int_vec2 vec)
|
||||||
|
{
|
||||||
|
return { x * vec.x, y * vec.y };
|
||||||
|
}
|
||||||
|
int_vec2 operator-(int_vec2 vec)
|
||||||
|
{
|
||||||
|
return { x - vec.x, y - vec.y };
|
||||||
|
}
|
||||||
|
};
|
20
makefile
Normal file
20
makefile
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
CXX = g++
|
||||||
|
LDFLAGS = `sdl2-config --libs` -l SDL2_ttf -l SDL2_mixer
|
||||||
|
CXXFLAGS = `sdl2-config --cflags` -pedantic -O2 -std=c++17 -lX11 -lstdc++fs -I include
|
||||||
|
SRC = $(wildcard src/*.cpp)
|
||||||
|
OBJ = $(addprefix build/, $(notdir $(SRC:.cpp=.o)))
|
||||||
|
TARGET = build/x86_64/main.x86_64
|
||||||
|
|
||||||
|
all: clean dirs $(TARGET)
|
||||||
|
|
||||||
|
dirs:
|
||||||
|
@mkdir -p build/x86_64
|
||||||
|
|
||||||
|
$(TARGET): $(OBJ)
|
||||||
|
$(CXX) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
build/%.o: src/%.cpp
|
||||||
|
$(CXX) -c -o $@ $< $(CXXFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -f $(OBJ) $(TARGET)
|
71
src/engine.cpp
Normal file
71
src/engine.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include "engine.h"
|
||||||
|
|
||||||
|
Engine::Engine(std::string title, int width, int height)
|
||||||
|
{
|
||||||
|
// convert title to char*
|
||||||
|
ctitle = title.c_str();
|
||||||
|
|
||||||
|
// Initialize SDL and TFF;
|
||||||
|
TTF_Init();
|
||||||
|
SDL_Init(SDL_INIT_EVERYTHING);
|
||||||
|
|
||||||
|
// Create window and renderer
|
||||||
|
window = SDL_CreateWindow(ctitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_SHOWN);
|
||||||
|
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::initSound()
|
||||||
|
{
|
||||||
|
// Initialize sound
|
||||||
|
Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048);
|
||||||
|
soundInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::clear(SDL_Color color)
|
||||||
|
{
|
||||||
|
// Set color
|
||||||
|
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
|
||||||
|
|
||||||
|
// Clear screen
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::startFrame()
|
||||||
|
{
|
||||||
|
// Start frame
|
||||||
|
frameStart = SDL_GetTicks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::render()
|
||||||
|
{
|
||||||
|
// Render screen
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
|
||||||
|
if (1000 / targetFrameRate > SDL_GetTicks() - frameStart)
|
||||||
|
{
|
||||||
|
SDL_Delay(1000 / targetFrameRate - (SDL_GetTicks() - frameStart));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::update()
|
||||||
|
{
|
||||||
|
// Update input
|
||||||
|
input.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Engine::~Engine()
|
||||||
|
{
|
||||||
|
// Free renderer and window
|
||||||
|
SDL_DestroyRenderer(renderer);
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
|
||||||
|
// If sound is initialized, quit Mix
|
||||||
|
if (soundInitialized)
|
||||||
|
{
|
||||||
|
Mix_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quit SDL and TTF
|
||||||
|
SDL_Quit();
|
||||||
|
TTF_Quit();
|
||||||
|
}
|
56
src/input.cpp
Normal file
56
src/input.cpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include "input.h"
|
||||||
|
|
||||||
|
Input::Input()
|
||||||
|
{
|
||||||
|
SDL_Init(SDL_INIT_JOYSTICK);
|
||||||
|
exit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Input::update()
|
||||||
|
{
|
||||||
|
while (SDL_PollEvent(&event))
|
||||||
|
{
|
||||||
|
switch (event.type)
|
||||||
|
{
|
||||||
|
case SDL_CONTROLLERBUTTONDOWN:
|
||||||
|
controllers[event.cbutton.which].buttons[event.cbutton.button] = true;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLERBUTTONUP:
|
||||||
|
controllers[event.cbutton.which].buttons[event.cbutton.button] = false;
|
||||||
|
break;
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
mouse.buttons[event.button.button] = true;
|
||||||
|
break;
|
||||||
|
case SDL_MOUSEBUTTONUP:
|
||||||
|
mouse.buttons[event.button.button] = false;
|
||||||
|
break;
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
activeKeys[event.key.keysym.sym] = true;
|
||||||
|
break;
|
||||||
|
case SDL_KEYUP:
|
||||||
|
activeKeys.erase(event.key.keysym.sym);
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLERDEVICEADDED:
|
||||||
|
controllers[SDL_NumJoysticks() - 1] = {
|
||||||
|
SDL_GameControllerOpen(SDL_NumJoysticks() - 1),
|
||||||
|
SDL_GameControllerName(SDL_GameControllerOpen(SDL_NumJoysticks() - 1))
|
||||||
|
};
|
||||||
|
printf("Controller added: %s\n", controllers[SDL_NumJoysticks() - 1].name.c_str());
|
||||||
|
break;
|
||||||
|
case SDL_QUIT:
|
||||||
|
exit = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (auto& controller : controllers)
|
||||||
|
{
|
||||||
|
controller.second.leftStickX = SDL_GameControllerGetAxis(controller.second.controller, SDL_CONTROLLER_AXIS_LEFTX);
|
||||||
|
controller.second.leftStickY = SDL_GameControllerGetAxis(controller.second.controller, SDL_CONTROLLER_AXIS_LEFTY);
|
||||||
|
controller.second.rightStickX = SDL_GameControllerGetAxis(controller.second.controller, SDL_CONTROLLER_AXIS_RIGHTX);
|
||||||
|
controller.second.rightStickY = SDL_GameControllerGetAxis(controller.second.controller, SDL_CONTROLLER_AXIS_RIGHTY);
|
||||||
|
controller.second.leftTrigger = SDL_GameControllerGetAxis(controller.second.controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
|
||||||
|
controller.second.rightTrigger = SDL_GameControllerGetAxis(controller.second.controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
|
||||||
|
}
|
||||||
|
SDL_GetMouseState(&mouse.x, &mouse.y);
|
||||||
|
mouse.wheel = event.wheel.y;
|
||||||
|
}
|
||||||
|
}
|
225
src/main.cpp
Normal file
225
src/main.cpp
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
#include "engine.h"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
SDL_Surface* background;
|
||||||
|
SDL_Surface* pipe;
|
||||||
|
SDL_Surface* ground;
|
||||||
|
SDL_Surface* bird;
|
||||||
|
Effect* flapSound;
|
||||||
|
Effect* hitSound;
|
||||||
|
Effect* pointSound;
|
||||||
|
Effect* dieSound;
|
||||||
|
Engine *engine;
|
||||||
|
|
||||||
|
int random(int min, int max)
|
||||||
|
{
|
||||||
|
return rand() % (max - min + 1) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
void quit()
|
||||||
|
{
|
||||||
|
delete engine;
|
||||||
|
SDL_FreeSurface(background);
|
||||||
|
SDL_FreeSurface(pipe);
|
||||||
|
SDL_FreeSurface(ground);
|
||||||
|
SDL_FreeSurface(bird);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
srand(time(NULL));
|
||||||
|
engine = new Engine("Flappy Bird", 288, 512);
|
||||||
|
engine->initSound();
|
||||||
|
engine->targetFrameRate = 60;
|
||||||
|
|
||||||
|
background = SDL_LoadBMP("assets/sprites/background.bmp");
|
||||||
|
pipe = SDL_LoadBMP("assets/sprites/pipe.bmp");
|
||||||
|
ground = SDL_LoadBMP("assets/sprites/ground.bmp");
|
||||||
|
bird = SDL_LoadBMP("assets/sprites/bird.bmp");
|
||||||
|
|
||||||
|
Text* scoreText = new Text("assets/fonts/C64.ttf", 24, { 255, 255, 255, 255 });
|
||||||
|
|
||||||
|
flapSound = new Effect("assets/sounds/wing.wav");
|
||||||
|
hitSound = new Effect("assets/sounds/hit.wav");
|
||||||
|
pointSound = new Effect("assets/sounds/point.wav");
|
||||||
|
dieSound = new Effect("assets/sounds/die.wav");
|
||||||
|
flapSound->setVolume(50);
|
||||||
|
hitSound->setVolume(50);
|
||||||
|
pointSound->setVolume(50);
|
||||||
|
dieSound->setVolume(50);
|
||||||
|
Sprite* backgroundSprite = new Sprite(engine->renderer, background);
|
||||||
|
backgroundSprite->addFrame("background", { 0, 0, 288, 512 });
|
||||||
|
|
||||||
|
Sprite* groundSprite = new Sprite(engine->renderer, ground);
|
||||||
|
groundSprite->addFrame("ground", { 0, 0, 336, 112 });
|
||||||
|
groundSprite->setPos({ 0, 400 });
|
||||||
|
|
||||||
|
Sprite* pipeSprite = new Sprite(engine->renderer, pipe);
|
||||||
|
pipeSprite->addFrame("pipe", { 0, 0, 52, 320 });
|
||||||
|
|
||||||
|
int groundSpeed = 1;
|
||||||
|
int groundPosx[2] = { 0, 336 };
|
||||||
|
|
||||||
|
int pipeSpeed = 1;
|
||||||
|
int pipeGap = 125;
|
||||||
|
int pipeSet1[2] = { 288, random(0, 320 - pipeGap) };
|
||||||
|
int pipeSet2[2] = { 288 + 144 + 26, random(0, 320 - pipeGap) };
|
||||||
|
|
||||||
|
|
||||||
|
Sprite* birdSprite = new Sprite(engine->renderer, bird);
|
||||||
|
AnimationManager* birdAnimations = new AnimationManager(birdSprite);
|
||||||
|
std::map<std::string, SDL_Rect> flap = {
|
||||||
|
{ "up", { 34*2, 0, 34, 24 } },
|
||||||
|
{ "mid", { 0, 0, 34, 24 } },
|
||||||
|
{ "down", { 34*1, 0, 34, 24 } },
|
||||||
|
};
|
||||||
|
std::map<std::string, SDL_Rect> idle = {
|
||||||
|
{ "mid", { 0, 0, 34, 24 } },
|
||||||
|
};
|
||||||
|
birdAnimations->addAnimation("flap", flap, 15, false, true, true, true);
|
||||||
|
birdAnimations->setAnimation("flap");
|
||||||
|
|
||||||
|
float birdAngle = 0;
|
||||||
|
float birdGravity = 0.2;
|
||||||
|
float birdVelocity = 0;
|
||||||
|
float birdJump = -3.5;
|
||||||
|
float birdY = 200;
|
||||||
|
bool dead = false;
|
||||||
|
int score = 0;
|
||||||
|
int jumpDelay = 0;
|
||||||
|
bool deathSoundPlayed = false;
|
||||||
|
int scoreCooldown = 0;
|
||||||
|
|
||||||
|
scoreText->update("0", engine->renderer);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
|
||||||
|
engine->startFrame();
|
||||||
|
|
||||||
|
engine->update();
|
||||||
|
|
||||||
|
if (engine->input.exit || engine->input.activeKeys[SDLK_ESCAPE])
|
||||||
|
{
|
||||||
|
quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
birdVelocity += birdGravity;
|
||||||
|
|
||||||
|
if (engine->input.activeKeys[SDLK_SPACE] && !dead && jumpDelay == 0)
|
||||||
|
{
|
||||||
|
birdVelocity = birdJump;
|
||||||
|
flapSound->play();
|
||||||
|
jumpDelay = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jumpDelay > 0)
|
||||||
|
{
|
||||||
|
jumpDelay--;
|
||||||
|
}
|
||||||
|
|
||||||
|
birdY += birdVelocity;
|
||||||
|
birdAngle = birdVelocity * 3;
|
||||||
|
|
||||||
|
engine->clear({ 0, 0, 0, 255 });
|
||||||
|
backgroundSprite->draw(engine->renderer, "background");
|
||||||
|
|
||||||
|
pipeSprite->setPos({ pipeSet1[0], pipeSet1[1] - 320 });
|
||||||
|
pipeSprite->draw(engine->renderer, "pipe", true, SDL_FLIP_VERTICAL);
|
||||||
|
pipeSprite->setPos({ pipeSet1[0], pipeSet1[1] + pipeGap });
|
||||||
|
pipeSprite->draw(engine->renderer, "pipe");
|
||||||
|
|
||||||
|
pipeSprite->setPos({ pipeSet2[0], pipeSet2[1] - 320 });
|
||||||
|
pipeSprite->draw(engine->renderer, "pipe", true, SDL_FLIP_VERTICAL);
|
||||||
|
pipeSprite->setPos({ pipeSet2[0], pipeSet2[1] + pipeGap });
|
||||||
|
pipeSprite->draw(engine->renderer, "pipe");
|
||||||
|
|
||||||
|
pipeSet1[0] -= pipeSpeed;
|
||||||
|
pipeSet2[0] -= pipeSpeed;
|
||||||
|
|
||||||
|
if (birdY >= 400 || birdY <= 0)
|
||||||
|
{
|
||||||
|
dead = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (birdSprite->dstrect.x + birdSprite->dstrect.w >= pipeSet1[0] && birdSprite->dstrect.x <= pipeSet1[0] + 52)
|
||||||
|
{
|
||||||
|
if (birdSprite->dstrect.y <= pipeSet1[1] || birdSprite->dstrect.y + birdSprite->dstrect.h >= pipeSet1[1] + pipeGap)
|
||||||
|
{
|
||||||
|
dead = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (birdSprite->dstrect.x + birdSprite->dstrect.w >= pipeSet2[0] && birdSprite->dstrect.x <= pipeSet2[0] + 52)
|
||||||
|
{
|
||||||
|
if (birdSprite->dstrect.y <= pipeSet2[1] || birdSprite->dstrect.y + birdSprite->dstrect.h >= pipeSet2[1] + pipeGap)
|
||||||
|
{
|
||||||
|
dead = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (birdSprite->dstrect.x >= pipeSet1[0] + 26 - 24 && birdSprite->dstrect.x <= pipeSet1[0] + 26 - 24 + pipeSpeed && !dead && scoreCooldown == 0)
|
||||||
|
{
|
||||||
|
score++;
|
||||||
|
scoreCooldown = 5;
|
||||||
|
pointSound->play();
|
||||||
|
scoreText->update(std::to_string(score), engine->renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (birdSprite->dstrect.x >= pipeSet2[0] + 26 - 24 && birdSprite->dstrect.x <= pipeSet2[0] + 26 - 24 + pipeSpeed && !dead && scoreCooldown == 0)
|
||||||
|
{
|
||||||
|
score++;
|
||||||
|
scoreCooldown = 5;
|
||||||
|
pointSound->play();
|
||||||
|
scoreText->update(std::to_string(score), engine->renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scoreCooldown > 0)
|
||||||
|
{
|
||||||
|
scoreCooldown--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dead && !deathSoundPlayed)
|
||||||
|
{
|
||||||
|
pipeSpeed = 0;
|
||||||
|
groundSpeed = 0;
|
||||||
|
hitSound->play();
|
||||||
|
dieSound->play();
|
||||||
|
deathSoundPlayed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipeSet1[0] <= -52)
|
||||||
|
{
|
||||||
|
pipeSet1[0] = 288;
|
||||||
|
pipeSet1[1] = random(120, 320 - pipeGap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipeSet2[0] <= -52)
|
||||||
|
{
|
||||||
|
pipeSet2[0] = 288;
|
||||||
|
pipeSet2[1] = random(120, 320 - pipeGap);
|
||||||
|
}
|
||||||
|
|
||||||
|
birdSprite->angle = birdAngle;
|
||||||
|
birdSprite->setPos({ 50, (int)birdY });
|
||||||
|
birdAnimations->update();
|
||||||
|
birdAnimations->draw(engine->renderer);
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
groundSprite->setPos({ groundPosx[i], 400 });
|
||||||
|
groundSprite->draw(engine->renderer, "ground");
|
||||||
|
groundPosx[i] -= groundSpeed;
|
||||||
|
if (groundPosx[i] <= -336)
|
||||||
|
{
|
||||||
|
groundPosx[i] = 336;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scoreText->draw(engine->renderer, 144, 50);
|
||||||
|
engine->render();
|
||||||
|
}
|
||||||
|
quit();
|
||||||
|
return 0;
|
||||||
|
}
|
56
src/sound.cpp
Normal file
56
src/sound.cpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include "sound.h"
|
||||||
|
|
||||||
|
Music::Music(const char* path)
|
||||||
|
{
|
||||||
|
music = Mix_LoadMUS(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Music::play(int loops)
|
||||||
|
{
|
||||||
|
Mix_PlayMusic(music, loops);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Music::pause()
|
||||||
|
{
|
||||||
|
Mix_PauseMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Music::stop()
|
||||||
|
{
|
||||||
|
Mix_HaltMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Music::resume()
|
||||||
|
{
|
||||||
|
Mix_ResumeMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Music::setVolume(int volume)
|
||||||
|
{
|
||||||
|
Mix_VolumeMusic(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
Music::~Music()
|
||||||
|
{
|
||||||
|
Mix_FreeMusic(music);
|
||||||
|
}
|
||||||
|
|
||||||
|
Effect::Effect(const char* path)
|
||||||
|
{
|
||||||
|
effect = Mix_LoadWAV(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Effect::play(int loops, int channel)
|
||||||
|
{
|
||||||
|
Mix_PlayChannel(channel, effect, loops);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Effect::setVolume(int volume)
|
||||||
|
{
|
||||||
|
Mix_VolumeChunk(effect, volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
Effect::~Effect()
|
||||||
|
{
|
||||||
|
Mix_FreeChunk(effect);
|
||||||
|
}
|
164
src/sprite.cpp
Normal file
164
src/sprite.cpp
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
#include "sprite.h"
|
||||||
|
|
||||||
|
Sprite::Sprite(SDL_Renderer *renderer, SDL_Surface *surface)
|
||||||
|
{
|
||||||
|
Texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||||
|
dstrect = { 0, 0, surface->w, surface->h };
|
||||||
|
}
|
||||||
|
|
||||||
|
Sprite::~Sprite()
|
||||||
|
{
|
||||||
|
SDL_DestroyTexture(Texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sprite::draw(SDL_Renderer* renderer, std::string frame, bool autoRect, SDL_RendererFlip flip)
|
||||||
|
{
|
||||||
|
if (frames.find(frame) == frames.end())
|
||||||
|
{
|
||||||
|
printf("Frame not found\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (autoRect)
|
||||||
|
{
|
||||||
|
dstrect = { dstrect.x, dstrect.y, frames[frame].w, frames[frame].h };
|
||||||
|
}
|
||||||
|
SDL_SetTextureAlphaMod(Texture, 255);
|
||||||
|
dstrect.w *= scale.x;
|
||||||
|
dstrect.h *= scale.y;
|
||||||
|
SDL_RenderCopyEx(renderer, Texture, &frames[frame], &dstrect, angle, NULL, flip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sprite::addFrame(std::string name, SDL_Rect rect)
|
||||||
|
{
|
||||||
|
frames[name] = rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sprite::setPos(int_vec2 position)
|
||||||
|
{
|
||||||
|
dstrect.x = position.x;
|
||||||
|
dstrect.y = position.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sprite::move(int_vec2 position)
|
||||||
|
{
|
||||||
|
dstrect.x += position.x;
|
||||||
|
dstrect.y += position.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int_vec2 Sprite::getSize(std::string frame)
|
||||||
|
{
|
||||||
|
size = { frames[frame].w, frames[frame].h };
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sprite::autorect(std::string frame)
|
||||||
|
{
|
||||||
|
dstrect = { dstrect.x, dstrect.y, frames[frame].w, frames[frame].h };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Animation::Animation(std::map<std::string, SDL_Rect> frames, Sprite* sprite, int frameDuration)
|
||||||
|
{
|
||||||
|
this->sprite = sprite;
|
||||||
|
this->frameDuration = frameDuration;
|
||||||
|
|
||||||
|
for (auto const& x : frames)
|
||||||
|
{
|
||||||
|
this->frames.push_back(x.first);
|
||||||
|
this->sprite->addFrame(x.first, x.second);
|
||||||
|
}
|
||||||
|
currentFrameName = this->frames[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::update()
|
||||||
|
{
|
||||||
|
frameCounter++;
|
||||||
|
if (frameCounter >= frameDuration)
|
||||||
|
{
|
||||||
|
frameCounter = 0;
|
||||||
|
if (pingpong)
|
||||||
|
{
|
||||||
|
frameIndex += frameDirection;
|
||||||
|
if (frameIndex >= frames.size() - 1 || frameIndex <= 0)
|
||||||
|
{
|
||||||
|
if (!loop)
|
||||||
|
{
|
||||||
|
frameDirection = 0;
|
||||||
|
} else {
|
||||||
|
frameDirection *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
frameIndex++;
|
||||||
|
if (frameIndex >= frames.size())
|
||||||
|
{
|
||||||
|
if (!loop)
|
||||||
|
{
|
||||||
|
frameIndex = frames.size() - 1;
|
||||||
|
} else {
|
||||||
|
frameIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
currentFrameName = frames[frameIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::reset(bool ifFinish)
|
||||||
|
{
|
||||||
|
if (ifFinish)
|
||||||
|
{
|
||||||
|
if (frameIndex == frames.size() - 1)
|
||||||
|
{
|
||||||
|
frameIndex = 0;
|
||||||
|
currentFrameName = frames[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
frameIndex = 0;
|
||||||
|
currentFrameName = frames[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::draw(SDL_Renderer* renderer, bool autoRect, bool flip)
|
||||||
|
{
|
||||||
|
sprite->draw(renderer, currentFrameName, autoRect, flip ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationManager::AnimationManager(Sprite* sprite)
|
||||||
|
{
|
||||||
|
this->sprite = sprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationManager::addAnimation(std::string name, std::map<std::string, SDL_Rect> frames, int frameDuration, bool flip, bool autoRect, bool loop, bool pingpong)
|
||||||
|
{
|
||||||
|
animations[name] = new Animation(frames, sprite, frameDuration);
|
||||||
|
this->flip[name] = flip;
|
||||||
|
this->autoRect[name] = autoRect;
|
||||||
|
animations[name]->loop = loop;
|
||||||
|
animations[name]->pingpong = pingpong;
|
||||||
|
}
|
||||||
|
void autorect(std::string frame);
|
||||||
|
void AnimationManager::setAnimation(std::string name)
|
||||||
|
{
|
||||||
|
currentAnimation = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationManager::update()
|
||||||
|
{
|
||||||
|
animations[currentAnimation]->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationManager::draw(SDL_Renderer* renderer)
|
||||||
|
{
|
||||||
|
animations[currentAnimation]->draw(renderer, autoRect[currentAnimation], flip[currentAnimation]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationManager::play(std::string name)
|
||||||
|
{
|
||||||
|
setAnimation(name);
|
||||||
|
animations[currentAnimation]->reset(true);
|
||||||
|
}
|
30
src/text.cpp
Normal file
30
src/text.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include "text.h"
|
||||||
|
|
||||||
|
Text::Text(std::string font, int size, SDL_Color color)
|
||||||
|
{
|
||||||
|
this->font = TTF_OpenFont(font.c_str(), size);
|
||||||
|
this->color = color;
|
||||||
|
rect = new SDL_Rect();
|
||||||
|
}
|
||||||
|
|
||||||
|
Text::~Text()
|
||||||
|
{
|
||||||
|
SDL_FreeSurface(surface);
|
||||||
|
SDL_DestroyTexture(texture);
|
||||||
|
TTF_CloseFont(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Text::update(std::string text, SDL_Renderer* renderer)
|
||||||
|
{
|
||||||
|
surface = TTF_RenderText_Solid(font, text.c_str(), color);
|
||||||
|
texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||||
|
rect->w = surface->w;
|
||||||
|
rect->h = surface->h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Text::draw(SDL_Renderer* renderer, int x, int y)
|
||||||
|
{
|
||||||
|
rect->x = x - rect->w / 2;
|
||||||
|
rect->y = y - rect->h / 2;
|
||||||
|
SDL_RenderCopy(renderer, texture, NULL, rect);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user