Primitive Engine

Primitive Engine is a project I started to improve my C++ skills.

I decided to use SDL2 instead of a normal game engine. My main focus with this project is C++, but, I also thought it would be fun to try working with something I hadn't before. SDL2 is used for window management and rendering. For math I use GLM.

This project is a work in progress, and I have more features planned. So far, I've mainly focused on creating a foundation for the project, adding features like collision and player movement.

                        
#pragma once

#include "iostream"
#include "SDL_image.h"
#include "SDL.h"
#include "vector"

#define NOMINMAX
#include "windows.h"

static constexpr int max_Actors = 50;

// Forward declarations
class Actor;
enum class ECollision_Type;
class Camera;
class WorldGenerator;

class Game {

public:

	Game(const Game&) = delete;
	Game& operator=(const Game&) = delete;

	static Game& Instance()
	{
		static Game instance;
		return instance;
	}


	void Init(const char* title, int xPos, int yPos, int width, int height, bool fullscreen);

	void HandleEvents();

	void Update();

	void Render();


	void Clean();

	bool Running() { return isRunning; }

	void SetRenderColor();
	void FillRenderRect(int x, int y, int width, int height);
	void RenderRect(int x, int y, int width, int height);

	Actor* GetCollidingActor(Actor* other, ECollision_Type collisionType);
	std::vector<Actor*> GetAllCollidingActors(Actor* other, ECollision_Type collisionType);

	SDL_Renderer* GetRenderer();

	// getter functions
	Actor* GetPlayer();
	Camera* GetCamera();
	WorldGenerator* GetWorldGenerator();

private:

	Game();
	~Game();

	SDL_Window* window;
	SDL_Renderer* renderer;

	bool isRunning;

	static constexpr float BACKGROUND_GRID_SIZE = 50.f;

	Actor* actors[max_Actors] = { nullptr };


	WorldGenerator* worldGenerator = nullptr;


	Actor* player = nullptr;

	Camera* camera = nullptr;

};


// game time
float Get_DeltaTime();

float Get_CurrentTime();

float Get_TimePassedSince(float time);

int GetFrameCount();


                        
                    

INPUT MANAGER

The InputManager handles keyboard and mouse input using SDL events.
Tracks the different key and mouse button states:

- Pressed
- Held
- Released

It also tracks the mouse position.
All inputs are frame-accurate, ensuring accurate and responsive input handling.

                        
#pragma once

#include "SDL.h"
#include "SDL_image.h"
#include "string"
#include "unordered_map"

class TextureManager
{
public:

	TextureManager(const TextureManager&) = delete;
	TextureManager& operator=(const TextureManager&) = delete;

	static TextureManager& Instance()
	{
		static TextureManager instance;
		return instance;
	}

	//SDL_Texture* LoadTexture(const char* textureName, SDL_Renderer* renderer);

	bool Load(const std::string& id, const std::string fileName, SDL_Renderer* renderer);
	void Render(const std::string& id, int x, int y, int width, int height, SDL_Renderer* renderer);
	void Clean();

private:

	TextureManager() { }

	std::unordered_map<std::string, SDL_Texture*> textureMap;
};

                        
                    

COLLISION

The AABB (Axis-Aligned Bounding Box) struct represent a 2D rectangle used for collision detection.
FromPositionSize() converts a given position and size into an AABB by calculating the min and max corners.
aabbOverlap() compare two AABB and return whether they are overlapping or not.

                        
#pragma once

#include "glm.hpp"

class Camera
{
public:
	void Update();

	glm::vec2 WorldToScreen(glm::vec2 vector);
	glm::vec2 ScreenToWorld(glm::vec2 vector);

	glm::vec2 position;
	
};

                        
                    

PLAYER CLASS

The Player class inherits from the Actor class. It handles:

Player Movement - Horizontal movement, jumping, and gravity.
Resolving Collision - Player position is adjusted based on the smallest overlap.
Interact - Use mouse inputs to place or break blocks.

                        
#pragma once

#include "Actor.h"

class Block : public Actor
{
public:

	Block(glm::vec2 position);

	void Update() override;
	void Render() override;

	void Hit(int damage) override;

};