mirror of
https://github.com/Kapendev/parin.git
synced 2025-04-27 05:29:53 +03:00
Added an animation struct for sprites.
This commit is contained in:
parent
b4b47d8dea
commit
dbceb425d5
11 changed files with 57 additions and 39 deletions
|
@ -11,7 +11,7 @@ void ready() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update(float dt) {
|
bool update(float dt) {
|
||||||
drawDebugText("Hello world!", Vec2(8.0));
|
drawDebugText("Hello world!", Vec2(8));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
TOUR.md
2
TOUR.md
|
@ -12,7 +12,7 @@ void ready() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update(float dt) {
|
bool update(float dt) {
|
||||||
drawDebugText("Hello world!", Vec2(8.0));
|
drawDebugText("Hello world!", Vec2(8));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
> [!NOTE]
|
> [!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)
|
## [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.
|
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)
|
## [Map](map.d)
|
||||||
|
|
||||||
This example shows how to use the tile map structure of Popka.
|
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.
|
||||||
|
|
|
@ -18,12 +18,12 @@ bool update(float dt) {
|
||||||
// Draw the game world.
|
// Draw the game world.
|
||||||
auto cameraArea = Rect(camera.position, resolution).area(camera.hook).subAll(3);
|
auto cameraArea = Rect(camera.position, resolution).area(camera.hook).subAll(3);
|
||||||
camera.attach();
|
camera.attach();
|
||||||
drawDebugText("Move with arrow keys.", Vec2(8.0));
|
drawDebugText("Move with arrow keys.", Vec2(8));
|
||||||
drawRect(cameraArea, Color(50, 50, 40, 130));
|
drawRect(cameraArea, Color(50, 50, 40, 130));
|
||||||
camera.detach();
|
camera.detach();
|
||||||
|
|
||||||
// Draw the game UI.
|
// 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));
|
||||||
drawDebugText("+", resolution * Vec2(0.5) + (cameraTarget - camera.position));
|
drawDebugText("+", resolution * Vec2(0.5) + (cameraTarget - camera.position));
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -48,9 +48,9 @@ bool update(float dt) {
|
||||||
}
|
}
|
||||||
drawRect(player);
|
drawRect(player);
|
||||||
if (coins.length == 0) {
|
if (coins.length == 0) {
|
||||||
drawDebugText("You collected all the coins!", Vec2(8.0));
|
drawDebugText("You collected all the coins!", Vec2(8));
|
||||||
} else {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,9 +63,9 @@ bool update(float dt) {
|
||||||
drawDebugText(" | {}".format(choice), choicePosition);
|
drawDebugText(" | {}".format(choice), choicePosition);
|
||||||
}
|
}
|
||||||
} else if (dialogue.canUpdate) {
|
} else if (dialogue.canUpdate) {
|
||||||
drawDebugText("{}: {}".format(dialogue.actor, dialogue.text), Vec2(8.0));
|
drawDebugText("{}: {}".format(dialogue.actor, dialogue.text), Vec2(8));
|
||||||
} else {
|
} else {
|
||||||
drawDebugText("The dialogue has ended.", Vec2(8.0));
|
drawDebugText("The dialogue has ended.", Vec2(8));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the game info.
|
// Draw the game info.
|
||||||
|
|
|
@ -3,9 +3,8 @@ import popka;
|
||||||
|
|
||||||
// The game variables.
|
// The game variables.
|
||||||
auto atlas = TextureId();
|
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 spritePosition = Vec2();
|
||||||
auto spriteSlowdown = 0.2;
|
|
||||||
|
|
||||||
void ready() {
|
void ready() {
|
||||||
lockResolution(320, 180);
|
lockResolution(320, 180);
|
||||||
|
@ -18,7 +17,7 @@ void ready() {
|
||||||
|
|
||||||
bool update(float dt) {
|
bool update(float dt) {
|
||||||
// Move the sprite around in a smooth way.
|
// 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.
|
// Update the frame of the sprite.
|
||||||
auto isWaiting = spritePosition.distanceTo(mouseScreenPosition) < 0.2;
|
auto isWaiting = spritePosition.distanceTo(mouseScreenPosition) < 0.2;
|
||||||
|
@ -28,14 +27,23 @@ bool update(float dt) {
|
||||||
sprite.update(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.
|
// Set the drawing options for the sprite.
|
||||||
auto options = DrawOptions();
|
auto options = DrawOptions();
|
||||||
options.scale = Vec2(2);
|
options.scale = Vec2(2);
|
||||||
options.hook = Hook.center;
|
options.hook = Hook.center;
|
||||||
options.flip = (spritePosition.directionTo(mouseScreenPosition).x > 0) ? Flip.x : Flip.none;
|
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);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ void ready() {
|
||||||
// The update function. This is called every frame while the game is running.
|
// The update function. This is called every frame while the game is running.
|
||||||
// If true is returned, then the game will stop running.
|
// If true is returned, then the game will stop running.
|
||||||
bool update(float dt) {
|
bool update(float dt) {
|
||||||
drawDebugText("Hello world!", Vec2(8.0));
|
drawDebugText("Hello world!", Vec2(8));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,8 @@ void ready() {
|
||||||
bool update(float dt) {
|
bool update(float dt) {
|
||||||
// Set the drawing options for the tile map.
|
// Set the drawing options for the tile map.
|
||||||
auto options = DrawOptions();
|
auto options = DrawOptions();
|
||||||
options.scale = Vec2(2.0f);
|
options.scale = Vec2(2);
|
||||||
|
|
||||||
// Draw the tile map.
|
// Draw the tile map.
|
||||||
drawTileMap(atlas, tileMap, Vec2(), Camera(), options);
|
drawTileMap(atlas, tileMap, Vec2(), Camera(), options);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -19,7 +19,7 @@ void ready() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update(float dt) {
|
bool update(float dt) {
|
||||||
drawDebugText("Hello world!", Vec2(8.0));
|
drawDebugText("Hello world!", Vec2(8));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,28 +15,36 @@ import popka.engine;
|
||||||
|
|
||||||
// TODO: Think about gaps in an atlas texture.
|
// TODO: Think about gaps in an atlas texture.
|
||||||
|
|
||||||
struct Sprite {
|
struct SpriteAnimation {
|
||||||
int width;
|
ubyte frameRow;
|
||||||
int height;
|
ubyte frameCount = 1;
|
||||||
int atlasLeft;
|
ubyte frameSpeed = 1;
|
||||||
int atlasTop;
|
|
||||||
int frameCount = 1;
|
|
||||||
float frameSpeed = 1.0f;
|
|
||||||
float frameProgress = 0.0f;
|
|
||||||
|
|
||||||
@safe @nogc nothrow:
|
@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.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.atlasLeft = atlasLeft;
|
this.atlasLeft = atlasLeft;
|
||||||
this.atlasTop = atlasTop;
|
this.atlasTop = atlasTop;
|
||||||
this.frameCount = frameCount;
|
this.animation = animation;
|
||||||
this.frameSpeed = frameSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
this(int width, int height) {
|
|
||||||
this(width, height, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int frame() {
|
int frame() {
|
||||||
|
@ -48,19 +56,20 @@ struct Sprite {
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(float dt) {
|
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()) {
|
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 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) {
|
if (gridWidth == 0 || gridHeight == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto row = sprite.frame / gridWidth;
|
auto row = sprite.frame / gridWidth;
|
||||||
auto col = 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);
|
drawTextureArea(texture, area, position, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue