OpenGL C++ game engine for educational purposes
I'll use this repository to control and share my progress on my understanding of opengl. I'll test my knowledge by building a engine which will only serve as educational purposes.
I still have to look into that. The project currently uses Visual Studio 2015 and opengl 4.3
Easily create a window with the specified title, width and height with a singleton.
app(GLuint _width, GLuint _height);
Takes as parameters the window width and the window height
-
open method
void open(int GL_major, int GL_minor, const char * name);
The first two parameters specify the major and minor versions of opengl, the third parameter is the new window's name
Usage example:
cge::app app(1250, 900); app.open(4, 3, "opengl engine");
-
shouldClose method
int shouldClose();
returns
1
if the current application should close. note: There is another method wrappingshouldClose()
that should always be used, that isstartLoop()
Usage example:
cge::app app(1250, 900); app.open(4, 3, "opengl engine"); while (!app.shouldClose()) { // do something... }
-
startLoop method
int startLoop();
prepare the application for the next rendering call. Returns
1
if the current application should close. note: this method return the result from theshouldClose()
methodUsage example:
cge::app app(1250, 900); app.open(4, 3, "opengl engine"); while (!app.startLoop()) { // do something... }
-
endLoop method
void endLoop();
Swaps the opengl buffer. Internally check if the escape key was pressed to close the application
Usage example:
cge::app app(1250, 900); app.open(4, 3, "opengl engine"); while (!app.startLoop()) { app.endLoop(); }
-
keys property
bool keys[1024];
can be used to check if a key was pressed between the last loop iteration and the new one. the event key poll is made at the beginning of the loop in the
startLoop()
method.while (!app.startLoop()) { if (app.keys[GLFW_KEY_W] == true) { std::cout << "W key was pressed\n"; } app.endLoop(); }
A virtual 2D camera system
Camera(GLuint width, GLuint height);
takes as parameters the viewport' width and height.
-
updateView method
void updateView();
Usage example:
cge::app app(1250, 900); app.open(4, 3, "opengl engine"); cge::Camera camera(app.width, app.height); while (!app.startLoop()) { camera.updateView(); app.endLoop(); }
-
runFollow method
void runFollow();
make the camera follow the followed vector position stored.
Usage example:
cge::app app(1250, 900); app.open(4, 3, "opengl engine"); cge::Camera camera(app.width, app.height); while (!app.startLoop()) { camera.updateView(); camera.runFollow(); app.endLoop(); }
-
followedPosition property
glm::vec2 * followedPosition;
Vector pointer to the vector position you want the camera to follow when running the
runFollow()
method. -
anchor property
glm::vec2 anchor;
It is a 2D vector defining the anchor point for the camera's followed position. With the vector
[x, y]
when set to[0.5, 0.5]
the anchor point is set to the center of the viewport.- X defines the horizontal position from left to right between 0 and 1.
- Y defines the vertical position from top to bottom between 0 and 1.
-
followSpeed property
GLfloat followSpeed;
this value should be set between 0 and 1. And defines the number of steps required for the camera to get to the followedPosition
Efficient 2D rendering with the spritebatch class
SpriteBatch();
usage Example:
cge::SpriteBatch batch;
-
begin method
void begin();
Set up everything to begin the spritebatch collecting
-
end method
void end();
Set up everything for the batch.render() method
-
render method
void render();
uses all the data collected between the
begin
andend
methods to render to the screen the glyphesUsage example:
cge::app app(1250, 900); app.open(4, 3, "opengl engine"); cge::Camera camera(app.width, app.height); cge::SpriteBatch batch; while (!app.startLoop()) { batch.begin(); // rendering calls batch.end(); batch.rener(); app.endLoop(); }
Load 2D textures with ResourceManager
Texture2D();
usage Example:
cge::Texture2D texture_circle = cge::ResourceManager::LoadTexture("assets/circle.png", GL_TRUE, "circle");
No methods that should be manually called
You can use the cge::hitbox
class to instanciate the hitbox of a 2D sprite.
Hitbox(glm::vec2 customSize, glm::vec2 customPosition);
-
intersects method
bool Hitbox::intersects(Hitbox * obj, glm::vec2 & obj1_position, glm::vec2 obj2_position)
return
true
if this hitbox and the supplied hitbox intersects. As an hitbox can be linked to many elements in a 1 hitbox to many elements relation. The object 1's hitbox and the object 2's hitbox must be passed in the parameters. The object 1 is the one linked to this hitbox, the object 2 is the one linked to the supplied hitbox pointer. note: this method should not be called manually, it is called internally by theSprite
class in theSprite::intersects
method. -
resolve method
void Hitbox::resolve(Hitbox * obj, glm::vec2 & obj1_position, glm::vec2 obj2_position)
Move the two objects so that they don't intersect anymore. note: this mothoud should not be called manually, it is called internally by the
Sprite
class in theSprite::intersects
method.
A singleton that provides many helper methods such as FPS count, delta between frames...
helper();
-
getDelta method
GLfloat getDelta();
return the value of the delta-time between the current frame and the last one. Useful to get framerate independant velocity, camera movement and all.
Usage example:
cge::app app(1250, 900); app.open(4, 3, "opengl engine"); cge::helper helper; GLfloat delta = helper.getDelta(); while (!app.startLoop()) { delta = helper.getDelta(); app.endLoop(); }
-
coutFramerate() method
void coutFramerate();
std::cout the framerate
Usage example:
cge::app app(1250, 900); app.open(4, 3, "opengl engine"); cge::helper helper; GLfloat delta = helper.getDelta(); while (!app.startLoop()) { delta = helper.getDelta(); helper.coutFramerate(); app.endLoop(); }
Allows the rendering of 2D fixed textures.
Sprite();
Sprite(glm::vec2 pos, glm::vec2 size, cge::Texture2D * _texture);
-
drawBatch method
virtual void drawBatch(cge::SpriteBatch & spriteBatch);
Usage example
cge::app app(1250, 900); app.open(4, 3, "opengl engine"); cge::Camera camera(app.width, app.height); cge::SpriteBatch batch; cge::Texture2D texture_tile = cge::ResourceManager::LoadTexture("assets/tile.png", GL_TRUE, "tile"); cge::Hitbox tileBox(glm::vec2(100.0f, 100.0f), glm::vec2(0.0f, 0.0f)); cge::Sprite obstacle(glm::vec2(525.0f, 525.0f), glm::vec2(100.0f, 100.0f), &texture_tile); obstacle.addBox(&tileBox); while (!app.startLoop()) { batch.begin(); obstacle.drawBatch(batch); batch.end(); batch.rener(); app.endLoop(); }
-
addBox method
void addBox(Hitbox * _box);
set the hitbox
Usage example:
cge::Texture2D texture_tile = cge::ResourceManager::LoadTexture("assets/tile.png", GL_TRUE, "tile"); cge::Hitbox tileBox(glm::vec2(100.0f, 100.0f), glm::vec2(0.0f, 0.0f)); cge::Sprite obstacle(glm::vec2(525.0f, 525.0f), glm::vec2(100.0f, 100.0f), &texture_tile); obstacle.addBox(&tileBox);
-
applyAcceleration method
void applyAcceleration(const GLfloat delta);
Add the value of this->acceleration to
this->velocity
, then resets the acceleration value. It should be called beforethis->applyVelocity()
. -
applyVelocity method
void applyVelocity(const GLfloat delta);
Add the value of
this->velocity
tothis->position
. It should be called just beforethis->drawBatch()
-
applyFriction method
void applyFriction(const GLfloat factor);
multiply the velocity by the factor
Spritesheets support with the cge::SpriteSheet
class and the cge::AnimationsUV
class
The AnimationsUv
class serves as a storage for animations based on UV coordinates in a spritesheet. You can declare in the spritesheet multiple animations with custom names, custom lengths and durations.
AnimationsUV(int _rows, int _columns);
-
setAnimation method
AnimationsUV & setAnimation(std::string & name, int _beginX, int _beginY, int _endX, int _endY, float _timePerCell)
add an animation to the registry
Usage example:
cge::AnimationsUV(3, 9).setAnimation(std::string("default"), 0, 0, 6, 0, 1000)
-
setCurrentAnimation method
bool setCurrentAnimation(std::string & name);
this method tries to change to a new animation only if a stored animation exists with the same name as the supplied string.
-
time method
void time(float delta);
Adds a tick to the counter, automatically changes the current cell if
currentTick >= ticksPerCell
SpriteAnimation(glm::vec2 pos, glm::vec2 _size, cge::Texture2D * _texture, AnimationsUV _animationsUV);
-
drawBatch method
virtual void drawBatch(cge::SpriteBatch & spriteBatch);
-
time method
void time(float delta);
Offers easy text rendering with 2 classes
cge::TextManager
cge::Text
Text rendering should be done by first defining a TextManager
instance by passing to the init function the windows width and the windows height.
TextManager();
-
init method
bool init(GLuint width, GLuint height);
Usage example:
cge::app app(1250, 900); app.open(4, 3, "opengl app"); cge::TextManager textManager; textManager.init(app.width, app.height);
-
newText method
Text newText(char* text, GLfloat x = 0, GLfloat y = 0, GLfloat scale = 1, glm::vec3 color = glm::vec3(1, 1, 1));
Usage example:
cge::app app(1250, 900); app.open(4, 3, "opengl app"); cge::TextManager textManager; textManager.init(app.width, app.height); cge::Text textObject = textManager.newText("Hello world", 150, 150);
Text(char* text, TextManager * manager, GLfloat x = 0, GLfloat y = 0, GLfloat scale = 1, glm::vec3 color = glm::vec3(1, 1, 1));
-
setString method
void setString(char * text);
Usage example:
cge::Text textObject = textManager.newText("Hello world", 150, 150); textObject.setString("Custom message");
-
render method
void render();
Usage example:
cge::Text textObject = textManager.newText("Hello world", 150, 150); textObject.render();