Compare commits
No commits in common. "main" and "v1" have entirely different histories.
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
.vscode
|
||||
build
|
||||
build
|
||||
main.x86_64
|
9
LICENSE
Normal file
9
LICENSE
Normal file
@ -0,0 +1,9 @@
|
||||
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
Normal file
13
README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# 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
BIN
assets/bird.png
Binary file not shown.
Before Width: | Height: | Size: 497 B |
BIN
example_assets/C64.ttf
Normal file
BIN
example_assets/C64.ttf
Normal file
Binary file not shown.
BIN
example_assets/crystal_zone.mp3
Normal file
BIN
example_assets/crystal_zone.mp3
Normal file
Binary file not shown.
BIN
example_assets/sprites.bmp
Normal file
BIN
example_assets/sprites.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 MiB |
@ -1,59 +0,0 @@
|
||||
#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
|
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();
|
||||
};
|
@ -1,50 +0,0 @@
|
||||
#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
|
61
include/input.h
Normal file
61
include/input.h
Normal file
@ -0,0 +1,61 @@
|
||||
#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);
|
||||
};
|
@ -1,45 +0,0 @@
|
||||
#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
|
||||
|
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();
|
||||
};
|
68
include/sprite.h
Normal file
68
include/sprite.h
Normal file
@ -0,0 +1,68 @@
|
||||
#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);
|
||||
};
|
17
include/text.h
Normal file
17
include/text.h
Normal file
@ -0,0 +1,17 @@
|
||||
#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);
|
||||
};
|
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 };
|
||||
}
|
||||
};
|
31
makefile
31
makefile
@ -1,39 +1,20 @@
|
||||
# Compiler and linker settings
|
||||
CXX = g++
|
||||
LDFLAGS = -lSDL3 -lSDL3_image
|
||||
CXXFLAGS = -pedantic -std=c++17 -I include -I /usr/include/SDL3_image -I /usr/include/SDL3
|
||||
|
||||
# Source and object files
|
||||
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 executable
|
||||
TARGET = build/x86_64/main.x86_64
|
||||
|
||||
# Default target
|
||||
all: clean dirs $(TARGET)
|
||||
all: 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)
|
||||
@echo "Cleaned up build files."
|
||||
@rm -f $(OBJ) $(TARGET)
|
@ -1,4 +0,0 @@
|
||||
# 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.
|
@ -1,93 +0,0 @@
|
||||
#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();
|
||||
}
|
176
src/engine.cpp
176
src/engine.cpp
@ -1,138 +1,78 @@
|
||||
#include "engine.hpp"
|
||||
#include "engine.h"
|
||||
|
||||
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;
|
||||
}
|
||||
Engine::Engine(std::string title, int width, int height)
|
||||
{
|
||||
// convert title to char*
|
||||
ctitle = title.c_str();
|
||||
|
||||
// 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;
|
||||
}
|
||||
// Initialize SDL and TFF;
|
||||
TTF_Init();
|
||||
SDL_Init(SDL_INIT_EVERYTHING);
|
||||
|
||||
// Create the renderer
|
||||
renderer = SDL_CreateRenderer(window, nullptr);
|
||||
if (!renderer) {
|
||||
SDL_Log("Renderer 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);
|
||||
}
|
||||
|
||||
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::initSound()
|
||||
{
|
||||
// Initialize sound
|
||||
Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048);
|
||||
soundInitialized = true;
|
||||
}
|
||||
|
||||
void Engine::clearScreen(const Color& color) {
|
||||
// Set the draw color
|
||||
void Engine::clear(SDL_Color color)
|
||||
{
|
||||
// Set color
|
||||
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
|
||||
|
||||
// Clear the screen
|
||||
|
||||
// Clear screen
|
||||
SDL_RenderClear(renderer);
|
||||
}
|
||||
|
||||
void Engine::present() {
|
||||
// Present the renderer
|
||||
void Engine::startFrame()
|
||||
{
|
||||
// Start frame
|
||||
frameStart = SDL_GetTicks();
|
||||
}
|
||||
|
||||
void Engine::render()
|
||||
{
|
||||
// Render screen
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
if (1000 / targetFrameRate > SDL_GetTicks() - frameStart)
|
||||
{
|
||||
SDL_Delay(1000 / targetFrameRate - (SDL_GetTicks() - frameStart));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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::update()
|
||||
{
|
||||
// Update input
|
||||
input.update();
|
||||
}
|
||||
|
||||
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;
|
||||
Engine::~Engine()
|
||||
{
|
||||
// Free renderer and window
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
|
||||
// If sound is initialized, quit Mix
|
||||
if (soundInitialized)
|
||||
{
|
||||
Mix_Quit();
|
||||
}
|
||||
|
||||
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);
|
||||
// Quit SDL and TTF
|
||||
SDL_Quit();
|
||||
TTF_Quit();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
133
src/example-game.cpp
Normal file
133
src/example-game.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
// 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,112 +1,78 @@
|
||||
#include "input.hpp"
|
||||
|
||||
Input::Input() {
|
||||
#include "input.h"
|
||||
|
||||
Input::Input()
|
||||
{
|
||||
SDL_Init(SDL_INIT_JOYSTICK);
|
||||
exit = false;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
bool Input::keysPressed(std::vector<SDL_Keycode> keys)
|
||||
{
|
||||
for (auto key : keys)
|
||||
{
|
||||
if (activeKeys[key])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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)) {
|
||||
bool Input::controllerPressed(std::vector<Uint8> buttons, int controller)
|
||||
{
|
||||
for (auto button : buttons)
|
||||
{
|
||||
if (controllers[controller].buttons[button])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
57
src/main.cpp
57
src/main.cpp
@ -1,57 +0,0 @@
|
||||
#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;
|
||||
}
|
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);
|
||||
}
|
170
src/sprite.cpp
Normal file
170
src/sprite.cpp
Normal file
@ -0,0 +1,170 @@
|
||||
#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
Normal file
17
src/text.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#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