commit
a5e34055ce
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,2 @@
|
||||
.vscode
|
||||
build
|
||||
main.x86_64
|
||||
build
|
9
LICENSE
9
LICENSE
@ -1,9 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 acetheking987
|
||||
|
||||
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.
|
13
README.md
13
README.md
@ -1,13 +0,0 @@
|
||||
# bootleg-game-engine
|
||||
|
||||
A bootleg "game engine" in c++, using SDL2 for rendering and input handling.
|
||||
|
||||
## Dependencies
|
||||
- SDL2
|
||||
- SDL2_ttf
|
||||
- SDL2_mixer
|
||||
|
||||
## Building
|
||||
```bash
|
||||
$ make
|
||||
```
|
BIN
assets/bird.png
Normal file
BIN
assets/bird.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 497 B |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 31 MiB |
59
include/assets.hpp
Normal file
59
include/assets.hpp
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef ASSETS_HPP
|
||||
#define ASSETS_HPP
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
// Structs
|
||||
struct Rect {
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
Rect(int x = 0, int y = 0, int width = 0, int height = 0)
|
||||
: x(x), y(y), width(width), height(height) {}
|
||||
Rect(const SDL_Rect& rect)
|
||||
: x(rect.x), y(rect.y), width(rect.w), height(rect.h) {}
|
||||
};
|
||||
|
||||
struct Tile {
|
||||
Rect srcRect;
|
||||
std::string assetName;
|
||||
};
|
||||
|
||||
// Classes
|
||||
class AssetManager {
|
||||
public:
|
||||
AssetManager();
|
||||
~AssetManager();
|
||||
|
||||
void load(const std::string& name, const std::string& filePath);
|
||||
SDL_Surface* getAsset(const std::string& name) const;
|
||||
void unloadAsset(const std::string& name);
|
||||
void clearAssets();
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, SDL_Surface*> assets;
|
||||
};
|
||||
|
||||
struct TileMap {
|
||||
public:
|
||||
TileMap(AssetManager& assetManager);
|
||||
~TileMap();
|
||||
|
||||
void addTile(const std::string& name, const Tile& tile);
|
||||
Tile getTile(const std::string& name) const;
|
||||
SDL_Surface* getTileAsset(const std::string& name) const;
|
||||
Rect getTileRect(const std::string& name) const;
|
||||
void removeTile(const std::string& name);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, Tile> tiles;
|
||||
AssetManager& assetManager;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,30 +0,0 @@
|
||||
#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();
|
||||
};
|
50
include/engine.hpp
Normal file
50
include/engine.hpp
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef RENDER_HPP
|
||||
#define RENDER_HPP
|
||||
|
||||
// Include necessary headers
|
||||
#include "assets.hpp"
|
||||
#include "input.hpp"
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
// Structs
|
||||
struct Color {
|
||||
Uint8 r;
|
||||
Uint8 g;
|
||||
Uint8 b;
|
||||
Uint8 a;
|
||||
|
||||
Color(Uint8 r = 0, Uint8 g = 0, Uint8 b = 0, Uint8 a = 255) : r(r), g(g), b(b), a(a) {}
|
||||
};
|
||||
|
||||
// Classes
|
||||
class Engine {
|
||||
public:
|
||||
Engine(const char* windowTitle, int windowWidth, int windowHeight, int windowFlags);
|
||||
Engine(const char* windowTitle, int windowWidth, int windowHeight)
|
||||
: Engine(windowTitle, windowWidth, windowHeight, 0) {}
|
||||
~Engine();
|
||||
|
||||
void targetFPS(int fps);
|
||||
void startFrame();
|
||||
void clearScreen(const Color& color);
|
||||
void draw(SDL_Surface* surface, Rect destRect);
|
||||
void draw(SDL_Surface* surface, Rect srcRect, Rect destRect);
|
||||
void draw(Tile tile, Rect destRect);
|
||||
void draw(SDL_Surface* surface, Vector2 pos) { draw(surface, Rect(pos.x, pos.y, surface->w, surface->h)); }
|
||||
void draw(SDL_Surface* surface, Rect srcRect, Vector2 pos) { draw(surface, srcRect, Rect(pos.x, pos.y, srcRect.width, srcRect.height)); }
|
||||
void draw(Tile tile, Vector2 pos) { draw(tile, Rect(pos.x, pos.y, tile.srcRect.width, tile.srcRect.height)); }
|
||||
void present();
|
||||
|
||||
Input input; // Input handler
|
||||
AssetManager assets; // Asset manager
|
||||
|
||||
private:
|
||||
SDL_Window* window;
|
||||
SDL_Renderer* renderer;
|
||||
int targetFPSValue = 60; // Target frames per second
|
||||
Uint64 frameStartTime = 0; // Start time of the current frame
|
||||
Uint64 frameEndTime = 0; // End time of the current frame
|
||||
Uint64 frameDuration = 0; // Duration of the current frame in milliseconds
|
||||
};
|
||||
|
||||
#endif
|
@ -1,61 +0,0 @@
|
||||
#include <SDL.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
enum CBUTTONS
|
||||
{
|
||||
DPAD_UP = SDL_CONTROLLER_BUTTON_DPAD_UP,
|
||||
DPAD_DOWN = SDL_CONTROLLER_BUTTON_DPAD_DOWN,
|
||||
DPAD_LEFT = SDL_CONTROLLER_BUTTON_DPAD_LEFT,
|
||||
DPAD_RIGHT = SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
|
||||
A = SDL_CONTROLLER_BUTTON_A,
|
||||
B = SDL_CONTROLLER_BUTTON_B,
|
||||
X = SDL_CONTROLLER_BUTTON_X,
|
||||
Y = SDL_CONTROLLER_BUTTON_Y,
|
||||
BACK = SDL_CONTROLLER_BUTTON_BACK,
|
||||
GUIDE = SDL_CONTROLLER_BUTTON_GUIDE,
|
||||
START = SDL_CONTROLLER_BUTTON_START,
|
||||
LEFTSTICK = SDL_CONTROLLER_BUTTON_LEFTSTICK,
|
||||
RIGHTSTICK = SDL_CONTROLLER_BUTTON_RIGHTSTICK,
|
||||
LEFTSHOULDER = SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
|
||||
RIGHTSHOULDER = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
|
||||
};
|
||||
|
||||
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();
|
||||
bool keysPressed(std::vector<SDL_Keycode> keys);
|
||||
bool controllerPressed(std::vector<Uint8> buttons, int controller = 0);
|
||||
};
|
45
include/input.hpp
Normal file
45
include/input.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef INPUT_HPP
|
||||
#define INPUT_HPP
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
// Structs
|
||||
struct Vector2 {
|
||||
int x;
|
||||
int y;
|
||||
Vector2(int x = 0, int y = 0) : x(x), y(y) {}
|
||||
};
|
||||
|
||||
// Classes
|
||||
class Input {
|
||||
public:
|
||||
Input();
|
||||
~Input();
|
||||
|
||||
void handleEvents();
|
||||
bool quitRequested() const;
|
||||
bool isKeyPressed(SDL_Scancode key);
|
||||
bool isKeyPressed(std::vector<SDL_Scancode> keys);
|
||||
bool hasKeyBeenPressed(SDL_Scancode key);
|
||||
bool hasKeyBeenPressed(std::vector<SDL_Scancode> keys);
|
||||
bool isMouseButtonPressed(Uint8 button);
|
||||
bool isMouseButtonPressed(std::vector<Uint8> buttons);
|
||||
bool hasMouseButtonBeenPressed(Uint8 button);
|
||||
bool hasMouseButtonBeenPressed(std::vector<Uint8> buttons);
|
||||
Vector2 getMousePosition() const;
|
||||
|
||||
|
||||
private:
|
||||
SDL_Event event;
|
||||
std::unordered_map<SDL_Scancode, bool> keyStates;
|
||||
std::unordered_map<SDL_Scancode, bool> keyFallingEdgeStates;
|
||||
std::unordered_map<Uint8, bool> mouseButtonStates;
|
||||
std::unordered_map<Uint8, bool> mouseButtonFallingEdgeStates;
|
||||
Vector2 mousePosition;
|
||||
bool quitRequestedFlag = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,26 +0,0 @@
|
||||
#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();
|
||||
};
|
@ -1,68 +0,0 @@
|
||||
#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, bool flip = false);
|
||||
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 frameDuration = 0;
|
||||
int frameCounter = 0;
|
||||
std::string currentFrameName;
|
||||
|
||||
public:
|
||||
bool end = false;
|
||||
int frameDirection = 1;
|
||||
int frameIndex = 0;
|
||||
bool loop = true;
|
||||
bool pingpong = false;
|
||||
Animation(std::map<std::string, SDL_Rect> frames, Sprite* sprite, int frameDuration);
|
||||
void update();
|
||||
void draw(SDL_Renderer* renderer, bool autoRect = true, bool flip = false);
|
||||
void reset();
|
||||
};
|
||||
|
||||
class AnimationManager
|
||||
{
|
||||
private:
|
||||
std::map<std::string, Animation*> animations;
|
||||
std::map<std::string, bool> flip;
|
||||
std::map<std::string, bool> autoRect;
|
||||
std::string currentAnimation;
|
||||
bool playing = false;
|
||||
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 playAnimation(std::string name);
|
||||
void update();
|
||||
void draw(SDL_Renderer* renderer);
|
||||
};
|
@ -1,17 +0,0 @@
|
||||
#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(TTF_Font* font, SDL_Color color);
|
||||
void draw(SDL_Renderer* renderer, std::string text, int x, int y);
|
||||
};
|
@ -1,58 +0,0 @@
|
||||
// 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 };
|
||||
}
|
||||
};
|
31
makefile
31
makefile
@ -1,20 +1,39 @@
|
||||
# Compiler and linker settings
|
||||
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
|
||||
LDFLAGS = -lSDL3 -lSDL3_image
|
||||
CXXFLAGS = -pedantic -std=c++17 -I include -I /usr/include/SDL3_image -I /usr/include/SDL3
|
||||
|
||||
# Source and object files
|
||||
SRC = $(wildcard src/*.cpp)
|
||||
OBJ = $(addprefix build/, $(notdir $(SRC:.cpp=.o)))
|
||||
|
||||
# Target executable
|
||||
TARGET = build/x86_64/main.x86_64
|
||||
|
||||
all: dirs $(TARGET)
|
||||
# Default target
|
||||
all: clean dirs $(TARGET)
|
||||
|
||||
# development target with debugging
|
||||
dev: CXXFLAGS += -g
|
||||
dev: all
|
||||
|
||||
# Release target
|
||||
release: CXXFLAGS += -O3
|
||||
release: all
|
||||
|
||||
# Create build directory if it doesn't exist
|
||||
dirs:
|
||||
@mkdir -p build/x86_64
|
||||
|
||||
# Build target
|
||||
$(TARGET): $(OBJ)
|
||||
@$(CXX) -o $@ $^ $(LDFLAGS)
|
||||
$(CXX) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
# Build object files
|
||||
build/%.o: src/%.cpp
|
||||
@$(CXX) -c -o $@ $< $(CXXFLAGS)
|
||||
$(CXX) -c -o $@ $< $(CXXFLAGS)
|
||||
|
||||
# Clean up build files
|
||||
clean:
|
||||
@rm -f $(OBJ) $(TARGET)
|
||||
@rm -f $(OBJ) $(TARGET)
|
||||
@echo "Cleaned up build files."
|
4
readme.md
Normal file
4
readme.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Bootleg Game Engine V2
|
||||
|
||||
## Overview
|
||||
This is a lightweight "game engine", designed to be simple and easy to use for small projects. It provides basic functionality for rendering, input handling, and game loop management.
|
93
src/assets.cpp
Normal file
93
src/assets.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#include "assets.hpp"
|
||||
|
||||
AssetManager::AssetManager() {
|
||||
}
|
||||
|
||||
AssetManager::~AssetManager() {
|
||||
clearAssets();
|
||||
}
|
||||
|
||||
void AssetManager::load(const std::string& name, const std::string& filePath) {
|
||||
SDL_Surface* surface = IMG_Load(filePath.c_str());
|
||||
if (!surface) {
|
||||
SDL_Log("Failed to load image %s: %s", filePath.c_str(), SDL_GetError());
|
||||
}
|
||||
assets[name] = surface;
|
||||
}
|
||||
|
||||
SDL_Surface* AssetManager::getAsset(const std::string& name) const {
|
||||
auto it = assets.find(name);
|
||||
if (it != assets.end()) {
|
||||
return it->second;
|
||||
}
|
||||
SDL_Log("Asset %s not found", name.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AssetManager::unloadAsset(const std::string& name) {
|
||||
auto it = assets.find(name);
|
||||
if (it != assets.end()) {
|
||||
SDL_DestroySurface(it->second);
|
||||
assets.erase(it);
|
||||
}
|
||||
SDL_Log("Asset %s not found", name.c_str());
|
||||
}
|
||||
|
||||
void AssetManager::clearAssets() {
|
||||
for (auto& pair : assets) {
|
||||
SDL_DestroySurface(pair.second);
|
||||
}
|
||||
assets.clear();
|
||||
}
|
||||
|
||||
TileMap::TileMap(AssetManager& assetManager)
|
||||
: assetManager(assetManager) {
|
||||
}
|
||||
|
||||
TileMap::~TileMap() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void TileMap::addTile(const std::string& name, const Tile& tile) {
|
||||
tiles[name] = tile;
|
||||
}
|
||||
|
||||
Tile TileMap::getTile(const std::string& name) const {
|
||||
auto it = tiles.find(name);
|
||||
if (it != tiles.end()) {
|
||||
return it->second;
|
||||
}
|
||||
SDL_Log("Tile %s not found", name.c_str());
|
||||
return Tile(); // Return an empty Tile
|
||||
}
|
||||
|
||||
SDL_Surface* TileMap::getTileAsset(const std::string& name) const {
|
||||
auto it = tiles.find(name);
|
||||
if (it != tiles.end()) {
|
||||
return assetManager.getAsset(it->second.assetName);
|
||||
}
|
||||
SDL_Log("Tile %s not found", name.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Rect TileMap::getTileRect(const std::string& name) const {
|
||||
auto it = tiles.find(name);
|
||||
if (it != tiles.end()) {
|
||||
return Rect(it->second.srcRect);
|
||||
}
|
||||
SDL_Log("Tile %s not found", name.c_str());
|
||||
return Rect(); // Return an empty Rect
|
||||
}
|
||||
|
||||
void TileMap::removeTile(const std::string& name) {
|
||||
auto it = tiles.find(name);
|
||||
if (it != tiles.end()) {
|
||||
tiles.erase(it);
|
||||
} else {
|
||||
SDL_Log("Tile %s not found", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void TileMap::clear() {
|
||||
tiles.clear();
|
||||
}
|
180
src/engine.cpp
180
src/engine.cpp
@ -1,78 +1,138 @@
|
||||
#include "engine.h"
|
||||
#include "engine.hpp"
|
||||
|
||||
Engine::Engine(std::string title, int width, int height)
|
||||
{
|
||||
// convert title to char*
|
||||
ctitle = title.c_str();
|
||||
Engine::Engine(const char* windowTitle, int windowWidth, int windowHeight, int windowFlags) {
|
||||
// Initialize SDL
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
SDL_Log("SDL could not initialize! SDL_Error: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize SDL and TFF;
|
||||
TTF_Init();
|
||||
SDL_Init(SDL_INIT_EVERYTHING);
|
||||
// Create the window
|
||||
window = SDL_CreateWindow(windowTitle, windowWidth, windowHeight, windowFlags);
|
||||
if (!window) {
|
||||
SDL_Log("Window could not be created! SDL_Error: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
// Create the renderer
|
||||
renderer = SDL_CreateRenderer(window, nullptr);
|
||||
if (!renderer) {
|
||||
SDL_Log("Renderer could not be created! SDL_Error: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::initSound()
|
||||
{
|
||||
// Initialize sound
|
||||
Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048);
|
||||
soundInitialized = true;
|
||||
Engine::~Engine() {
|
||||
// Destroy the asset manager
|
||||
assets.clearAssets();
|
||||
|
||||
// Destroy the renderer
|
||||
if (renderer) {
|
||||
SDL_DestroyRenderer(renderer);
|
||||
}
|
||||
|
||||
// Destroy the window
|
||||
if (window) {
|
||||
SDL_DestroyWindow(window);
|
||||
}
|
||||
|
||||
// Quit SDL subsystems
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void Engine::clear(SDL_Color color)
|
||||
{
|
||||
// Set color
|
||||
void Engine::clearScreen(const Color& color) {
|
||||
// Set the draw color
|
||||
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
|
||||
|
||||
// Clear screen
|
||||
|
||||
// Clear the screen
|
||||
SDL_RenderClear(renderer);
|
||||
}
|
||||
|
||||
void Engine::startFrame()
|
||||
{
|
||||
// Start frame
|
||||
frameStart = SDL_GetTicks();
|
||||
}
|
||||
|
||||
void Engine::render()
|
||||
{
|
||||
// Render screen
|
||||
void Engine::present() {
|
||||
// Present the renderer
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
if (1000 / targetFrameRate > SDL_GetTicks() - frameStart)
|
||||
{
|
||||
SDL_Delay(1000 / targetFrameRate - (SDL_GetTicks() - frameStart));
|
||||
|
||||
// Calculate frame duration
|
||||
frameEndTime = SDL_GetTicks();
|
||||
frameDuration = frameEndTime - frameStartTime;
|
||||
// Calculate delay to maintain target FPS
|
||||
if (targetFPSValue > 0) {
|
||||
Uint32 targetFrameTime = 1000 / targetFPSValue;
|
||||
if (frameDuration < targetFrameTime) {
|
||||
SDL_Delay(targetFrameTime - frameDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
void Engine::draw(SDL_Surface* surface, Rect destRect) {
|
||||
// Draw a surface to the renderer at the specified destination rectangle
|
||||
if (!surface) {
|
||||
SDL_Log("Cannot draw null surface");
|
||||
return;
|
||||
}
|
||||
|
||||
// Quit SDL and TTF
|
||||
SDL_Quit();
|
||||
TTF_Quit();
|
||||
SDL_FRect sdlDestRect = {
|
||||
static_cast<float>(destRect.x),
|
||||
static_cast<float>(destRect.y),
|
||||
static_cast<float>(destRect.width),
|
||||
static_cast<float>(destRect.height)
|
||||
};
|
||||
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
if (!texture) {
|
||||
SDL_Log("Failed to create texture from surface: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_RenderTexture(renderer, texture, nullptr, &sdlDestRect);
|
||||
SDL_DestroyTexture(texture);
|
||||
}
|
||||
|
||||
void Engine::draw(SDL_Surface* surface, Rect srcRect, Rect destRect) {
|
||||
// Draw a surface to the renderer with specified source and destination rectangles
|
||||
if (!surface) {
|
||||
SDL_Log("Cannot draw null surface");
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_FRect sdlSrcRect = {
|
||||
static_cast<float>(srcRect.x),
|
||||
static_cast<float>(srcRect.y),
|
||||
static_cast<float>(srcRect.width),
|
||||
static_cast<float>(srcRect.height)
|
||||
};
|
||||
SDL_FRect sdlDestRect = {
|
||||
static_cast<float>(destRect.x),
|
||||
static_cast<float>(destRect.y),
|
||||
static_cast<float>(destRect.width),
|
||||
static_cast<float>(destRect.height)
|
||||
};
|
||||
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
if (!texture) {
|
||||
SDL_Log("Failed to create texture from surface: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_RenderTexture(renderer, texture, &sdlSrcRect, &sdlDestRect);
|
||||
SDL_DestroyTexture(texture);
|
||||
}
|
||||
|
||||
void Engine::draw(Tile tile, Rect destRect) {
|
||||
// Draw a tile to the renderer at the specified destination rectangle
|
||||
SDL_Surface* surface = assets.getAsset(tile.assetName);
|
||||
if (!surface) {
|
||||
SDL_Log("Tile asset %s not found", tile.assetName.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
draw(surface, tile.srcRect, destRect);
|
||||
}
|
||||
|
||||
void Engine::startFrame() {
|
||||
// Start the frame timer
|
||||
frameStartTime = SDL_GetTicks();
|
||||
}
|
||||
|
||||
void Engine::targetFPS(int fps) {
|
||||
// Set the target frames per second
|
||||
targetFPSValue = fps;
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
// Includes
|
||||
#include "engine.h"
|
||||
|
||||
// Variables
|
||||
SDL_Surface* assets;
|
||||
Music* music;
|
||||
Engine *engine;
|
||||
|
||||
// Functions
|
||||
// Quit function
|
||||
void quit()
|
||||
{
|
||||
// Free assets
|
||||
SDL_FreeSurface(assets);
|
||||
delete engine;
|
||||
// Exit program
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Main function
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
engine = new Engine("Game", 800, 600);
|
||||
engine->initSound();
|
||||
engine->targetFrameRate = 60;
|
||||
|
||||
// Load assets
|
||||
assets = SDL_LoadBMP("example_assets/sprites.bmp");
|
||||
music = new Music("example_assets/crystal_zone.mp3");
|
||||
|
||||
// frame map
|
||||
std::map<std::string, SDL_Rect> idle = {
|
||||
{ "idle", { 76, 456, 68, 128 } },
|
||||
};
|
||||
|
||||
std::map<std::string, SDL_Rect> front = {
|
||||
{ "front", { 4, 456, 68, 125 } },
|
||||
{ "front2", { 76, 456, 68, 128 } },
|
||||
{ "front3", { 148, 456, 68, 125 } }
|
||||
};
|
||||
|
||||
std::map<std::string, SDL_Rect> back = {
|
||||
{ "back", { 662, 456, 68, 125 } },
|
||||
{ "back2", { 734, 456, 68, 128 } },
|
||||
{ "back3", { 806, 456, 68, 125 } }
|
||||
};
|
||||
|
||||
std::map<std::string, SDL_Rect> walk = {
|
||||
{ "walk", { 220, 456, 68, 124 } },
|
||||
{ "walk2", { 292, 456, 73, 127 } },
|
||||
{ "walk3", { 369, 456, 68, 124 } }
|
||||
};
|
||||
|
||||
std::map<std::string, SDL_Rect> test = {
|
||||
{ "test", { 4, 2095, 68, 59 } },
|
||||
{ "test2", { 76, 2095, 68, 59 } }
|
||||
};
|
||||
|
||||
// Create sprite and animation
|
||||
Sprite* sprite = new Sprite(engine->renderer, assets);
|
||||
AnimationManager* animations = new AnimationManager(sprite);
|
||||
animations->addAnimation("idle", idle, 10, false, true, false, false);
|
||||
animations->addAnimation("walk_left", walk, 10, false, true, true, false);
|
||||
animations->addAnimation("walk_right", walk, 10, true, true, true, false);
|
||||
animations->addAnimation("walk_back", back, 10, false, true, true, false);
|
||||
animations->addAnimation("walk_front", front, 10, false, true, true, true);
|
||||
animations->addAnimation("test", test, 20, false, true, false, false);
|
||||
animations->setAnimation("idle");
|
||||
|
||||
// Play music
|
||||
music->play();
|
||||
|
||||
// Main loop
|
||||
while (true)
|
||||
{
|
||||
// Start time
|
||||
engine->startFrame();
|
||||
|
||||
// Update input
|
||||
engine->update();
|
||||
|
||||
// Exit if window s closed
|
||||
if (engine->input.exit || engine->input.activeKeys[SDLK_ESCAPE])
|
||||
{
|
||||
quit();
|
||||
}
|
||||
|
||||
if (engine->input.activeKeys[SDLK_d] || engine->input.controllers[0].buttons[CBUTTONS::DPAD_RIGHT] || engine->input.controllers[0].leftStickX > 8000)
|
||||
{
|
||||
animations->setAnimation("walk_right");
|
||||
sprite->move({ 1, 0 });
|
||||
}
|
||||
if (engine->input.activeKeys[SDLK_a] || engine->input.controllers[0].buttons[CBUTTONS::DPAD_LEFT] || engine->input.controllers[0].leftStickX < -8000)
|
||||
|
||||
{
|
||||
animations->setAnimation("walk_left");
|
||||
sprite->move({ -1, 0 });
|
||||
}
|
||||
if (engine->input.activeKeys[SDLK_w] || engine->input.controllers[0].buttons[CBUTTONS::DPAD_UP] || engine->input.controllers[0].leftStickY < -8000)
|
||||
{
|
||||
animations->setAnimation("walk_back");
|
||||
sprite->move({ 0, -1 });
|
||||
}
|
||||
if (engine->input.activeKeys[SDLK_s] || engine->input.controllers[0].buttons[CBUTTONS::DPAD_DOWN] || engine->input.controllers[0].leftStickY > 8000)
|
||||
{
|
||||
animations->setAnimation("walk_front");
|
||||
sprite->move({ 0, 1 });
|
||||
}
|
||||
if (engine->input.activeKeys[SDLK_SPACE] || engine->input.controllers[0].buttons[CBUTTONS::A])
|
||||
{
|
||||
animations->playAnimation("test");
|
||||
}
|
||||
if (!engine->input.keysPressed({ SDLK_w, SDLK_a, SDLK_s, SDLK_d }) && engine->input.controllers[0].leftStickX < 8000 && engine->input.controllers[0].leftStickX > -8000 &&
|
||||
engine->input.controllers[0].leftStickY < 8000 && engine->input.controllers[0].leftStickY > -8000 &&
|
||||
!engine->input.controllerPressed({ CBUTTONS::DPAD_UP, CBUTTONS::DPAD_DOWN, CBUTTONS::DPAD_LEFT, CBUTTONS::DPAD_RIGHT }))
|
||||
{
|
||||
animations->setAnimation("idle");
|
||||
}
|
||||
|
||||
// Update animation
|
||||
animations->update();
|
||||
|
||||
// Clear screen
|
||||
engine->clear({ 100, 150, 255, 255 });
|
||||
|
||||
// Draw sprite
|
||||
animations->draw(engine->renderer);
|
||||
|
||||
// Update screen
|
||||
engine->render();
|
||||
}
|
||||
return 0;
|
||||
}
|
158
src/input.cpp
158
src/input.cpp
@ -1,78 +1,112 @@
|
||||
#include "input.h"
|
||||
#include "input.hpp"
|
||||
|
||||
Input::Input() {
|
||||
|
||||
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;
|
||||
Input::~Input() {
|
||||
|
||||
}
|
||||
|
||||
void Input::handleEvents() {
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_EVENT_QUIT:
|
||||
quitRequestedFlag = true;
|
||||
break;
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
if (keyStates[event.key.scancode] == false) {
|
||||
keyFallingEdgeStates[event.key.scancode] = true;
|
||||
}
|
||||
keyStates[event.key.scancode] = true;
|
||||
break;
|
||||
case SDL_EVENT_KEY_UP:
|
||||
keyStates[event.key.scancode] = false;
|
||||
keyFallingEdgeStates[event.key.scancode] = false;
|
||||
break;
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
if (mouseButtonStates[event.button.button] == false) {
|
||||
mouseButtonFallingEdgeStates[event.button.button] = true;
|
||||
}
|
||||
mouseButtonStates[event.button.button] = true;
|
||||
break;
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
mouseButtonStates[event.button.button] = false;
|
||||
mouseButtonFallingEdgeStates[event.button.button] = false;
|
||||
break;
|
||||
case SDL_EVENT_MOUSE_MOTION:
|
||||
mousePosition.x = static_cast<int>(event.motion.x);
|
||||
mousePosition.y = static_cast<int>(event.motion.y);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
bool Input::keysPressed(std::vector<SDL_Keycode> keys)
|
||||
{
|
||||
for (auto key : keys)
|
||||
{
|
||||
if (activeKeys[key])
|
||||
{
|
||||
bool Input::quitRequested() const {
|
||||
return quitRequestedFlag;
|
||||
}
|
||||
|
||||
bool Input::isKeyPressed(SDL_Scancode key) {
|
||||
auto it = keyStates.find(key);
|
||||
return it != keyStates.end() && it->second;
|
||||
}
|
||||
|
||||
bool Input::isKeyPressed(std::vector<SDL_Scancode> keys) {
|
||||
for (const auto& key : keys) {
|
||||
if (isKeyPressed(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Input::controllerPressed(std::vector<Uint8> buttons, int controller)
|
||||
{
|
||||
for (auto button : buttons)
|
||||
{
|
||||
if (controllers[controller].buttons[button])
|
||||
{
|
||||
bool Input::isMouseButtonPressed(Uint8 button) {
|
||||
auto it = mouseButtonStates.find(button);
|
||||
return it != mouseButtonStates.end() && it->second;
|
||||
}
|
||||
|
||||
bool Input::isMouseButtonPressed(std::vector<Uint8> buttons) {
|
||||
for (const auto& button : buttons) {
|
||||
if (isMouseButtonPressed(button)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector2 Input::getMousePosition() const {
|
||||
return mousePosition;
|
||||
}
|
||||
|
||||
bool Input::hasKeyBeenPressed(SDL_Scancode key) {
|
||||
auto it = keyFallingEdgeStates.find(key);
|
||||
if (it != keyFallingEdgeStates.end() && it->second) {
|
||||
keyFallingEdgeStates[key] = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Input::hasKeyBeenPressed(std::vector<SDL_Scancode> keys) {
|
||||
for (const auto& key : keys) {
|
||||
if (hasKeyBeenPressed(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Input::hasMouseButtonBeenPressed(Uint8 button) {
|
||||
auto it = mouseButtonFallingEdgeStates.find(button);
|
||||
if (it != mouseButtonFallingEdgeStates.end() && it->second) {
|
||||
mouseButtonFallingEdgeStates[button] = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool Input::hasMouseButtonBeenPressed(std::vector<Uint8> buttons) {
|
||||
for (const auto& button : buttons) {
|
||||
if (hasMouseButtonBeenPressed(button)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
57
src/main.cpp
Normal file
57
src/main.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include "engine.hpp"
|
||||
|
||||
// Main function
|
||||
int main(int argc, char* argv[]) {
|
||||
// Create the engine with a window title and dimensions
|
||||
Engine engine("SDL3 Game Engine", 800, 600);
|
||||
TileMap tileMap(engine.assets);
|
||||
|
||||
// Load bird asset
|
||||
engine.assets.load("bird", "assets/bird.png");
|
||||
tileMap.addTile("bird0", Tile{{0, 0, 34, 24}, "bird"});
|
||||
tileMap.addTile("bird1", Tile{{34, 0, 34, 24}, "bird"});
|
||||
tileMap.addTile("bird2", Tile{{68, 0, 34, 24}, "bird"});
|
||||
|
||||
int currentBirdIndex = 0;
|
||||
|
||||
// bird position
|
||||
Vector2 birdPosition(0, 0);
|
||||
|
||||
while (!engine.input.quitRequested()) {
|
||||
// Start a new frame
|
||||
engine.startFrame();
|
||||
|
||||
// Handle input events
|
||||
engine.input.handleEvents();
|
||||
|
||||
// check for movement keys
|
||||
if (engine.input.isKeyPressed(SDL_SCANCODE_D)) {
|
||||
birdPosition.x += 1; // Move right
|
||||
}
|
||||
if (engine.input.isKeyPressed(SDL_SCANCODE_A)) {
|
||||
birdPosition.x -= 1; // Move left
|
||||
}
|
||||
if (engine.input.isKeyPressed(SDL_SCANCODE_W)) {
|
||||
birdPosition.y -= 1; // Move up
|
||||
}
|
||||
if (engine.input.isKeyPressed(SDL_SCANCODE_S)) {
|
||||
birdPosition.y += 1; // Move down
|
||||
}
|
||||
|
||||
// Change bird sprite on space key press
|
||||
if (engine.input.hasKeyBeenPressed(SDL_SCANCODE_SPACE)) {
|
||||
currentBirdIndex = (currentBirdIndex + 1) % 3; // Cycle through bird sprites
|
||||
}
|
||||
|
||||
// Clear the screen with a color
|
||||
engine.clearScreen({0, 0, 0}); // Black color
|
||||
|
||||
// Draw the bird asset at a specific position
|
||||
engine.draw(tileMap.getTile("bird" + std::to_string(currentBirdIndex)), birdPosition);
|
||||
|
||||
// Present the rendered frame
|
||||
engine.present();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
#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);
|
||||
}
|
170
src/sprite.cpp
170
src/sprite.cpp
@ -1,170 +0,0 @@
|
||||
#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, bool 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 ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE);
|
||||
}
|
||||
|
||||
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::reset()
|
||||
{
|
||||
frameIndex = 0;
|
||||
frameDirection = 1;
|
||||
currentFrameName = frames[0];
|
||||
end = false;
|
||||
}
|
||||
|
||||
void Animation::update()
|
||||
{
|
||||
frameCounter++;
|
||||
end = false;
|
||||
if (frameCounter >= frameDuration)
|
||||
{
|
||||
frameCounter = 0;
|
||||
if (pingpong)
|
||||
{
|
||||
frameIndex += frameDirection;
|
||||
if (frameIndex >= frames.size() - 1 || frameIndex <= 0)
|
||||
{
|
||||
if (!loop)
|
||||
{
|
||||
frameDirection = 0;
|
||||
end = true;
|
||||
} else {
|
||||
frameDirection *= -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
frameIndex++;
|
||||
if (frameIndex >= frames.size())
|
||||
{
|
||||
if (!loop)
|
||||
{
|
||||
frameIndex = frames.size() - 1;
|
||||
end = true;
|
||||
} else {
|
||||
frameIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
currentFrameName = frames[frameIndex];
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::draw(SDL_Renderer* renderer, bool autoRect, bool flip)
|
||||
{
|
||||
sprite->draw(renderer, currentFrameName, autoRect, flip);
|
||||
}
|
||||
|
||||
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 AnimationManager::setAnimation(std::string name)
|
||||
{
|
||||
if (!playing) {
|
||||
currentAnimation = name;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationManager::update()
|
||||
{
|
||||
animations[currentAnimation]->update();
|
||||
if (playing && animations[currentAnimation]->end)
|
||||
{
|
||||
playing = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationManager::draw(SDL_Renderer* renderer)
|
||||
{
|
||||
animations[currentAnimation]->draw(renderer, autoRect[currentAnimation], flip[currentAnimation]);
|
||||
}
|
||||
|
||||
void AnimationManager::playAnimation(std::string name)
|
||||
{
|
||||
if (!playing) {
|
||||
animations[name]->loop = false;
|
||||
animations[name]->reset();
|
||||
setAnimation(name);
|
||||
playing = true;
|
||||
}
|
||||
}
|
17
src/text.cpp
17
src/text.cpp
@ -1,17 +0,0 @@
|
||||
#include "text.h"
|
||||
|
||||
Text::Text(TTF_Font* font, SDL_Color color)
|
||||
{
|
||||
this->font = font;
|
||||
this->color = color;
|
||||
}
|
||||
|
||||
void Text::draw(SDL_Renderer* renderer, std::string text, int x, int y)
|
||||
{
|
||||
surface = TTF_RenderText_Solid(font, text.c_str(), color);
|
||||
texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
rect = { x, y, surface->w, surface->h };
|
||||
SDL_RenderCopy(renderer, texture, NULL, &rect);
|
||||
SDL_FreeSurface(surface);
|
||||
SDL_DestroyTexture(texture);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user