feat: separated combat and movement collision layers

This commit is contained in:
Sara 2024-01-14 22:15:10 +01:00
parent 8a05984afa
commit 46ef92ef92
9 changed files with 144 additions and 52 deletions

View file

@ -7,6 +7,9 @@
typedef struct DamageEventData {
int damageAmount;
int knockdown;
float stun;
float knockback;
Vector origin;
} DamageEventData;

View file

@ -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;
}
}

View file

@ -22,12 +22,14 @@ typedef struct Enemy {
RigidBody* rigidbody;
Collider* collider;
Collider* hitbox;
Sprite* sprite;
int hurt;
int facing;
float stun_time;
AnimationSprite* idleAnim;
AnimationSprite* walkAnim;
AnimationSprite* hurtAnim;

View file

@ -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();
}

36
game/src/Hurtbox.c Normal file
View file

@ -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;
}

18
game/src/Hurtbox.h Normal file
View file

@ -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

View file

@ -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) {}

View file

@ -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);

View file

@ -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)