- Download Demo: https://drive.google.com/file/d/1uVFAW6RbYmwjxG1NOEa0GxsbpG5UAtMT/view?usp=sharing
- Video Demo: https://youtu.be/Qe25e_3YVuw
I already done this game demo (here) using Unity, so this is a port to SDL C++.
BunTheBunny is a platformer 2D game.
This might tight up with the engine physics system
- Move around by arrow keys.
- Have distinct movement acceleration and decceleration based on current player movement and state.
- Acceleration and Decceleration here means how fast the player can reach the desired speed.
- Fully customizable.
- Jump using
C
button. - Jumping having quite a bit of helper:
- Coyote time: Allow player to jump even after left the ground for a bit of time.
- Jump buffer: Allow player to jump when touch the ground even player input the jump a bit sooner than expected.
- Purpose: For better controlling player.
- Player can store the velocity.
- store velocity might be use in difference way.
- Run.
- Take the power up.
- Use obstacles.
- Dash by
X
. - Player will dash in the direction of arrow keys.
- Dash will use store velocity, which mean more store velocity the faster player dash.
- Wall jump by
C
when near the Wall. - Wall jump also use store velocity as additional velocity to the jump.
- For better feeling on dashing, the first few ticks of the dash, player actually move many times store velocity fast.
- Because of the above, player can cancel the dash by jump or wall jump and take advantage of the fast velocity in start of the dash and perform a super far jump, this might call jump dash cancel. (The easiest way to excute this is by move in a flat surface and press
X
->C
)
- Simply kill (reset level) when player touched.
- Transfer all player velocity to upward velocity and a bit more addition.
- Add a bit velocity to player store velocity.
- Transfer all player velocity to horizontal velocity and a bit more addition.
- Add a bit velocity to player store velocity.
- Temporary increase player movement speed.
- Final score of a level calculated by:
- Time to complete.
- Final speed.
- Max speed.
- All code by me.
- Art original design by WibuKa, remade for this project by me.
- All sound, music by me.
more clear, WibuKa and I work on the ([game](https://krakra.itch.io/bunthebunny)) for a GameJam, the art asset made by WibuKa on that project and in this project, i modified it a bit and the music once was made by other but I made the music for this project.
A simple 2D AABB based GameEngine using SDL C++ run in WIndows.
- Disclaimer
- Getting Started
- Features
- Basics
- Entry point
- Mechanic
- Utilities
- Object*
- Component
- Game
- Input
- Time
- Camera
- Event
- Renderer
- Physics
- Other
- Things I could do better
The engine still not yet finished, it lack a lot of feature
I will definitely re-do a new one
but like for real, i'm really suprised if you can use this abomination
#include "miaangine.hpp"
to use all the features or import specify any file depending on your needs.
All engine components are in the mia
namespace.
- Custom SDL window.
- Object-based engine.
- Camera system - World position.
- Input system.
- Events system.
- AABB-based physics.
- Audio support.
The engine mostly use function to access object.
The engine contains some basic tools:
- Game: Handle some basic SDL stuff and contain some generic function for the engine.
- Input: Handle the inputs.
- Time: Handle time of the engine.
- Events: Handle events callback system.
- Camera: World Camera.
- Renderer: Manage the engine's rendering.
- Physics: Manage the engine's physics.
- SpriteHandler: Help make *Sprite.
You can use all the tools by mia::_<name-of-tool>()
.
- Screen: is the plane of the program screen, the real plane where things are rendered out.
- World: a plane/layout which is separated from Screen, related with Screen through Camera
Make sure to import the necessary header
Go to the common.hpp
file and change the const variables for your usage.
this is so bad but I don't want to redo it anymore
mia::_Game().InitWindow()
to make the SDL program.
mia::_Game().ClearWindow()
to clear the SDL program.
Make a simple while(true)
loop and use mia::_Game().Update()
to tell the engine update.
Use mia::_Game().Render()"
to render.
Use if (mia::_Input().isQuit()) break;
break out of the loop if user quit the window.
Together, you might have something like this as a entry point:
mia::_Game().InitWindow();
while (true)
{
mia::_Game().Update();
// Game logic here
if (mia::_Input().isQuit()) break;
mia::_Game().Render();
}
mia::_Game().ClearWindow();
Observer design pattern.
Arbitrary AABB Collision.
The engine mostly use function to access object attributes.
The engine contain some utilities.
Vector have 3 variant are v2f
; v2i
; v2d
which contain difference type of "x, y". v2f
for "float"; v2i
for "int"; v2d
for "double".
Besides basic operator, it also have magnitude()
, normalize()
.
Just a lighter, simpler version of std::string
.
A 32-bit bitmask
insert(int pos)
: Insert bit to "pos".remove(int pos)
: Remove bit in "pos".query(int pos)
: Check if a bit in "pos".count()
: Return number of bit in mask.get()
: Return the mask as int.
A rectangle data.
v2f pos
: positionv2f siz
: sizerect(v2f pos, v2f siz)
: Init a rect with pos and siz.bool contain(v2f point)
: Check if contain a point.bool contain(rect other)
: Check if contain a rect.bool overlap(rect other)
: Check if overlap other rect.
Inheritance this class to make the class become singleton
class <target-class> : public Singleton<<target-class>>
Remember to private the constructor and add friend class to Singleton.
private:
friend class Singleton<<target-class>>
The main working ...object existing on World.
- string name.
- v2f position.
- Portrait *portrait: Portrait component.
- Body *body: Body component
The main object existing on Screen.
- string name.
- v2f position.
- Image *image: Image component
The observer of the event system.
void Update(int message)
: This will be called if the event it registered call, "message" corresponding the event.
it work
An Object's component, is the way to render object.
- Sprite *sprite.
- v2f pivot.
- v2f offset.
- SDL_Color color.
Portrait(Object *master, ...)
: Constructor a Portait attach to "master".Object ChangeMaster(Object *other)
: Set new master.rect GetRect()
: Get the rect of Portrait.
An Object's component, is the way to render object.
- BodyType type: have 2 type _BODY_STATIC and _BODY_DYNAMIC.
- v2f size.
- v2f pivot.
- v2f offset.
- v2f velocity.
Body(Object *master, ...)
: Constructor a Portait attach to "master".Object ChangeMaster(Object *other)
: Set new master.rect GetRect()
: Get the rect of Body.AddForce(v2f value)
: Add force.AddAcceleration(v2f value)
: Add acceleration.
An UI's component, is the way to render UI.
- Sprite *sprite.
- v2f pivot.
- v2f offset.
- SDL_Color color.
Image(UI *master, ...)
: Constructor a Image attach to "master".Object ChangeMaster(Object *other)
: Set new master.rect GetRect()
: Get the rect of Image.
One of basic tools, access by mia::_Game()
.
int InitWindow()
: Init SDL program according tocommon.hpp
.int ClearWindow()
: Clear SDL program.int Update()
: Update game.int Render()
: Render game.
One of basic tools, access by mia::_Input()
.
void Update()
: Update/Register input.bool getKey(int key)
: Check if "key" is holding.bool getKeyDown(int key)
: Check if "key" is pressed in the last update.bool getKeyUp(int key)
: Check if "key" is released in the last update.v2f getMousePosition()
: Get the mouse position in the last update.bool isQuit()
: Check if user quit the program.
One of basic tools, access by mia::_Time()
.
void Step()
: Update time clock.double deltaTime()
: Get the delta time between 2 update.float fps()
: Get the current FPS.double time()
: Get the current time (in seconds).uint64_t stepCount()
: Get the ammount of update.
Like above, Camera is the one define how thing on World should be considered in Screen.
One of basic tools, access by mia::_Camera()
.
int getScreenWidth()
: Get screen width.int getScreenHeight()
: Get screen height.float getCameraWidth()
: Get camera width in World.float getCameraHeight()
: Get camera height in World.v2f SetCenter(v2f position)
: Set camera center position.float Resize(float newSize, v2f pivot)
: Resize camera to "newSize" in pivot "pivot"v2f WorldToScreenPoint(v2f point)
: Get Screen point from a World point.v2f ScreenToWorldPoint(v2f point)
: Get World point from a Screen point.
One of basic tools, access by mia::_Events()
.
RegisterObserver(Observer *observer)
.RemoveObserver(Observer *observer)
.Notify(int message)
: Notify the registered observer with the "message".
One of basic tools, access by mia::_Renderer()
.
void RegisterPortrait(Portrait *portrait)
: Register Portrait to render.void UnregisterPortrait(Portrait *portrait)
: UnRegister Portrait from render.void RegisterImage(Image *image)
: Register Image to render.void UnregisterImage(Image *image)
: UnRegister Image from render.void RegisterTilemap(Tilemap *tilemap)
: Register Tilemap to render.void UnregisterTilemap(Tilemap *tilemap)
: UnRegister Tilemap from render.void RenderBodiesCollision(bool state)
: Enable Render Bodies collision (or not).
One of basic tools, access by mia::_Physics()
.
void RegisterBody(Body *Body)
: Register Body collision, dynamic handle.void UnregisterBody(Body *Body)
: UnRegister Body collision, dynamic handle.void RegisterTilemap(Tilemap *tilemap)
: Register Tilemap collision.void UnregisterTilemap(Tilemap *tilemap)
: UnRegister Tilemap collision.bool Query(rect rect)
: return if there's STATIC body in area "rect"bool RaycastRect(v2f origin, v2f velocity, rect target, double &timeHit, v2f &hitPoint, v2f &normal)
: Cast a ray in "origin" to direction "velocity", distance "velocity" magnitude with the target "target", return if the ray hit, and output:timeHit
: return time need to hit the target (scale in "velocity")hitPoint
: return hit point.normal
: return normal vector of the hit.
A container manager multiple sprite.
A container contain sprites to be used as data for Tilemap.
this is like a place where I confess my sins when I was working on the project
- Error handling and debugging system. (this engine has done so poorly on debug and error handling so I think this is literally unusable by anyone else except me)
- Use less pointer and heap allocation to store things. (heap allocation allow many powerful thing but also the pain in the ass when come down to error handling)
- Use less OOP approach while I can use something simpler.
- Use fewer get/set functions and some weird way to access an object's attributes. (this is like the result of 2 thing above, I tried to use pointer stuff but also want to prevent error so I came up with the weirdest thing humanity can possibly came up with)
- More clear on ownership (this engine has no clear on ownerships, this might also the result of overuse heap allocation and transfer parameters as pointer)
time to do another one