Added an animation struct for sprites.

This commit is contained in:
Kapendev 2024-09-03 06:07:01 +03:00
parent b4b47d8dea
commit dbceb425d5
11 changed files with 57 additions and 39 deletions

View file

@ -11,7 +11,7 @@ void ready() {
}
bool update(float dt) {
drawDebugText("Hello world!", Vec2(8.0));
drawDebugText("Hello world!", Vec2(8));
return false;
}

View file

@ -12,7 +12,7 @@ void ready() {
}
bool update(float dt) {
drawDebugText("Hello world!", Vec2(8.0));
drawDebugText("Hello world!", Vec2(8));
return false;
}

View file

@ -1,7 +1,7 @@
# Examples
> [!NOTE]
> For examples that use sprites, you must download the [atlas.png](atlas.png) file and save it in your project's assets folder.
> For examples that use textures, the [atlas.png](atlas.png) file must be downloaded and saved in the project's assets folder.
## [Hello](hello.d)
@ -23,10 +23,10 @@ This example shows how to use the camera structure of Popka.
This example shows how to use the Popka dialogue system.
## [Follower](follower.d)
This example shows how to create an animated character that follows the mouse.
## [Map](map.d)
This example shows how to use the tile map structure of Popka.
## [Follower](follower.d)
This example shows how to create an animated character that follows the mouse.

View file

@ -18,12 +18,12 @@ bool update(float dt) {
// Draw the game world.
auto cameraArea = Rect(camera.position, resolution).area(camera.hook).subAll(3);
camera.attach();
drawDebugText("Move with arrow keys.", Vec2(8.0));
drawDebugText("Move with arrow keys.", Vec2(8));
drawRect(cameraArea, Color(50, 50, 40, 130));
camera.detach();
// Draw the game UI.
drawDebugText("I am UI!", Vec2(8.0));
drawDebugText("I am UI!", Vec2(8));
drawDebugText("+", resolution * Vec2(0.5));
drawDebugText("+", resolution * Vec2(0.5) + (cameraTarget - camera.position));
return false;

View file

@ -48,9 +48,9 @@ bool update(float dt) {
}
drawRect(player);
if (coins.length == 0) {
drawDebugText("You collected all the coins!", Vec2(8.0));
drawDebugText("You collected all the coins!", Vec2(8));
} else {
drawDebugText("Coins: {}/{}\nMove with arrow keys.".format(maxCoinCount - coins.length, maxCoinCount), Vec2(8.0));
drawDebugText("Coins: {}/{}\nMove with arrow keys.".format(maxCoinCount - coins.length, maxCoinCount), Vec2(8));
}
return false;
}

View file

@ -63,9 +63,9 @@ bool update(float dt) {
drawDebugText(" | {}".format(choice), choicePosition);
}
} else if (dialogue.canUpdate) {
drawDebugText("{}: {}".format(dialogue.actor, dialogue.text), Vec2(8.0));
drawDebugText("{}: {}".format(dialogue.actor, dialogue.text), Vec2(8));
} else {
drawDebugText("The dialogue has ended.", Vec2(8.0));
drawDebugText("The dialogue has ended.", Vec2(8));
}
// Draw the game info.

View file

