diff --git a/game/src/Damagable.h b/game/src/Damagable.h index 677ada6..5206579 100644 --- a/game/src/Damagable.h +++ b/game/src/Damagable.h @@ -7,6 +7,9 @@ typedef struct DamageEventData { int damageAmount; + int knockdown; + float stun; + float knockback; Vector origin; } DamageEventData; diff --git a/game/src/Enemy.c b/game/src/Enemy.c index b6b83bb..c651387 100644 --- a/game/src/Enemy.c +++ b/game/src/Enemy.c @@ -1,4 +1,5 @@ #include "Enemy.h" +#include "Layers.h" #include "debug.h" #include "game_world.h" #include "physics.h" @@ -46,9 +47,10 @@ Enemy* MakeEnemy() { .behaviour = NULL, .rigidbody = NULL, .collider = NULL, + .hitbox = NULL, .sprite = sprite_new_empty(), - .hurt = 0, .facing = 1, + .stun_time = 0.f, .idleAnim = NULL, .walkAnim = NULL, .hurtAnim = NULL, @@ -57,7 +59,15 @@ Enemy* MakeEnemy() { }; self->rigidbody = rigidbody_make(Enemy_as_PhysicsEntity(self)); - self->collider = collider_new(Enemy_as_PhysicsEntity(self), shape_new_square(MakeVector(0.2f, 0.05f)), 0, PHYSICS_LAYER_DEFAULT | PHYSICS_LAYER_DEFAULT); + self->collider = collider_new(Enemy_as_PhysicsEntity(self), shape_new_square(MakeVector(0.2f, 0.05f)), 0, PHYSICS_LAYER_DEFAULT); + self->collider = collider_new(Enemy_as_PhysicsEntity(self), shape_new((Vector[]){ + MakeVector(-0.2f, -0.95f), + MakeVector( 0.2f, -0.95f), + MakeVector( 0.2f, 0.0f), + MakeVector(-0.2f, 0.0f), + }, 4), 1, PHYSICS_LAYER_COMBAT); + PhysicsEntity pe = Enemy_as_PhysicsEntity(self); + LOG_INFO("enemy instantiated mirroring as: %s", pe.mirror->get_typestring(pe.data)); sprite_set_origin(self->sprite, MakeVector(0.45f, 0.925f)); @@ -81,6 +91,8 @@ void EnemyStart(Enemy* self) {} void EnemyUpdate(Enemy* self, float deltaTime) { state_machine_update(self->behaviour, deltaTime); + if(self->stun_time > 0.0f) + self->stun_time -= deltaTime; } void EnemyDraw(Enemy* self) { @@ -116,8 +128,10 @@ int EnemyDamage(Enemy* self, DamageEventData* data) { game_world_destroy_entity(Enemy_as_BehaviourEntity(self)); return 1; } else { - self->hurt = 1; - self->facing = ((data->origin.x - self->transform.position.x) > 0) * 2 - 1; + self->stun_time = data->stun; + float direction = ((data->origin.x - self->transform.position.x) > 0) * 2 - 1; + self->facing = direction; + rigidbody_get_transform(self->rigidbody)->position = vaddf(self->transform.position, MakeVector(-direction * data->knockback, 0)); return 0; } } diff --git a/game/src/Enemy.h b/game/src/Enemy.h index 7bc4e25..af36694 100644 --- a/game/src/Enemy.h +++ b/game/src/Enemy.h @@ -22,11 +22,13 @@ typedef struct Enemy { RigidBody* rigidbody; Collider* collider; + Collider* hitbox; Sprite* sprite; - int hurt; int facing; + + float stun_time; AnimationSprite* idleAnim; AnimationSprite* walkAnim; diff --git a/game/src/EnemyStates.c b/game/src/EnemyStates.c index 9738f22..87559b7 100644 --- a/game/src/EnemyStates.c +++ b/game/src/EnemyStates.c @@ -10,7 +10,7 @@ void EnemyIdle_Enter(Enemy* self) { } const State* EnemyIdle_Update(Enemy* self, float deltaTime) { - if(self->hurt) + if(self->stun_time > 0.f) return EnemyHurt(); return EnemyIdle(); } @@ -25,15 +25,13 @@ const State* EnemyWalk_Update(Enemy* self, float deltaTime) { } void EnemyHurt_Enter(Enemy* self) { - self->hurt = 0; - self->currentAnimation = self->hurtAnim; animation_sprite_play_from(self->currentAnimation, 0.f); } const State* EnemyHurt_Update(Enemy* self, float deltaTime) { - const float ntime = animation_sprite_get_time_normalized(self->currentAnimation); - if(ntime > 1.0f) + const float time = animation_sprite_get_time(self->currentAnimation); + if(self->stun_time < 0.f) return EnemyIdle(); return EnemyHurt(); } diff --git a/game/src/Hurtbox.c b/game/src/Hurtbox.c new file mode 100644 index 0000000..2b41f17 --- /dev/null +++ b/game/src/Hurtbox.c @@ -0,0 +1,36 @@ +#include "Hurtbox.h" +#include "Damagable.h" +#include "transformable.h" +#include "transform.h" +#include "physics_entity.h" +#include "physics_world.h" +#include "collider.h" +#include "Layers.h" + +static inline +void Internal_HurtboxDealDamage(const Hurtbox* self, List* colliders, float min_y, float max_y) { + DamageEventData data = self->damage; + list_foreach(Collider**, collider, colliders) { + PhysicsEntity entity = collider_get_owner(*collider); + const IDamagable* damagable = mirror_get_typeclass(entity.data, entity.mirror, "Damagable"); + const Transform* transform = entity.transformable->get_transform(entity.data); + if(damagable && transform->position.y >= min_y && transform->position.y <= max_y) damagable->damage(entity.data, &data); + } +} + +int HurtboxCast(Hurtbox* self, float facing_dir) { + const IPhysicsEntity* physics_entity = mirror_get_typeclass(self->owner.data, self->owner.mirror, "PhysicsEntity"); + const ITransformable* transformable = mirror_get_typeclass(self->owner.data, self->owner.mirror, "Transformable"); + + if(physics_entity == NULL || transformable == NULL) + return -1; + + RigidBody* body = physics_entity->get_rigidbody(self->owner.data); + const Transform* transform = transformable->get_transform(self->owner.data); + self->damage.origin = transform->position; + + const Vector offset = vaddf(transform->position, MakeVector(facing_dir * self->offset.x, self->offset.y)); + List found = physics_world_box_query_all(offset, self->size, PHYSICS_LAYER_COMBAT, body); + Internal_HurtboxDealDamage(self, &found, transform->position.y - self->depth_extent, transform->position.y + self->depth_extent); + return found.len; +} diff --git a/game/src/Hurtbox.h b/game/src/Hurtbox.h new file mode 100644 index 0000000..c3cd3a2 --- /dev/null +++ b/game/src/Hurtbox.h @@ -0,0 +1,18 @@ +#ifndef FIGHT_HURTBOX_H +#define FIGHT_HURTBOX_H + +#include "Damagable.h" +#include "behaviour_entity.h" +#include "vmath.h" + +typedef struct Hurtbox { + BehaviourEntity owner; + DamageEventData damage; + Vector size; + Vector offset; + float depth_extent; +} Hurtbox; + +int HurtboxCast(Hurtbox* self, float facing_dir); + +#endif // !FIGHT_HURTBOX_H diff --git a/game/src/Player.c b/game/src/Player.c index fb074b9..592726a 100644 --- a/game/src/Player.c +++ b/game/src/Player.c @@ -13,6 +13,7 @@ START_REFLECT(Player) REFLECT_TYPECLASS(Player, Drop) REFLECT_TYPECLASS(Player, PhysicsEntity) REFLECT_TYPECLASS(Player, BehaviourEntity) + REFLECT_TYPECLASS(Player, Transformable) END_REFLECT(Player) impl_Drop_for(Player, @@ -61,6 +62,7 @@ Player* MakePlayer() { .rigidbody = NULL, .physicsCollider = NULL, + .hitbox = NULL, .playerInput = playerinput_new(self, -1), .moveInput = ZeroVector, @@ -86,7 +88,13 @@ Player* MakePlayer() { MakeVector( 0.2f, -0.065f), MakeVector( 0.2f, 0.065f), MakeVector(-0.2f, 0.065f) - }, 4), 0, PHYSICS_LAYER_DEFAULT | PHYSICS_LAYER_COMBAT); + }, 4), 0, PHYSICS_LAYER_DEFAULT); + self->hitbox = collider_new(Player_as_PhysicsEntity(self), shape_new((Vector[]){ + MakeVector(-0.2f, -0.95f), + MakeVector( 0.2f, -0.95f), + MakeVector( 0.2f, 0.00f), + MakeVector(-0.2f, 0.00f) + }, 3), 1, PHYSICS_LAYER_COMBAT); sprite_set_origin(self->sprite, MakeVector(0.45f, 0.925f)); @@ -128,6 +136,18 @@ void DestroyPlayer(Player* self) { state_machine_destroy(self->animationStateMachine); } +void PlayerStart(Player* self) { + animation_sprite_play_from(self->currentAnimation, 0.0f); +} + +void PlayerUpdate(Player* self, float deltaTime) { + state_machine_update(self->animationStateMachine, deltaTime); +} + +void PlayerDraw(Player* self) { + animation_sprite_draw(self->currentAnimation, &self->transform); +} + void PlayerHorizontalInput(Player* self, InputEvent value) { self->moveInput.x = value.as_float; } @@ -146,17 +166,8 @@ void PlayerHeavyAttackInput(Player* self, InputEvent value) { self->attackInput = 2; } -void PlayerStart(Player* self) { - animation_sprite_play_from(self->currentAnimation, 0.0f); -} - -void PlayerUpdate(Player* self, float deltaTime) { - state_machine_update(self->animationStateMachine, deltaTime); -} - -void PlayerDraw(Player* self) { - animation_sprite_draw(self->currentAnimation, &self->transform); -} +void PlayerOnCollision(Player* self, Collision collision) {} +void PlayerOnOverlap(Player* self, Collider* other) {} Transform* PlayerGetTransform(Player* self) { return &self->transform; @@ -165,6 +176,3 @@ Transform* PlayerGetTransform(Player* self) { RigidBody* PlayerGetRigidBody(Player* self) { return self->rigidbody; } - -void PlayerOnCollision(Player* self, Collision collision) {} -void PlayerOnOverlap(Player* self, Collider* other) {} diff --git a/game/src/Player.h b/game/src/Player.h index cc48776..fbec3b6 100644 --- a/game/src/Player.h +++ b/game/src/Player.h @@ -19,6 +19,7 @@ typedef struct Player { RigidBody* rigidbody; Collider* physicsCollider; + Collider* hitbox; PlayerInput* playerInput; @@ -29,6 +30,7 @@ typedef struct Player { int facing; Sprite* sprite; + Transform sprite_local_transform; AnimationSprite* idle; AnimationSprite* walk; @@ -45,21 +47,22 @@ Player* MakePlayer(); Player* SpawnPlayer(Vector location); void DestroyPlayer(Player* self); +void PlayerStart(Player* self); +void PlayerUpdate(Player* self, float deltaTime); +void PlayerDraw(Player* self); + void PlayerHorizontalInput(Player* self, InputEvent value); void PlayerVerticalInput(Player* self, InputEvent value); void PlayerLightAttackInput(Player* self, InputEvent value); void PlayerHeavyAttackInput(Player* self, InputEvent value); -void PlayerStart(Player* self); -void PlayerUpdate(Player* self, float deltaTime); -void PlayerDraw(Player* self); - -Transform* PlayerGetTransform(Player* self); - -RigidBody* PlayerGetRigidBody(Player* self); void PlayerOnCollision(Player* self, Collision collision); void PlayerOnOverlap(Player* self, Collider* other); +Transform* PlayerGetTransform(Player* self); +RigidBody* PlayerGetRigidBody(Player* self); + + static long PlayerGetDepth(Player* self) { return (int)(-10-self->transform.position.y * 1000); } DECL_REFLECT(Player); diff --git a/game/src/PlayerStates.c b/game/src/PlayerStates.c index 1089bc9..7e52fb6 100644 --- a/game/src/PlayerStates.c +++ b/game/src/PlayerStates.c @@ -1,10 +1,8 @@ #include "PlayerStates.h" -#include "mirror.h" -#include "physics_world.h" +#include "Hurtbox.h" #include "Damagable.h" #include "Player.h" -#include "Layers.h" static inline void InternalSpriteFlipWithMovement(Player* self) { @@ -60,17 +58,14 @@ void PlayerAttackEnter(Player* self) { static void PlayerHurtbox(Player* self, DamageEventData damage, Vector hitbox_size, Vector offset) { - offset.x *= self->facing; - offset = vaddf(self->transform.position, offset); - Collider* found = physics_world_box_query(offset, hitbox_size, PHYSICS_LAYER_COMBAT, self->rigidbody); - if(found != NULL) { - PhysicsEntity entity = collider_get_owner(found); - const IDamagable* damagable = mirror_get_typeclass(entity.data, entity.mirror, "Damagable"); - if(damagable) { - damage.origin = self->transform.position; - damagable->damage(entity.data, &damage); - } - } + Hurtbox box = { + .owner = Player_as_BehaviourEntity(self), + .damage = damage, + .size = hitbox_size, + .offset = offset, + .depth_extent = 0.15f, + }; + HurtboxCast(&box, self->facing); } void PlayerJabA_Enter(Player* self) { @@ -80,10 +75,15 @@ void PlayerJabA_Enter(Player* self) { } const State* PlayerJabA_Update(Player* self, float deltaTime) { - const static DamageEventData damage = {.damageAmount = 1}; + const static DamageEventData damage = { + .damageAmount = 1, + .knockdown = 0, + .stun = 0.1f, + .knockback = 0.05f, + }; const float ntime = animation_sprite_get_time_normalized(self->currentAnimation); if(self->animationTriggers == 0 && ntime > 0.33f) { - PlayerHurtbox(self, damage, MakeVector(0.1f, 0.06f), MakeVector(0.3f, 0.06f)); + PlayerHurtbox(self, damage, MakeVector(0.1f, 0.06f), MakeVector(0.3f, -0.6f)); ++self->animationTriggers; } if(ntime > 1.0f) { @@ -106,10 +106,15 @@ void PlayerJabB_Enter(Player* self) { } const State* PlayerJabB_Update(Player* self, float deltaTime) { - static const DamageEventData damage = {.damageAmount = 1}; + static const DamageEventData damage = { + .damageAmount = 1, + .knockdown = 0, + .stun = 0.1f, + .knockback = 0.05f, + }; const float ntime = animation_sprite_get_time_normalized(self->currentAnimation); if(self->animationTriggers == 0 && ntime > 0.33f) { - PlayerHurtbox(self, damage, MakeVector(0.1f, 0.06f), MakeVector(0.3f, 0.0f)); + PlayerHurtbox(self, damage, MakeVector(0.1f, 0.06f), MakeVector(0.3f, -0.6f)); ++self->animationTriggers; } if(ntime > 1.0f) { @@ -132,10 +137,15 @@ void PlayerKickA_Enter(Player* self) { } const State* PlayerKickA_Update(Player* self, float deltaTime) { - static const DamageEventData damage = {.damageAmount = 3}; + static const DamageEventData damage = { + .damageAmount = 3, + .knockdown = 1, + .stun = 0.5f, + .knockback = 0.15f, + }; const float ntime = animation_sprite_get_time_normalized(self->currentAnimation); if(ntime > 0.25f && self->animationTriggers == 0) { - PlayerHurtbox(self, damage, MakeVector(0.1f, 0.06f), MakeVector(0.3f, 0.0f)); + PlayerHurtbox(self, damage, MakeVector(0.1f, 0.06f), MakeVector(0.3f, -0.4f)); ++self->animationTriggers; } if(ntime > 1.0f && self->attackInput == 1)