From b86e16883176e5a9d84f311499996c27a44267d0 Mon Sep 17 00:00:00 2001 From: Sebastian Krzyszkowiak Date: Sun, 18 Feb 2018 14:42:58 +0100 Subject: [PATCH] WIP character rework from Rumina --- src/character.c | 149 ++++++++++++++++++++++++++++-------------------- src/character.h | 54 +++++++++++------- 2 files changed, 120 insertions(+), 83 deletions(-) diff --git a/src/character.c b/src/character.c index 7b38954..89942a9 100644 --- a/src/character.c +++ b/src/character.c @@ -22,6 +22,7 @@ #include "utils.h" #include #include +#include #include #include @@ -43,15 +44,12 @@ SYMBOL_EXPORT void SelectSpritesheet(struct Game* game, struct Character* charac } else { character->successor = NULL; } - character->repeat = tmp->repeat; + character->repeats = tmp->repeats; character->pos = 0; if (character->bitmap) { - if ((al_get_bitmap_width(character->bitmap) != tmp->width / tmp->cols) || (al_get_bitmap_height(character->bitmap) != tmp->height / tmp->rows)) { - al_destroy_bitmap(character->bitmap); - character->bitmap = al_create_bitmap(tmp->width / tmp->cols, tmp->height / tmp->rows); - } + al_reparent_bitmap(character->bitmap, tmp->bitmap, 0, 0, tmp->width / tmp->cols, tmp->height / tmp->rows); } else { - character->bitmap = al_create_bitmap(tmp->width / tmp->cols, tmp->height / tmp->rows); + character->bitmap = al_create_sub_bitmap(tmp->bitmap, 0, 0, tmp->width / tmp->cols, tmp->height / tmp->rows); } PrintConsole(game, "SUCCESS: Spritesheet for %s activated: %s (%dx%d)", character->name, character->spritesheet->name, al_get_bitmap_width(character->bitmap), al_get_bitmap_height(character->bitmap)); return; @@ -61,7 +59,7 @@ SYMBOL_EXPORT void SelectSpritesheet(struct Game* game, struct Character* charac PrintConsole(game, "ERROR: No spritesheets registered for %s with given name: %s", character->name, name); } -SYMBOL_EXPORT void ChangeSpritesheet(struct Game* game, struct Character* character, char* name) { +SYMBOL_EXPORT void EnqueueSpritesheet(struct Game* game, struct Character* character, char* name) { if (character->successor) { free(character->successor); } @@ -111,20 +109,17 @@ SYMBOL_EXPORT void RegisterSpritesheet(struct Game* game, struct Character* char s = malloc(sizeof(struct Spritesheet)); s->name = strdup(name); s->bitmap = NULL; - s->cols = strtol(al_get_config_value(config, "", "cols"), NULL, 10); s->rows = strtol(al_get_config_value(config, "", "rows"), NULL, 10); + s->cols = strtol(al_get_config_value(config, "", "cols"), NULL, 10); s->blanks = strtol(al_get_config_value(config, "", "blanks"), NULL, 10); s->delay = strtod(al_get_config_value(config, "", "delay"), NULL); - const char* val = al_get_config_value(config, "", "repeat"); + s->width = 0; + s->height = 0; + const char* val = al_get_config_value(config, "", "repeats"); if (val) { - s->repeat = strtod(val, NULL); + s->repeats = strtod(val, NULL); } else { - s->repeat = 0; - } - s->kill = false; - const char* kill = al_get_config_value(config, "", "kill"); - if (kill) { - s->kill = strtol(kill, NULL, 10); + s->repeats = 0; } s->successor = NULL; const char* successor = al_get_config_value(config, "", "successor"); @@ -141,23 +136,29 @@ SYMBOL_EXPORT struct Character* CreateCharacter(struct Game* game, char* name) { PrintConsole(game, "Creating character %s...", name); struct Character* character = malloc(sizeof(struct Character)); character->name = strdup(name); - character->angle = 0; character->bitmap = NULL; - character->data = NULL; + character->spritesheet = NULL; + character->spritesheets = NULL; character->pos = 0; character->pos_tmp = 0; + character->successor = NULL; character->x = -1; character->y = -1; + character->tint = al_map_rgb(255, 255, 255); character->pivotX = 0.5; character->pivotY = 0.5; + character->scaleX = 1.0; + character->scaleY = 1.0; + character->angle = 0; character->confineX = -1; character->confineY = -1; - character->spritesheets = NULL; - character->spritesheet = NULL; - character->successor = NULL; - character->repeat = 0; + character->flipX = false; + character->flipY = false; character->shared = false; - character->dead = false; + character->repeats = 0; + character->parent = NULL; + character->data = NULL; + return character; } @@ -189,8 +190,8 @@ SYMBOL_EXPORT void DestroyCharacter(struct Game* game, struct Character* charact free(character); } -SYMBOL_EXPORT void AnimateCharacter(struct Game* game, struct Character* character, float speed_modifier) { - if (character->dead) { return; } +SYMBOL_EXPORT void AnimateCharacter(struct Game* game, struct Character* character, float delta, float speed_modifier) { + speed_modifier *= delta / (1 / 60.f); // TODO: proper delta handling if (speed_modifier) { character->pos_tmp++; if (character->pos_tmp >= character->spritesheet->delay / speed_modifier) { @@ -199,16 +200,16 @@ SYMBOL_EXPORT void AnimateCharacter(struct Game* game, struct Character* charact } if (character->pos >= character->spritesheet->cols * character->spritesheet->rows - character->spritesheet->blanks) { character->pos = 0; - if (character->repeat) { - character->repeat--; - } else { - if (character->spritesheet->kill) { - character->dead = true; - } else if (character->successor) { - SelectSpritesheet(game, character, character->successor); - } + if (character->repeats) { + character->repeats--; + } else if (character->successor) { + SelectSpritesheet(game, character, character->successor); } } + + al_reparent_bitmap(character->bitmap, character->spritesheet->bitmap, + (character->pos % character->spritesheet->cols) * (character->spritesheet->width / character->spritesheet->cols), (character->pos / character->spritesheet->cols) * (character->spritesheet->height / character->spritesheet->rows), + character->spritesheet->width / character->spritesheet->cols, character->spritesheet->height / character->spritesheet->rows); } } @@ -217,14 +218,12 @@ SYMBOL_EXPORT void MoveCharacter(struct Game* game, struct Character* character, } SYMBOL_EXPORT void MoveCharacterF(struct Game* game, struct Character* character, float x, float y, float angle) { - if (character->dead) { return; } character->x += x; character->y += y; character->angle += angle; } SYMBOL_EXPORT void SetCharacterPositionF(struct Game* game, struct Character* character, float x, float y, float angle) { - if (character->dead) { return; } character->x = x; character->y = y; character->angle = angle; @@ -239,26 +238,14 @@ SYMBOL_EXPORT void SetCharacterPivotPoint(struct Game* game, struct Character* c character->pivotY = y; } -SYMBOL_EXPORT void DrawScaledCharacterF(struct Game* game, struct Character* character, ALLEGRO_COLOR tint, float scalex, float scaley, int flags) { - if (character->dead) { return; } - int spritesheetX = al_get_bitmap_width(character->bitmap) * (character->pos % character->spritesheet->cols); - int spritesheetY = al_get_bitmap_height(character->bitmap) * (character->pos / character->spritesheet->cols); - al_draw_tinted_scaled_rotated_bitmap_region(character->spritesheet->bitmap, spritesheetX, spritesheetY, al_get_bitmap_width(character->bitmap), al_get_bitmap_height(character->bitmap), tint, al_get_bitmap_width(character->bitmap) * character->pivotX, al_get_bitmap_height(character->bitmap) * character->pivotY, GetCharacterX(game, character) + al_get_bitmap_width(character->bitmap) * scalex * character->pivotX, GetCharacterY(game, character) + al_get_bitmap_height(character->bitmap) * scaley * character->pivotY, scalex, scaley, character->angle, flags); -} - -SYMBOL_EXPORT void DrawCharacterF(struct Game* game, struct Character* character, ALLEGRO_COLOR tint, int flags) { - DrawScaledCharacterF(game, character, tint, 1, 1, flags); -} - -SYMBOL_EXPORT void DrawScaledCharacter(struct Game* game, struct Character* character, ALLEGRO_COLOR tint, float scalex, float scaley, int flags) { - if (character->dead) { return; } - int spritesheetX = al_get_bitmap_width(character->bitmap) * (character->pos % character->spritesheet->cols); - int spritesheetY = al_get_bitmap_height(character->bitmap) * (character->pos / character->spritesheet->cols); - al_draw_tinted_scaled_rotated_bitmap_region(character->spritesheet->bitmap, spritesheetX, spritesheetY, al_get_bitmap_width(character->bitmap), al_get_bitmap_height(character->bitmap), tint, al_get_bitmap_width(character->bitmap) * character->pivotX, al_get_bitmap_height(character->bitmap) * character->pivotY, (int)(GetCharacterX(game, character) + al_get_bitmap_width(character->bitmap) * scalex * character->pivotX), (int)(GetCharacterY(game, character) + al_get_bitmap_height(character->bitmap) * scaley * character->pivotY), scalex, scaley, character->angle, flags); -} - -SYMBOL_EXPORT void DrawCharacter(struct Game* game, struct Character* character, ALLEGRO_COLOR tint, int flags) { - DrawScaledCharacter(game, character, tint, 1, 1, flags); +// TODO: coords are centered (pivot-related) or top left? +SYMBOL_EXPORT void DrawCharacter(struct Game* game, struct Character* character) { + int w = al_get_bitmap_width(character->bitmap), h = al_get_bitmap_height(character->bitmap); + al_draw_tinted_scaled_rotated_bitmap(character->bitmap, character->tint, + w * character->pivotX, h * character->pivotY, + GetCharacterX(game, character) + w * character->pivotX, GetCharacterY(game, character) + h * character->pivotY, + character->scaleX, character->scaleY, character->angle, + (character->flipX ? ALLEGRO_FLIP_HORIZONTAL : 0) | (character->flipY ? ALLEGRO_FLIP_VERTICAL : 0)); } SYMBOL_EXPORT void SetCharacterConfines(struct Game* game, struct Character* character, int x, int y) { @@ -274,21 +261,57 @@ SYMBOL_EXPORT int GetCharacterConfineY(struct Game* game, struct Character* char return (character->confineY >= 0) ? character->confineY : game->viewport.height; } -SYMBOL_EXPORT int GetCharacterX(struct Game* game, struct Character* character) { +SYMBOL_EXPORT float GetCharacterX(struct Game* game, struct Character* character) { return character->x * GetCharacterConfineX(game, character); } -SYMBOL_EXPORT int GetCharacterY(struct Game* game, struct Character* character) { +SYMBOL_EXPORT float GetCharacterY(struct Game* game, struct Character* character) { return character->y * GetCharacterConfineY(game, character); } -SYMBOL_EXPORT float GetCharacterAngle(struct Game* game, struct Character* character) { - return character->angle; +static void SortTwoFloats(float* v1, float* v2) { + float pom = *v1; + if (v1 > v2) { + *v1 = *v2; + *v2 = pom; + } } -SYMBOL_EXPORT bool IsOnCharacter(struct Game* game, struct Character* character, int x, int y) { - int x1 = GetCharacterX(game, character), y1 = GetCharacterY(game, character); - int x2 = x1 + al_get_bitmap_width(character->bitmap), y2 = y1 + al_get_bitmap_height(character->bitmap); +SYMBOL_EXPORT bool IsOnCharacter(struct Game* game, struct Character* character, float x, float y, bool pixelperfect) { + // TODO: fucking rework - return ((x >= x1) && (x <= x2) && (y >= y1) && (y <= y2)); + int w = al_get_bitmap_width(character->bitmap), h = al_get_bitmap_height(character->bitmap); + float x1 = GetCharacterX(game, character), y1 = GetCharacterY(game, character); + float x2 = x1 + w, y2 = y1 + h; + + /* float scalex = character->scaleX; + float scaley = character->scaleY; + if (character->flipX) { + scalex *= -1; + } + if (character->flipY) { + scaley *= -1; + } + ALLEGRO_TRANSFORM transform; + al_identity_transform(&transform); + al_translate_transform(&transform, -character->pivotX * w, -character->pivotY * h); + al_scale_transform(&transform, scalex, scaley); + al_translate_transform(&transform, character->pivotX * w, character->pivotY * h); + al_transform_coordinates(&transform, &x1, &y1); + al_transform_coordinates(&transform, &x2, &y2); + SortTwoFloats(&x1, &x2); + SortTwoFloats(&y1, &y2); +*/ + bool test = ((x >= x1) && (x <= x2) && (y >= y1) && (y <= y2)); + + //al_transform_coordinates(&transform, &x, &y); + + if (test && pixelperfect) { + x -= x1; + y -= y1; + ALLEGRO_COLOR color = al_get_pixel(character->bitmap, x, y); + return (color.a > 0.0); + } + + return test; } diff --git a/src/character.h b/src/character.h index 6b9d150..33f6a14 100644 --- a/src/character.h +++ b/src/character.h @@ -29,45 +29,60 @@ struct Spritesheet { char* name; /*!< Name of the spritesheet (used in file paths). */ ALLEGRO_BITMAP* bitmap; /*!< Spritesheet bitmap. */ + // TODO: bitmap file int rows; /*!< Number of rows in the spritesheet. */ int cols; /*!< Number of columns in the spritesheet. */ int blanks; /*!< Number of blank frames at the end of the spritesheet. */ int width; int height; int delay; - bool kill; - int repeat; - float scale; /*!< Scale modifier of the frame. */ + int repeats; /*!< Number of repeats to make before the spritesheet is changed to its successor. */ char* successor; /*!< Name of animation successor. If it's not blank, then animation will be played only once. */ struct Spritesheet* next; /*!< Next spritesheet in the queue. */ + // TODO: loopmode + // TODO: playmode + + // TODO: missing docs }; /*! \brief Structure representing one visible character. */ struct Character { char* name; /*!< Name of the character (used in file paths). */ + struct Character* parent; /*!< Parent character. NULL is no parent. */ + ALLEGRO_BITMAP* bitmap; /*!< Subbitmap with character's current frame. */ struct Spritesheet* spritesheet; /*!< Current spritesheet used by character. */ struct Spritesheet* spritesheets; /*!< List of all spritesheets registered to character. */ - char* successor; - ALLEGRO_BITMAP* bitmap; int pos; /*!< Current spritesheet position. */ - int pos_tmp; /*!< A counter used to slow down spritesheet animation. */ + int pos_tmp; /*!< A counter used internally to slow down spritesheet animation. */ // TODO: change to delta + char* successor; /*!< Name of the next spritesheet to be played when the current one finishes. */ float x; /*!< Horizontal position of character. */ float y; /*!< Vertical position of character. */ - float angle; /*!< Characters display angle (radians). */ - float pivotX, pivotY; /*!< Pivot point, relative of character's size. */ - int confineX, confineY; /*!< Size of the canvas being drawn to, for correct position calculation; when -1, uses viewport size */ + ALLEGRO_COLOR tint; /*!< Color with which the character's pixels will be multiplied (tinted). White for no effect. */ + float pivotX; /*!< Pivot point's X, for scaling and rotating, relative of character's size. */ + float pivotY; /*!< Pivot point's Y, for scaling and rotating, relative of character's size. */ + float scaleX; /*!< Scale factor for X axis. */ + float scaleY; /*!< Scale factor for Y axis. */ + float angle; /*!< Character's rotation angle (radians). */ + int confineX; /*!< Width of the canvas being drawn to, for correct position calculation; when -1, uses parent's confines or viewport size */ + int confineY; /*!< Height of the canvas being drawn to, for correct position calculation; when -1, uses parent's confines or viewport size */ + bool flipX; /*!< Flips the character's sprite vertically. */ + bool flipY; /*!< Flips the character's sprite horizontally. */ + bool shared; /*!< Marks the list of spritesheets as shared, so it won't be freed together with the character. */ + int repeats; /*!< Number of repeats left before the spritesheet is changed to its successor. */ void* data; /*!< Additional, custom character data (HP etc.). */ - int repeat; - bool shared; - bool dead; + // TODO: add a callback for when the animation finishes + // TODO: playmode + + // TODO: parents }; +// TODO: document functions + void SelectSpritesheet(struct Game* game, struct Character* character, char* name); -void ChangeSpritesheet(struct Game* game, struct Character* character, char* name); +void EnqueueSpritesheet(struct Game* game, struct Character* character, char* name); void RegisterSpritesheet(struct Game* game, struct Character* character, char* name); -void DrawCharacterF(struct Game* game, struct Character* character, ALLEGRO_COLOR tint, int flags); -void DrawCharacter(struct Game* game, struct Character* character, ALLEGRO_COLOR tint, int flags); +void DrawCharacter(struct Game* game, struct Character* character); void DrawScaledCharacterF(struct Game* game, struct Character* character, ALLEGRO_COLOR tint, float scalex, float scaley, int flags); void DrawScaledCharacter(struct Game* game, struct Character* character, ALLEGRO_COLOR tint, float scalex, float scaley, int flags); @@ -77,7 +92,7 @@ void DestroyCharacter(struct Game* game, struct Character* character); void LoadSpritesheets(struct Game* game, struct Character* character); void UnloadSpritesheets(struct Game* game, struct Character* character); -void AnimateCharacter(struct Game* game, struct Character* character, float speed_modifier); +void AnimateCharacter(struct Game* game, struct Character* character, float delta, float speed_modifier); void MoveCharacter(struct Game* game, struct Character* character, float x, float y, float angle); void MoveCharacterF(struct Game* game, struct Character* character, float x, float y, float angle); void SetCharacterPosition(struct Game* game, struct Character* character, float x, float y, float angle); @@ -85,12 +100,11 @@ void SetCharacterPositionF(struct Game* game, struct Character* character, float void SetCharacterPivotPoint(struct Game* game, struct Character* character, float x, float y); void SetCharacterConfines(struct Game* game, struct Character* character, int x, int y); -int GetCharacterX(struct Game* game, struct Character* character); -int GetCharacterY(struct Game* game, struct Character* character); -float GetCharacterAngle(struct Game* game, struct Character* character); +float GetCharacterX(struct Game* game, struct Character* character); +float GetCharacterY(struct Game* game, struct Character* character); int GetCharacterConfineX(struct Game* game, struct Character* character); int GetCharacterConfineY(struct Game* game, struct Character* character); -bool IsOnCharacter(struct Game* game, struct Character* character, int x, int y); +bool IsOnCharacter(struct Game* game, struct Character* character, float x, float y, bool pixelperfect); #endif