#include #include #include "constants.h" #include "game.h" #include "player.h" #include "player_data.h" #include "physics.h" #include "assets.h" #include "utils.h" extern Game game; static void AddPlayerSprites(Entity* player); typedef enum PlayerStates { PLAYER_IDLE = 0, PLAYER_WALKING = 1, PLAYER_ATTACK = 2, } PlayerStates; Vector2 GetMovementDirection() { Vector2 movementDirection = {0.0f, 0.0f}; if (IsKeyDown(KEY_W)) { movementDirection.y = -1.0f; } else if (IsKeyDown(KEY_S)) { movementDirection.y = 1.0f; } if (IsKeyDown(KEY_A)) { movementDirection.x = -1.0f; } else if (IsKeyDown(KEY_D)) { movementDirection.x = 1.0f; } if (Vector2Length(movementDirection) > 0.0f) return Vector2Normalize(movementDirection); return movementDirection; } void CameraFollow(const Entity* player) { game.camera.target.x = fmaxf(WINDOW_WIDTH / 2.0f, player->position.x); } void UpdateBodyFacing(Entity* player) { Sprite* bodySprite = &player->sprites[player->bodySpriteIndex]; if (player->velocity.x < 0) bodySprite->flipX = true; else if (player->velocity.x > 0) bodySprite->flipX = false; } bool CanAttack(Entity* player) { return player->state == PLAYER_IDLE || player->state == PLAYER_WALKING; } bool CanMove(Entity* player) { return player->state == PLAYER_IDLE || player->state == PLAYER_WALKING; } void HandleMovement(Entity* player) { if (CanMove(player)) { if (Vector2Length(player->velocity) > 0.0) player->state = PLAYER_WALKING; else player->state = PLAYER_IDLE; } else { player->velocity = (Vector2) {0.0f, 0.0f}; } } void HandleAttack(Entity* player) { if (player->state != PLAYER_ATTACK) { player->numHitBoxes = 0; return; } Sprite* bodySprite = &player->sprites[player->bodySpriteIndex]; player->numHitBoxes = 1; if (bodySprite->animations[PLAYER_ATTACK].isComplete) { player->state = PLAYER_IDLE; ResetAnimation(&bodySprite->animations[PLAYER_ATTACK]); } } void HandleInput(Entity* player) { player->velocity = Vector2Scale(GetMovementDirection(), PLAYER_SPEED); if (IsKeyPressed(KEY_O) && CanAttack(player)) player->state = PLAYER_ATTACK; } void HandleAnimation(Entity* player) { Sprite* bodySprite = &player->sprites[player->bodySpriteIndex]; bodySprite->currentAnimation = player->state; } void UpdateAnimation(Entity* player, float deltaTime) { Sprite* bodySprite = &player->sprites[player->bodySpriteIndex]; UpdateCurrentSpriteAnimation(bodySprite, deltaTime); } void FlipBody(Entity* player) { Sprite* bodySprite = &player->sprites[player->bodySpriteIndex]; if (player->velocity.x < 0) { bodySprite->flipX = true; player->hitBoxes[0].x = HITBOX_XPOS_FLIPPED; } else if (player->velocity.x > 0) { bodySprite->flipX = false; player->hitBoxes[0].x = HITBOX_XPOS; } } void UpdatePlayer(Entity* player, float deltaTime) { HandleInput(player); HandleMovement(player); FlipBody(player); MoveAndStop(player, deltaTime); HandleAnimation(player); UpdateAnimation(player, deltaTime); HandleAttack(player); CameraFollow(player); } void AddPlayer(float xpos, float ypos) { Entity player = {0}; player.type = Player_Entity; player.position = (Vector2) {xpos, ypos}; player.flags |= (ENTITY_PHYSICS_ACTIVE | ENTITY_VISIBLE); player.physicsCollider = physicsCollider; player.hitBoxes[0] = punchHitBox; player.numHitBoxes = 1; #ifdef BEATEMUP_DEBUG player.physicsColliderColor = RED; player.hitboxColors[0] = BLUE; #endif AddPlayerSprites(&player); AddEntity(&player); } static void AddPlayerSprites(Entity* player) { Asset* shadowTexture = GetMatchingAssetExitOnFail("human-shadow", Texture_Asset); Sprite shadowSprite = (Sprite) { .texture = shadowTexture->texture, .layer = Foreground_Layer, .destRect = shadowDestRect, .srcRect = { 0, 0, shadowTexture->texture.width, shadowTexture->texture.height }, .numAnimations = 0, //Not an animated sprite }; AddSpriteToEntity(player, shadowSprite); Asset* bodyTexture = GetMatchingAssetExitOnFail("player-body", Texture_Asset); Sprite bodySprite = (Sprite) { .texture = bodyTexture->texture, .layer = Foreground_Layer, .destRect = bodyDestRect, .numAnimations = 0 }; //The body texture devided into a 10x10 grid //with one cell representing a frame of animation Animation idleAnimation = AnimationFromIndices((AnimationFromIndicesParams){ .texture = bodyTexture->texture, .isLooping = true, .numFrames = 4, .framesX = 10, .framesY = 10, .indices = (int[]) {0, 1, 2, 3}, .frameTimes = (float[]) {0.1f, 0.1f, 0.1f, 0.1f} }); bodySprite.animations[PLAYER_IDLE] = idleAnimation; Animation walkingAnimation = AnimationFromIndices((AnimationFromIndicesParams){ .texture = bodyTexture->texture, .isLooping = true, .numFrames = 7, .framesX = 10, .framesY = 10, .indices = (int[]) {10, 11, 12, 13, 14, 15, 16, 17}, .frameTimes = (float[]) {0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f} }); bodySprite.animations[PLAYER_WALKING] = walkingAnimation; Animation punchAnimation = AnimationFromIndices((AnimationFromIndicesParams){ .texture = bodyTexture->texture, .isLooping = false, .numFrames = 4, .framesX = 10, .framesY = 10, .indices = (int[]) {20, 21, 22, 23}, .frameTimes = (float[]) {0.05f, 0.05f, 0.05f, 0.05f} }); bodySprite.animations[PLAYER_ATTACK] = punchAnimation; bodySprite.numAnimations = 2; player->bodySpriteIndex = AddSpriteToEntity(player, bodySprite); }