@ -3,9 +3,8 @@ import popka;
// The game variables.
auto atlas = TextureId();
auto sprite = Sprite(16, 16, 0, 128, 2, 8);
auto sprite = Sprite(16, 16, 0, 128, SpriteAnimation(0, 2, 6));
auto spritePosition = Vec2();
auto spriteSlowdown = 0.2;
void ready() {
lockResolution(320, 180);
@ -18,7 +17,7 @@ void ready() {
bool update(float dt) {
// Move the sprite around in a smooth way.
spritePosition = spritePosition.moveToWithSlowdown(mouseScreenPosition, Vec2(dt), spriteSlowdown);
spritePosition = spritePosition.moveToWithSlowdown(mouseScreenPosition, Vec2(dt), 0.2);
// Update the frame of the sprite.
auto isWaiting = spritePosition.distanceTo(mouseScreenPosition) < 0.2;
@ -28,14 +27,23 @@ bool update(float dt) {
sprite.update(dt);
}
// Check if 1, 2, or 3 is pressed and change the character.
foreach (i, digit; digitChars[1 .. 4]) {
if (digit.isPressed) {
sprite.animation.frameRow = cast(ubyte) i;
}
}
// Set the drawing options for the sprite.
auto options = DrawOptions();
options.scale = Vec2(2);
options.hook = Hook.center;
options.flip = (spritePosition.directionTo(mouseScreenPosition).x > 0) ? Flip.x : Flip.none;
// Draw the sprite and the mouse position.
// Draw the sprite, the mouse position and some info.
drawSprite(atlas, sprite, spritePosition, options);
drawVec2(mouseScreenPosition, 8, isWaiting ? blank : white.alpha(130));
drawVec2(mouseScreenPosition, 8, isWaiting ? blank : white.alpha(150));
drawDebugText("Press 1, 2 or 3 to change the character.", Vec2(8));
return false;
}

View file

@ -9,7 +9,7 @@ void ready() {
// The update function. This is called every frame while the game is running.
// If true is returned, then the game will stop running.
bool update(float dt) {
drawDebugText("Hello world!", Vec2(8.0));
drawDebugText("Hello world!", Vec2(8));
return false;
}

View file

@ -17,7 +17,8 @@ void ready() {
bool update(float dt) {
// Set the drawing options for the tile map.
auto options = DrawOptions();
options.scale = Vec2(2.0f);
options.scale = Vec2(2);
// Draw the tile map.
drawTileMap(atlas, tileMap, Vec2(), Camera(), options);
return false;

View file

@ -19,7 +19,7 @@ void ready() {
}
bool update(float dt) {
drawDebugText("Hello world!", Vec2(8.0));
drawDebugText("Hello world!", Vec2(8));
return false;
}

View file

@ -15,28 +15,36 @@ import popka.engine;
// TODO: Think about gaps in an atlas texture.
struct Sprite {
int width;
int height;
int atlasLeft;
int atlasTop;
int frameCount = 1;
float frameSpeed = 1.0f;
float frameProgress = 0.0f;
struct SpriteAnimation {
ubyte frameRow;
ubyte frameCount = 1;
ubyte frameSpeed = 1;
@safe @nogc nothrow:
this(int width, int height, int atlasLeft, int atlasTop, int frameCount = 1, float frameSpeed = 1.0f) {
this(ubyte frameRow, ubyte frameCount, ubyte frameSpeed) {
this.frameRow = frameRow;
this.frameCount = frameCount;
this.frameSpeed = frameSpeed;
}
}
struct Sprite {
int width;
int height;
ushort atlasLeft;
ushort atlasTop;
float frameProgress = 0.0f;
SpriteAnimation animation;
@safe @nogc nothrow:
this(int width, int height, ushort atlasLeft, ushort atlasTop, SpriteAnimation animation = SpriteAnimation()) {
this.width = width;
this.height = height;
this.atlasLeft = atlasLeft;
this.atlasTop = atlasTop;
this.frameCount = frameCount;
this.frameSpeed = frameSpeed;
}
this(int width, int height) {
this(width, height, 0, 0);
this.animation = animation;
}
int frame() {
@ -48,19 +56,20 @@ struct Sprite {
}
void update(float dt) {
frameProgress = wrap(frameProgress + frameSpeed * dt, 0.0f, frameCount);
frameProgress = wrap(frameProgress + animation.frameSpeed * dt, 0.0f, animation.frameCount);
}
}
void drawSprite(Texture texture, Sprite sprite, Vec2 position, DrawOptions options = DrawOptions()) {
auto top = sprite.atlasTop + sprite.animation.frameRow * sprite.height;
auto gridWidth = max(texture.width - sprite.atlasLeft, 0) / sprite.width;
auto gridHeight = max(texture.height - sprite.atlasTop, 0) / sprite.height;
auto gridHeight = max(texture.height - top, 0) / sprite.height;
if (gridWidth == 0 || gridHeight == 0) {
return;
}
auto row = sprite.frame / gridWidth;
auto col = sprite.frame % gridWidth;
auto area = Rect(sprite.atlasLeft + col * sprite.width, sprite.atlasTop + row * sprite.height, sprite.width, sprite.height);
auto area = Rect(sprite.atlasLeft + col * sprite.width, top + row * sprite.height, sprite.width, sprite.height);
drawTextureArea(texture, area, position, options);
}