完成土狼时间与无敌闪烁
This commit is contained in:
+30
-1
@@ -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) : 对玩家造成伤害的瓦片
|
||||
@@ -126,8 +126,8 @@
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":32,
|
||||
"x":482.643939393939,
|
||||
"y":381.098484848485
|
||||
"x":636.507575757576,
|
||||
"y":157.962121212121
|
||||
},
|
||||
{
|
||||
"gid":607,
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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:
|
||||
// 核心循环函数
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user