It is a pretty straight forward API to be honest, function names are descriptive and the syntax is pretty forgiving, managed memory but above all it may seem like a simple thing but internal sprite and object management classes make it a joy to use, take Love2D or raylib for example, sure they both rock but before you do anything you got to write management and animation systems, bounding boxes and collisions ... its all just there in AppGameKit, a lot of people forget or dont even consider this
Here, Ill give you a real world example, I am kind of building my own game engine on the back burner (shelved it for this comp)
this
#pragma once
#include <map>
#include "Animator.h"
#include "cHashedList.h"
extern "C" {
#include "raylib.h"
}
class cSprite {
private:
bool m_bHasTexture;
Texture2D m_Texture{};
bool m_bHasAnimation;
Animator m_Animator{"Name", 1,1,1};
std::string m_sCurrentAnimation;
Vector2 m_vSize;
Vector2 m_vPos;
Vector2 m_vOffset;
float m_fScale;
float m_fAngel;
Color m_tColor;
public:
cSprite(int iX, int iY, Color color);
cSprite(int iX, int iY, Image image, Color color);
~cSprite();
void AddAnimation(std::string name, unsigned int iColumns, unsigned int iRows, unsigned int iSpeed);
void PlayAnimation(int iStart, int iEnd, float fFPS);
void SetSpriteFrame(int iFrame);
int GetSpriteFrame();
bool HasTexture();
void SetPosition(int iX, int iY);
int GetX();
int GetY();
void SetSize(int iWidth, int iHeight);
int GetWidth();
int GetHeight();
void SetOffset(int iX, int iY);
int GetOffsetX();
int GetOffsetY();
void SetScale(float fScale);
float GetScale();
void SetAngel(float fAngle);
float GetAngel();
void SetTexture(Texture2D texture);
Texture2D GetTexture();
void Draw();
};
cSprite::cSprite(int iX, int iY, Image image, Color color) {
TraceLog(LOG_TRACE, "cSprite::cSprite(%d, %d, %d, %d)", iX, iY, image, color);
Texture2D texture = LoadTextureFromImage(image);
m_vPos.x = iX;
m_vPos.y = iY;
m_vOffset.x = texture.width / 2;
m_vOffset.y = texture.height / 2;
m_fScale = 1.0f;
m_fAngel = 0.0f;
m_tColor = color;
m_Texture = texture;
m_bHasTexture = true;
m_bHasAnimation = false;
m_vSize.x = texture.width;
m_vSize.y = texture.height;
}
cSprite::cSprite(int iX, int iY, Color color) {
m_vPos.x = iX;
m_vPos.y = iY;
m_vOffset.x = 16;
m_vOffset.y = 16;
m_fScale = 1.0f;
m_fAngel = 0.0f;
m_tColor = color;
//m_Texture = Texture2D{};
m_bHasTexture = false;
m_bHasAnimation = false;
m_vSize.x = 32;
m_vSize.y = 32;
}
cSprite::~cSprite()
{
}
bool cSprite::HasTexture()
{
return m_bHasTexture;
}
void cSprite::SetPosition(int iX, int iY) {
m_vPos.x = iX + m_vOffset.x;
m_vPos.y = iY + m_vOffset.y;
}
int cSprite::GetX()
{
return m_vPos.x;
}
int cSprite::GetY()
{
return m_vPos.y;
}
void cSprite::SetOffset(int iWidth, int iHeight)
{
m_vOffset.x = iWidth;
m_vOffset.y = iHeight;
}
int cSprite::GetOffsetX()
{
return m_vOffset.x;
}
int cSprite::GetOffsetY()
{
return m_vOffset.y;
}
void cSprite::SetSize(int iWidth, int iHeight)
{
m_vSize.x = iWidth;
m_vSize.y = iHeight;
}
int cSprite::GetWidth()
{
return m_vSize.x;
}
int cSprite::GetHeight()
{
return m_vSize.y;
}
void cSprite::SetScale(float fScale)
{
m_fScale = fScale;
float fWidth = m_Texture.width * m_fScale;
float fHeight = m_Texture.height * m_fScale;
m_vOffset.x = fWidth / 2;
m_vOffset.y = fHeight / 2;
}
float cSprite::GetScale()
{
return m_fScale;
}
void cSprite::SetAngel(float fAngle)
{
m_fAngel = fAngle;
}
float cSprite::GetAngel()
{
return m_fAngel;
}
void cSprite::SetTexture(Texture2D texture)
{
m_Texture = texture;
}
Texture2D cSprite::GetTexture()
{
return m_Texture;
}
void cSprite::Draw() {
if (m_bHasTexture) {
Texture2D texture = m_Texture;
Vector2 origin{ m_vOffset.x, m_vOffset.y };
float rotation = m_fAngel;
float scale = m_fScale;
Color tint{ 255, 255, 255, 255 };
Rectangle dest{ m_vPos.x, m_vPos.y, m_vSize.x * m_fScale, m_vSize.y * m_fScale };
if (m_bHasAnimation)
{
if (strcmp(m_Animator.GetName(), m_sCurrentAnimation.c_str())) {
TraceLog(LOG_TRACE, "Draw Animated 1");
m_Animator.Play();
DrawTextureTiled(m_Animator.GetSprite(), m_Animator.GetFrameRec(), dest, origin, m_fAngel, m_fScale, tint);
}
}
else
{
Rectangle source{ 0, 0, m_vSize.x, m_vSize.y };
DrawTextureTiled(texture, source, dest, origin, rotation, scale, tint);
}
}
else {
Rectangle rect{ m_vPos.x , m_vPos.y, m_vSize.x , m_vSize.y };
DrawRectanglePro(rect, m_vOffset, m_fAngel, m_tColor);
}
}
void cSprite::AddAnimation(std::string name, unsigned int iColumns, unsigned int iRows, unsigned int iSpeed)
{
m_bHasAnimation = true;
//Animator anim{ name.c_str(), iColumns, iRows, iSpeed };
m_Animator.AssignSprite(m_Texture);
m_Animator.ChangeSprite(m_Texture, iColumns, iRows, iSpeed);
m_Animator.GoToFrame(6);
m_sCurrentAnimation = name;
}
void cSprite::PlayAnimation(int iStart, int iEnd, float fFPS)
{
}
void cSprite::SetSpriteFrame(int iFrame)
{
}
int cSprite::GetSpriteFrame()
{
return 0;
}
and this
#pragma once
#include "cHashedList.h"
#include "cSprite.h"
namespace SpriteManager {
cHashedList<cSprite> m_Map(64);
int Create(Image image);
int Create();
void Delete(int iID);
void SetAnimation(int iID, const char* name, int iColumns, int iRows, int iSpeed);
void SetPosition(int iID, int iX, int iY);
int GetX(int iID);
int GetY(int iID);
void SetSize(int iID, int iWidth, int iHeight);
int GetWidth(int iID);
int GetHeight(int iID);
void SetOffset(int iID, int iWidth, int iHeight);
int GetOffsetX(int iID);
int GetOffsetY(int iID);
void SetScale(int iID, float fScale);
float GetScale(int iID);
void SetAngle(int iID, float fAngle);
float GetAngle(int iID);
void Draw();
bool GetExists(int iID);
}
bool SpriteManager::GetExists(int iID) {
if (m_Map.GetItem(iID)) {
return true;
}
return false;
}
int SpriteManager::Create() {
cSprite* pSprite = new cSprite(0, 0, WHITE);
int iID = m_Map.GetFreeID();
m_Map.AddItem(pSprite, iID);
return iID;
}
int SpriteManager::Create(Image image) {
//Image data = *image;
cSprite* pSprite = new cSprite(0, 0, image, WHITE);
int iID = m_Map.GetFreeID();
m_Map.AddItem(pSprite, iID);
return iID;
}
void SpriteManager::Delete(int iID)
{
cSprite * sprite = m_Map.GetItem(iID);
if (sprite)
{
m_Map.RemoveItem(iID);
}
}
void SpriteManager::SetAnimation(int iID, const char * name, int iColumns, int iRows, int iSpeed)
{
// Check dimensions
cSprite * sprite = m_Map.GetItem(iID);
if (sprite)
{
if (sprite->HasTexture()) {
sprite->AddAnimation(name, iColumns, iRows, iSpeed);
}
}
}
void SpriteManager::SetPosition(int iID, int iX, int iY)
{
cSprite * sprite = m_Map.GetItem(iID);
if (sprite)
{
sprite->SetPosition(iX, iY);
}
}
int SpriteManager::GetX(int iID)
{
cSprite * sprite = m_Map.GetItem(iID);
if (sprite)
{
return sprite->GetX();
}
}
int SpriteManager::GetY(int iID)
{
cSprite * sprite = m_Map.GetItem(iID);
if (sprite)
{
return sprite->GetY();
}
}
void SpriteManager::SetSize(int iID, int iWidth, int iHeight)
{
cSprite * sprite = m_Map.GetItem(iID);
if (sprite)
{
sprite->SetSize(iWidth, iHeight);
}
}
int SpriteManager::GetWidth(int iID)
{
cSprite * sprite = m_Map.GetItem(iID);
if (sprite)
{
return sprite->GetWidth();
}
}
int SpriteManager::GetHeight(int iID)
{
cSprite * sprite = m_Map.GetItem(iID);
if (sprite)
{
return sprite->GetHeight();
}
}
void SpriteManager::SetOffset(int iID, int iX, int iY)
{
cSprite * sprite = m_Map.GetItem(iID);
if (sprite)
{
sprite->SetOffset(iX, iY);
}
}
int SpriteManager::GetOffsetX(int iID)
{
cSprite * sprite = m_Map.GetItem(iID);
if (sprite)
{
return sprite->GetOffsetX();
}
}
int SpriteManager::GetOffsetY(int iID)
{
cSprite * sprite = m_Map.GetItem(iID);
if (sprite)
{
return sprite->GetOffsetY();
}
}
void SpriteManager::SetScale(int iID, float fScale)
{
cSprite* sprite = m_Map.GetItem(iID);
if (sprite) {
sprite->SetScale(fScale);
}
}
float SpriteManager::GetScale(int iID)
{
cSprite* sprite = m_Map.GetItem(iID);
if (sprite)
{
return sprite->GetScale();
}
}
void SpriteManager::SetAngle(int iID, float fAngle)
{
cSprite* sprite = m_Map.GetItem(iID);
if (sprite)
{
sprite->SetAngel(fAngle);
}
}
float SpriteManager::GetAngle(int iID)
{
cSprite* sprite = m_Map.GetItem(iID);
if (sprite) {
return sprite->GetAngel();
}
}
void SpriteManager::Draw()
{
cSprite * sprite = m_Map.GetFirst();
while (sprite)
{
sprite->Draw();
sprite = m_Map.GetNext();
}
}
are just to create, move and draw a sprite ... and there not finished yet, no collisions, no physics, animations not finished, everything ^^ that lot does AppGameKit does with a handful of function calls!, it is a pure joy to code with even the C++ side, compared to the alternative ^^
Same for Love2D I wrote a sprite management class for that a while ago, same deal, but dumped it because I also want 3D.
There is a reason I keep coming back to AppGameKit, it saves me writing thousands of lines of code to do the most mundane things lol