完成土狼时间与无敌闪烁

This commit is contained in:
Ziyu
2025-06-16 14:44:47 +08:00
parent 2e0edb950c
commit c4afa83817
6 changed files with 75 additions and 7 deletions
+30 -1
View File
@@ -28,4 +28,33 @@
- **对象层物体特别注意:** 信息分散在两个区块中:
- 地图tmj中: 绘制区域、名字 (及针对当前地图添加的自定义属性)
- gid对应的图块集tsj中: 源图片信息 (画在任何地图上都会有的属性)
- gid对应的图块集tsj中: 源图片信息 (画在任何地图上都会有的属性)
# 地图自定义属性约定
- 限瓦片层
- unisolid (bool) : 单向平台
- ladder (bool) : 梯子
- slope (string) : 斜坡图块,格式"x_y"。x表示左边高度,y表示右边高度。范围0~1。(如果是2则表示1/2高度)
- 限对象层
- tag (string) : 对象类型,例如player,enemy,item
- gravity (bool) : 是否使用重力(有此字段则默认添加 PhysicsComponent)
- health (int) : 添加生命组件,生命值为 value
- animation (json_string) : 添加动画组件,json格式为:
```json
{
"name1" : {"duration" : int, "row" : int, "frames": array(int)},
"name2" : ...
}
```
含义为:
```json
{ "动画名" : {"帧持续时间" : ms, "行" : (从0开始数), "帧序列(列)": [0,1,2...]} }
```
要求每个动画序列帧必须在同一行。
- 图块碰撞编辑器:识别为碰撞盒,限一个图形,只支持矩形和圆形
- 两层皆可
- solid (bool) : 静止不可进入的图块/物体
- hazard (bool) : 对玩家造成伤害的瓦片
+2 -2
View File
@@ -126,8 +126,8 @@
"type":"",
"visible":true,
"width":32,
"x":482.643939393939,
"y":381.098484848485
"x":636.507575757576,
"y":157.962121212121
},
{
"gid":607,
+30
View File
@@ -81,6 +81,11 @@ void PlayerComponent::setState(std::unique_ptr<state::PlayerState> new_state) {
}
bool PlayerComponent::is_on_ground() const
{
return coyote_timer_ <= coyote_time_ || physics_component_->hasCollidedBelow();
}
void PlayerComponent::handleInput(engine::core::Context& context) {
if (!current_state_) return;
@@ -93,6 +98,31 @@ void PlayerComponent::handleInput(engine::core::Context& context) {
void PlayerComponent::update(float delta_time, engine::core::Context& context) {
if (!current_state_) return;
// 一旦离地,开始计时 Coyote Timer
if (!physics_component_->hasCollidedBelow()) {
coyote_timer_ += delta_time;
} else { // 如果碰撞到地面,重置 Coyote Timer
coyote_timer_ = 0.0f;
}
// 如果处于无敌状态,则进行闪烁
if (health_component_->isInvincible()) {
flash_timer_ += delta_time; // 闪烁计时器增加
if (flash_timer_ >= 2 * flash_interval_) {
flash_timer_ -= 2 * flash_interval_; // 闪烁计时器在 0~2倍闪烁间隔 中循环
}
// 一半时间可见,一半时间不可见。
if (flash_timer_ < flash_interval_) {
sprite_component_->setHidden(true);
} else {
sprite_component_->setHidden(false);
}
}
// 非无敌状态时确保精灵可见
else if (sprite_component_->isHidden()) {
sprite_component_->setHidden(false);
}
auto next_state = current_state_->update(delta_time, context);
if (next_state) {
setState(std::move(next_state));
+9
View File
@@ -46,6 +46,14 @@ private:
// --- 属性相关参数 ---
float stunned_duration_ = 0.4f; ///< @brief 玩家被击中后的硬直时间(单位:秒)
// 土狼时间(Coyote Time): 允许玩家在离地后短暂时间内仍然可以跳跃
static constexpr float coyote_time_ = 0.1f; ///< @brief Coyote Time (单位:秒)
float coyote_timer_ = 0.0f; ///< @brief Coyote Time 计时器
// 无敌闪烁时间
static constexpr float flash_interval_ = 0.1f; ///< @brief 闪烁间隔时间(单位:秒)
float flash_timer_ = 0.0f; ///< @brief 闪烁计时器,用于无敌状态下的闪烁效果
public:
PlayerComponent() = default;
~PlayerComponent() override = default;
@@ -81,6 +89,7 @@ public:
float getStunnedDuration() const { return stunned_duration_; } ///< @brief 获取硬直时间
void setState(std::unique_ptr<state::PlayerState> new_state); ///< @brief 切换玩家状态
bool is_on_ground() const; ///< @brief 检查玩家是否在地面上(考虑了Coyote Time)
private:
// 核心循环函数
+2 -2
View File
@@ -56,8 +56,8 @@ std::unique_ptr<PlayerState> IdleState::update(float, engine::core::Context&)
auto friction_factor = player_component_->getFrictionFactor();
physics_component->velocity_.x *= friction_factor;
// 如果下方没有碰撞,则切换到 FallState
if (!physics_component->hasCollidedBelow()) {
// 如果离地,则切换到 FallState
if (!player_component_->is_on_ground()) {
return std::make_unique<FallState>(player_component_);
}
return nullptr;
+2 -2
View File
@@ -67,8 +67,8 @@ std::unique_ptr<PlayerState> WalkState::update(float, engine::core::Context&)
auto max_speed = player_component_->getMaxSpeed();
physics_component->velocity_.x = glm::clamp(physics_component->velocity_.x, -max_speed, max_speed);
// 如果下方没有碰撞,则切换到 FallState
if (!physics_component->hasCollidedBelow()) {
// 如果离地,则切换到 FallState
if (!player_component_->is_on_ground()) {
return std::make_unique<FallState>(player_component_);
}