refactor: 重构项目结构,优化代码组织与文件布局
将源代码从Extra2D/src迁移到src目录,统一文件路径 更新xmake构建配置以适配新路径 清理冗余代码文件,合并重复实现 调整头文件包含路径,确保编译通过 优化过渡动画场景实现,移除不必要的动画效果
This commit is contained in:
parent
f9c8f080eb
commit
5039b1d9fc
|
|
@ -1,172 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <core/types.h>
|
||||
#include <functional>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class Node;
|
||||
|
||||
/**
|
||||
* @brief 动作状态枚举
|
||||
*/
|
||||
enum class ActionState {
|
||||
Idle,
|
||||
Running,
|
||||
Paused,
|
||||
Completed
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 动作基类
|
||||
*
|
||||
* 所有动作的基类,定义了动作的核心接口。
|
||||
* 动作用于修改 Node 的属性,实现动画效果。
|
||||
*/
|
||||
class Action {
|
||||
public:
|
||||
using CompletionCallback = std::function<void()>;
|
||||
|
||||
Action();
|
||||
virtual ~Action() = default;
|
||||
|
||||
Action(const Action&) = delete;
|
||||
Action& operator=(const Action&) = delete;
|
||||
Action(Action&&) = default;
|
||||
Action& operator=(Action&&) = default;
|
||||
|
||||
/**
|
||||
* @brief 检查动作是否完成
|
||||
* @return true 如果动作已完成
|
||||
*/
|
||||
virtual bool isDone() const;
|
||||
|
||||
/**
|
||||
* @brief 使用目标节点启动动作
|
||||
* @param target 目标节点
|
||||
*/
|
||||
virtual void startWithTarget(Node* target);
|
||||
|
||||
/**
|
||||
* @brief 停止动作
|
||||
*/
|
||||
virtual void stop();
|
||||
|
||||
/**
|
||||
* @brief 每帧调用的步进函数
|
||||
* @param dt 帧时间间隔
|
||||
*/
|
||||
virtual void step(float dt);
|
||||
|
||||
/**
|
||||
* @brief 更新动作状态
|
||||
* @param time 归一化时间 [0, 1]
|
||||
*/
|
||||
virtual void update(float time);
|
||||
|
||||
/**
|
||||
* @brief 克隆动作
|
||||
* @return 动作的深拷贝
|
||||
*/
|
||||
virtual Action* clone() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 创建反向动作
|
||||
* @return 反向动作
|
||||
*/
|
||||
virtual Action* reverse() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 暂停动作
|
||||
*/
|
||||
void pause();
|
||||
|
||||
/**
|
||||
* @brief 恢复动作
|
||||
*/
|
||||
void resume();
|
||||
|
||||
/**
|
||||
* @brief 重启动作
|
||||
*/
|
||||
void restart();
|
||||
|
||||
/**
|
||||
* @brief 设置完成回调
|
||||
* @param callback 回调函数
|
||||
*/
|
||||
void setCompletionCallback(const CompletionCallback& callback) {
|
||||
completionCallback_ = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取目标节点
|
||||
* @return 目标节点指针
|
||||
*/
|
||||
Node* getTarget() const { return target_; }
|
||||
|
||||
/**
|
||||
* @brief 获取原始目标节点
|
||||
* @return 原始目标节点指针
|
||||
*/
|
||||
Node* getOriginalTarget() const { return originalTarget_; }
|
||||
|
||||
/**
|
||||
* @brief 获取动作状态
|
||||
* @return 当前状态
|
||||
*/
|
||||
ActionState getState() const { return state_; }
|
||||
|
||||
/**
|
||||
* @brief 获取标签
|
||||
* @return 标签值
|
||||
*/
|
||||
int getTag() const { return tag_; }
|
||||
|
||||
/**
|
||||
* @brief 设置标签
|
||||
* @param tag 标签值
|
||||
*/
|
||||
void setTag(int tag) { tag_ = tag; }
|
||||
|
||||
/**
|
||||
* @brief 获取标志位
|
||||
* @return 标志位
|
||||
*/
|
||||
unsigned int getFlags() const { return flags_; }
|
||||
|
||||
/**
|
||||
* @brief 设置标志位
|
||||
* @param flags 标志位
|
||||
*/
|
||||
void setFlags(unsigned int flags) { flags_ = flags; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief 动作开始时调用
|
||||
*/
|
||||
virtual void onStart() {}
|
||||
|
||||
/**
|
||||
* @brief 动作完成时调用
|
||||
*/
|
||||
virtual void onComplete() {
|
||||
if (completionCallback_) {
|
||||
completionCallback_();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置动作完成状态
|
||||
*/
|
||||
void setDone() { state_ = ActionState::Completed; }
|
||||
|
||||
Node* target_ = nullptr;
|
||||
Node* originalTarget_ = nullptr;
|
||||
ActionState state_ = ActionState::Idle;
|
||||
int tag_ = -1;
|
||||
unsigned int flags_ = 0;
|
||||
CompletionCallback completionCallback_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,344 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <action/action_interval.h>
|
||||
#include <action/ease.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 缓动动作基类
|
||||
*
|
||||
* 使用装饰器模式包装其他动作,实现缓动效果。
|
||||
*/
|
||||
class ActionEase : public ActionInterval {
|
||||
public:
|
||||
virtual ~ActionEase();
|
||||
|
||||
/**
|
||||
* @brief 获取内部动作
|
||||
* @return 内部动作指针
|
||||
*/
|
||||
ActionInterval* getInnerAction() const { return innerAction_; }
|
||||
|
||||
void startWithTarget(Node* target) override;
|
||||
void stop() override;
|
||||
void update(float time) override;
|
||||
ActionInterval* clone() const override = 0;
|
||||
ActionInterval* reverse() const override = 0;
|
||||
|
||||
protected:
|
||||
ActionEase() = default;
|
||||
bool initWithAction(ActionInterval* action);
|
||||
void onUpdate(float progress) override {}
|
||||
|
||||
ActionInterval* innerAction_ = nullptr;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 指数缓动
|
||||
// ============================================================================
|
||||
|
||||
class EaseExponentialIn : public ActionEase {
|
||||
public:
|
||||
static EaseExponentialIn* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseExponentialOut : public ActionEase {
|
||||
public:
|
||||
static EaseExponentialOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseExponentialInOut : public ActionEase {
|
||||
public:
|
||||
static EaseExponentialInOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 正弦缓动
|
||||
// ============================================================================
|
||||
|
||||
class EaseSineIn : public ActionEase {
|
||||
public:
|
||||
static EaseSineIn* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseSineOut : public ActionEase {
|
||||
public:
|
||||
static EaseSineOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseSineInOut : public ActionEase {
|
||||
public:
|
||||
static EaseSineInOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 弹性缓动
|
||||
// ============================================================================
|
||||
|
||||
class EaseElasticIn : public ActionEase {
|
||||
public:
|
||||
static EaseElasticIn* create(ActionInterval* action, float period = 0.3f);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
|
||||
protected:
|
||||
float period_ = 0.3f;
|
||||
};
|
||||
|
||||
class EaseElasticOut : public ActionEase {
|
||||
public:
|
||||
static EaseElasticOut* create(ActionInterval* action, float period = 0.3f);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
|
||||
protected:
|
||||
float period_ = 0.3f;
|
||||
};
|
||||
|
||||
class EaseElasticInOut : public ActionEase {
|
||||
public:
|
||||
static EaseElasticInOut* create(ActionInterval* action, float period = 0.3f);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
|
||||
protected:
|
||||
float period_ = 0.3f;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 弹跳缓动
|
||||
// ============================================================================
|
||||
|
||||
class EaseBounceIn : public ActionEase {
|
||||
public:
|
||||
static EaseBounceIn* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseBounceOut : public ActionEase {
|
||||
public:
|
||||
static EaseBounceOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseBounceInOut : public ActionEase {
|
||||
public:
|
||||
static EaseBounceInOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 回震缓动
|
||||
// ============================================================================
|
||||
|
||||
class EaseBackIn : public ActionEase {
|
||||
public:
|
||||
static EaseBackIn* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseBackOut : public ActionEase {
|
||||
public:
|
||||
static EaseBackOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseBackInOut : public ActionEase {
|
||||
public:
|
||||
static EaseBackInOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 二次缓动
|
||||
// ============================================================================
|
||||
|
||||
class EaseQuadIn : public ActionEase {
|
||||
public:
|
||||
static EaseQuadIn* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseQuadOut : public ActionEase {
|
||||
public:
|
||||
static EaseQuadOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseQuadInOut : public ActionEase {
|
||||
public:
|
||||
static EaseQuadInOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 三次缓动
|
||||
// ============================================================================
|
||||
|
||||
class EaseCubicIn : public ActionEase {
|
||||
public:
|
||||
static EaseCubicIn* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseCubicOut : public ActionEase {
|
||||
public:
|
||||
static EaseCubicOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseCubicInOut : public ActionEase {
|
||||
public:
|
||||
static EaseCubicInOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 四次缓动
|
||||
// ============================================================================
|
||||
|
||||
class EaseQuartIn : public ActionEase {
|
||||
public:
|
||||
static EaseQuartIn* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseQuartOut : public ActionEase {
|
||||
public:
|
||||
static EaseQuartOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseQuartInOut : public ActionEase {
|
||||
public:
|
||||
static EaseQuartInOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 五次缓动
|
||||
// ============================================================================
|
||||
|
||||
class EaseQuintIn : public ActionEase {
|
||||
public:
|
||||
static EaseQuintIn* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseQuintOut : public ActionEase {
|
||||
public:
|
||||
static EaseQuintOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseQuintInOut : public ActionEase {
|
||||
public:
|
||||
static EaseQuintInOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 圆形缓动
|
||||
// ============================================================================
|
||||
|
||||
class EaseCircleIn : public ActionEase {
|
||||
public:
|
||||
static EaseCircleIn* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseCircleOut : public ActionEase {
|
||||
public:
|
||||
static EaseCircleOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
class EaseCircleInOut : public ActionEase {
|
||||
public:
|
||||
static EaseCircleInOut* create(ActionInterval* action);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 自定义缓动
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 自定义缓动动作
|
||||
*/
|
||||
class EaseCustom : public ActionEase {
|
||||
public:
|
||||
static EaseCustom* create(ActionInterval* action, EaseFunction easeFunc);
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
void update(float time) override;
|
||||
|
||||
protected:
|
||||
EaseFunction easeFunc_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <action/finite_time_action.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 瞬时动作基类
|
||||
*
|
||||
* 瞬间完成的动作,中间没有任何动画效果。
|
||||
* 继承自 FiniteTimeAction,持续时间为 0。
|
||||
*/
|
||||
class ActionInstant : public FiniteTimeAction {
|
||||
public:
|
||||
ActionInstant();
|
||||
virtual ~ActionInstant() = default;
|
||||
|
||||
/**
|
||||
* @brief 检查动作是否完成
|
||||
* @return 总是返回 true
|
||||
*/
|
||||
bool isDone() const override;
|
||||
|
||||
/**
|
||||
* @brief 使用目标节点启动动作
|
||||
* @param target 目标节点
|
||||
*/
|
||||
void startWithTarget(Node* target) override;
|
||||
|
||||
/**
|
||||
* @brief 每帧调用的步进函数
|
||||
* @param dt 帧时间间隔
|
||||
*/
|
||||
void step(float dt) override;
|
||||
|
||||
/**
|
||||
* @brief 克隆动作
|
||||
* @return 动作的深拷贝
|
||||
*/
|
||||
ActionInstant* clone() const override = 0;
|
||||
|
||||
/**
|
||||
* @brief 创建反向动作
|
||||
* @return 反向动作
|
||||
*/
|
||||
ActionInstant* reverse() const override = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief 执行瞬时动作
|
||||
*/
|
||||
virtual void execute() = 0;
|
||||
|
||||
bool done_ = false;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <action/action_instant.h>
|
||||
#include <core/math_types.h>
|
||||
#include <functional>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 回调动作
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 无参数回调动作
|
||||
*/
|
||||
class CallFunc : public ActionInstant {
|
||||
public:
|
||||
using Callback = std::function<void()>;
|
||||
|
||||
static CallFunc* create(const Callback& callback);
|
||||
|
||||
ActionInstant* clone() const override;
|
||||
ActionInstant* reverse() const override;
|
||||
|
||||
protected:
|
||||
void execute() override;
|
||||
|
||||
Callback callback_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 带节点参数的回调动作
|
||||
*/
|
||||
class CallFuncN : public ActionInstant {
|
||||
public:
|
||||
using Callback = std::function<void(Node*)>;
|
||||
|
||||
static CallFuncN* create(const Callback& callback);
|
||||
|
||||
ActionInstant* clone() const override;
|
||||
ActionInstant* reverse() const override;
|
||||
|
||||
protected:
|
||||
void execute() override;
|
||||
|
||||
Callback callback_;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 位置动作
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 瞬间放置到指定位置
|
||||
*/
|
||||
class Place : public ActionInstant {
|
||||
public:
|
||||
static Place* create(const Vec2& position);
|
||||
|
||||
ActionInstant* clone() const override;
|
||||
ActionInstant* reverse() const override;
|
||||
|
||||
protected:
|
||||
void execute() override;
|
||||
|
||||
Vec2 position_;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 翻转动作
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief X轴翻转动作
|
||||
*/
|
||||
class FlipX : public ActionInstant {
|
||||
public:
|
||||
static FlipX* create(bool flipX);
|
||||
|
||||
ActionInstant* clone() const override;
|
||||
ActionInstant* reverse() const override;
|
||||
|
||||
protected:
|
||||
void execute() override;
|
||||
|
||||
bool flipX_ = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Y轴翻转动作
|
||||
*/
|
||||
class FlipY : public ActionInstant {
|
||||
public:
|
||||
static FlipY* create(bool flipY);
|
||||
|
||||
ActionInstant* clone() const override;
|
||||
ActionInstant* reverse() const override;
|
||||
|
||||
protected:
|
||||
void execute() override;
|
||||
|
||||
bool flipY_ = false;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 可见性动作
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 显示动作
|
||||
*/
|
||||
class Show : public ActionInstant {
|
||||
public:
|
||||
static Show* create();
|
||||
|
||||
ActionInstant* clone() const override;
|
||||
ActionInstant* reverse() const override;
|
||||
|
||||
protected:
|
||||
void execute() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 隐藏动作
|
||||
*/
|
||||
class Hide : public ActionInstant {
|
||||
public:
|
||||
static Hide* create();
|
||||
|
||||
ActionInstant* clone() const override;
|
||||
ActionInstant* reverse() const override;
|
||||
|
||||
protected:
|
||||
void execute() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 切换可见性动作
|
||||
*/
|
||||
class ToggleVisibility : public ActionInstant {
|
||||
public:
|
||||
static ToggleVisibility* create();
|
||||
|
||||
ActionInstant* clone() const override;
|
||||
ActionInstant* reverse() const override;
|
||||
|
||||
protected:
|
||||
void execute() override;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 节点管理动作
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 移除自身动作
|
||||
*/
|
||||
class RemoveSelf : public ActionInstant {
|
||||
public:
|
||||
static RemoveSelf* create();
|
||||
|
||||
ActionInstant* clone() const override;
|
||||
ActionInstant* reverse() const override;
|
||||
|
||||
protected:
|
||||
void execute() override;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <action/finite_time_action.h>
|
||||
#include <action/ease.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 时间间隔动作基类
|
||||
*
|
||||
* 在指定时间内完成的动作,中间会有动画效果。
|
||||
* 继承自 FiniteTimeAction。
|
||||
*/
|
||||
class ActionInterval : public FiniteTimeAction {
|
||||
public:
|
||||
ActionInterval() = default;
|
||||
explicit ActionInterval(float duration);
|
||||
virtual ~ActionInterval() = default;
|
||||
|
||||
/**
|
||||
* @brief 获取已流逝时间
|
||||
* @return 已流逝时间(秒)
|
||||
*/
|
||||
float getElapsed() const { return elapsed_; }
|
||||
|
||||
/**
|
||||
* @brief 检查动作是否完成
|
||||
* @return true 如果动作已完成
|
||||
*/
|
||||
bool isDone() const override;
|
||||
|
||||
/**
|
||||
* @brief 使用目标节点启动动作
|
||||
* @param target 目标节点
|
||||
*/
|
||||
void startWithTarget(Node* target) override;
|
||||
|
||||
/**
|
||||
* @brief 停止动作
|
||||
*/
|
||||
void stop() override;
|
||||
|
||||
/**
|
||||
* @brief 每帧调用的步进函数
|
||||
* @param dt 帧时间间隔
|
||||
*/
|
||||
void step(float dt) override;
|
||||
|
||||
/**
|
||||
* @brief 设置振幅比率(用于缓动)
|
||||
* @param amp 振幅比率
|
||||
*/
|
||||
void setAmplitudeRate(float amp) { amplitudeRate_ = amp; }
|
||||
|
||||
/**
|
||||
* @brief 获取振幅比率
|
||||
* @return 振幅比率
|
||||
*/
|
||||
float getAmplitudeRate() const { return amplitudeRate_; }
|
||||
|
||||
/**
|
||||
* @brief 设置内置缓动函数
|
||||
* @param easeFunc 缓动函数
|
||||
*/
|
||||
void setEaseFunction(EaseFunction easeFunc) { easeFunc_ = easeFunc; }
|
||||
|
||||
/**
|
||||
* @brief 获取内置缓动函数
|
||||
* @return 缓动函数
|
||||
*/
|
||||
EaseFunction getEaseFunction() const { return easeFunc_; }
|
||||
|
||||
/**
|
||||
* @brief 克隆动作
|
||||
* @return 动作的深拷贝
|
||||
*/
|
||||
ActionInterval* clone() const override = 0;
|
||||
|
||||
/**
|
||||
* @brief 创建反向动作
|
||||
* @return 反向动作
|
||||
*/
|
||||
ActionInterval* reverse() const override = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief 动作开始时调用
|
||||
*/
|
||||
virtual void onStart() {}
|
||||
|
||||
/**
|
||||
* @brief 动作更新时调用
|
||||
* @param progress 归一化进度 [0, 1]
|
||||
*/
|
||||
virtual void onUpdate(float progress) = 0;
|
||||
|
||||
float elapsed_ = 0.0f;
|
||||
bool firstTick_ = true;
|
||||
float amplitudeRate_ = 1.0f;
|
||||
EaseFunction easeFunc_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,469 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <action/action_interval.h>
|
||||
#include <core/math_types.h>
|
||||
#include <core/color.h>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 移动动作
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 相对移动动作
|
||||
*/
|
||||
class MoveBy : public ActionInterval {
|
||||
public:
|
||||
static MoveBy* create(float duration, const Vec2& delta);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
Vec2 delta_;
|
||||
Vec2 startPosition_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 绝对移动动作
|
||||
*/
|
||||
class MoveTo : public ActionInterval {
|
||||
public:
|
||||
static MoveTo* create(float duration, const Vec2& position);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
Vec2 endPosition_;
|
||||
Vec2 startPosition_;
|
||||
Vec2 delta_;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 跳跃动作
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 相对跳跃动作
|
||||
*/
|
||||
class JumpBy : public ActionInterval {
|
||||
public:
|
||||
static JumpBy* create(float duration, const Vec2& position, float height, int jumps);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
Vec2 startPosition_;
|
||||
Vec2 delta_;
|
||||
float height_ = 0.0f;
|
||||
int jumps_ = 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 绝对跳跃动作
|
||||
*/
|
||||
class JumpTo : public JumpBy {
|
||||
public:
|
||||
static JumpTo* create(float duration, const Vec2& position, float height, int jumps);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
|
||||
Vec2 endPosition_;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 贝塞尔曲线动作
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 贝塞尔曲线配置
|
||||
*/
|
||||
struct BezierConfig {
|
||||
Vec2 controlPoint1;
|
||||
Vec2 controlPoint2;
|
||||
Vec2 endPosition;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 相对贝塞尔曲线动作
|
||||
*/
|
||||
class BezierBy : public ActionInterval {
|
||||
public:
|
||||
static BezierBy* create(float duration, const BezierConfig& config);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
static float bezierat(float a, float b, float c, float d, float t);
|
||||
|
||||
BezierConfig config_;
|
||||
Vec2 startPosition_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 绝对贝塞尔曲线动作
|
||||
*/
|
||||
class BezierTo : public BezierBy {
|
||||
public:
|
||||
static BezierTo* create(float duration, const BezierConfig& config);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
|
||||
BezierConfig originalConfig_;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 缩放动作
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 相对缩放动作
|
||||
*/
|
||||
class ScaleBy : public ActionInterval {
|
||||
public:
|
||||
static ScaleBy* create(float duration, float scale);
|
||||
static ScaleBy* create(float duration, float scaleX, float scaleY);
|
||||
static ScaleBy* create(float duration, const Vec2& scale);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
Vec2 deltaScale_;
|
||||
Vec2 startScale_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 绝对缩放动作
|
||||
*/
|
||||
class ScaleTo : public ActionInterval {
|
||||
public:
|
||||
static ScaleTo* create(float duration, float scale);
|
||||
static ScaleTo* create(float duration, float scaleX, float scaleY);
|
||||
static ScaleTo* create(float duration, const Vec2& scale);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
Vec2 endScale_;
|
||||
Vec2 startScale_;
|
||||
Vec2 delta_;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 旋转动作
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 相对旋转动作
|
||||
*/
|
||||
class RotateBy : public ActionInterval {
|
||||
public:
|
||||
static RotateBy* create(float duration, float deltaAngle);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
float deltaAngle_ = 0.0f;
|
||||
float startAngle_ = 0.0f;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 绝对旋转动作
|
||||
*/
|
||||
class RotateTo : public ActionInterval {
|
||||
public:
|
||||
static RotateTo* create(float duration, float angle);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
float endAngle_ = 0.0f;
|
||||
float startAngle_ = 0.0f;
|
||||
float deltaAngle_ = 0.0f;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 淡入淡出动作
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 淡入动作
|
||||
*/
|
||||
class FadeIn : public ActionInterval {
|
||||
public:
|
||||
static FadeIn* create(float duration);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
float startOpacity_ = 0.0f;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 淡出动作
|
||||
*/
|
||||
class FadeOut : public ActionInterval {
|
||||
public:
|
||||
static FadeOut* create(float duration);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
float startOpacity_ = 0.0f;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 淡入到指定透明度动作
|
||||
*/
|
||||
class FadeTo : public ActionInterval {
|
||||
public:
|
||||
static FadeTo* create(float duration, float opacity);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
float endOpacity_ = 0.0f;
|
||||
float startOpacity_ = 0.0f;
|
||||
float deltaOpacity_ = 0.0f;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 闪烁动作
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 闪烁动作
|
||||
*/
|
||||
class Blink : public ActionInterval {
|
||||
public:
|
||||
static Blink* create(float duration, int times);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
int times_ = 1;
|
||||
int currentTimes_ = 0;
|
||||
bool originalVisible_ = true;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 色调动作
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 色调变化动作
|
||||
*/
|
||||
class TintTo : public ActionInterval {
|
||||
public:
|
||||
static TintTo* create(float duration, uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
Color3B startColor_;
|
||||
Color3B endColor_;
|
||||
Color3B deltaColor_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 相对色调变化动作
|
||||
*/
|
||||
class TintBy : public ActionInterval {
|
||||
public:
|
||||
static TintBy* create(float duration, int16_t deltaRed, int16_t deltaGreen, int16_t deltaBlue);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
Color3B startColor_;
|
||||
int16_t deltaR_ = 0;
|
||||
int16_t deltaG_ = 0;
|
||||
int16_t deltaB_ = 0;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 组合动作
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 序列动作
|
||||
*/
|
||||
class Sequence : public ActionInterval {
|
||||
public:
|
||||
static Sequence* create(ActionInterval* action1, ...);
|
||||
static Sequence* create(const std::vector<ActionInterval*>& actions);
|
||||
|
||||
~Sequence();
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
std::vector<ActionInterval*> actions_;
|
||||
size_t currentIndex_ = 0;
|
||||
float split_ = 0.0f;
|
||||
float last_ = -1.0f;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 并行动作
|
||||
*/
|
||||
class Spawn : public ActionInterval {
|
||||
public:
|
||||
static Spawn* create(ActionInterval* action1, ...);
|
||||
static Spawn* create(const std::vector<ActionInterval*>& actions);
|
||||
|
||||
~Spawn();
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
std::vector<ActionInterval*> actions_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 重复动作
|
||||
*/
|
||||
class Repeat : public ActionInterval {
|
||||
public:
|
||||
static Repeat* create(ActionInterval* action, int times);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
bool isDone() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
ActionInterval* innerAction_ = nullptr;
|
||||
int times_ = 1;
|
||||
int currentTimes_ = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 永久重复动作
|
||||
*/
|
||||
class RepeatForever : public ActionInterval {
|
||||
public:
|
||||
static RepeatForever* create(ActionInterval* action);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
bool isDone() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
ActionInterval* innerAction_ = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 延时动作
|
||||
*/
|
||||
class DelayTime : public ActionInterval {
|
||||
public:
|
||||
static DelayTime* create(float duration);
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onUpdate(float progress) override {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 反向时间动作
|
||||
*/
|
||||
class ReverseTime : public ActionInterval {
|
||||
public:
|
||||
static ReverseTime* create(ActionInterval* action);
|
||||
|
||||
~ReverseTime();
|
||||
|
||||
ActionInterval* clone() const override;
|
||||
ActionInterval* reverse() const override;
|
||||
|
||||
protected:
|
||||
void onStart() override;
|
||||
void onUpdate(float progress) override;
|
||||
|
||||
ActionInterval* innerAction_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <action/action.h>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 动作管理器
|
||||
*
|
||||
* 单例模式,集中管理所有动作的调度和生命周期。
|
||||
* 负责动作的添加、移除、暂停、恢复和更新。
|
||||
*/
|
||||
class ActionManager {
|
||||
public:
|
||||
/**
|
||||
* @brief 获取单例实例
|
||||
* @return ActionManager 实例指针
|
||||
*/
|
||||
static ActionManager* getInstance();
|
||||
|
||||
/**
|
||||
* @brief 销毁单例实例
|
||||
*/
|
||||
static void destroyInstance();
|
||||
|
||||
/**
|
||||
* @brief 添加动作到管理器
|
||||
* @param action 动作指针
|
||||
* @param target 目标节点
|
||||
* @param paused 是否暂停
|
||||
*/
|
||||
void addAction(Action* action, Node* target, bool paused = false);
|
||||
|
||||
/**
|
||||
* @brief 移除指定动作
|
||||
* @param action 动作指针
|
||||
*/
|
||||
void removeAction(Action* action);
|
||||
|
||||
/**
|
||||
* @brief 根据标签移除动作
|
||||
* @param tag 标签值
|
||||
* @param target 目标节点
|
||||
*/
|
||||
void removeActionByTag(int tag, Node* target);
|
||||
|
||||
/**
|
||||
* @brief 根据标志位移除动作
|
||||
* @param flags 标志位
|
||||
* @param target 目标节点
|
||||
*/
|
||||
void removeActionsByFlags(unsigned int flags, Node* target);
|
||||
|
||||
/**
|
||||
* @brief 移除目标节点的所有动作
|
||||
* @param target 目标节点
|
||||
*/
|
||||
void removeAllActionsFromTarget(Node* target);
|
||||
|
||||
/**
|
||||
* @brief 移除所有动作
|
||||
*/
|
||||
void removeAllActions();
|
||||
|
||||
/**
|
||||
* @brief 根据标签获取动作
|
||||
* @param tag 标签值
|
||||
* @param target 目标节点
|
||||
* @return 动作指针,未找到返回 nullptr
|
||||
*/
|
||||
Action* getActionByTag(int tag, Node* target);
|
||||
|
||||
/**
|
||||
* @brief 获取目标节点的动作数量
|
||||
* @param target 目标节点
|
||||
* @return 动作数量
|
||||
*/
|
||||
size_t getActionCount(Node* target) const;
|
||||
|
||||
/**
|
||||
* @brief 暂停目标节点的所有动作
|
||||
* @param target 目标节点
|
||||
*/
|
||||
void pauseTarget(Node* target);
|
||||
|
||||
/**
|
||||
* @brief 恢复目标节点的所有动作
|
||||
* @param target 目标节点
|
||||
*/
|
||||
void resumeTarget(Node* target);
|
||||
|
||||
/**
|
||||
* @brief 检查目标节点是否暂停
|
||||
* @param target 目标节点
|
||||
* @return true 如果暂停
|
||||
*/
|
||||
bool isPaused(Node* target) const;
|
||||
|
||||
/**
|
||||
* @brief 更新所有动作(每帧调用)
|
||||
* @param dt 帧时间间隔
|
||||
*/
|
||||
void update(float dt);
|
||||
|
||||
private:
|
||||
ActionManager();
|
||||
~ActionManager();
|
||||
|
||||
struct ActionElement {
|
||||
std::vector<Action*> actions;
|
||||
Node* target = nullptr;
|
||||
bool paused = false;
|
||||
int actionIndex = 0;
|
||||
Action* currentAction = nullptr;
|
||||
bool currentActionSalvaged = false;
|
||||
};
|
||||
|
||||
using ActionMap = std::unordered_map<Node*, ActionElement>;
|
||||
|
||||
void removeActionAt(size_t index, ActionElement& element);
|
||||
void deleteAction(Action* action);
|
||||
|
||||
ActionMap targets_;
|
||||
static ActionManager* instance_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <action/action.h>
|
||||
#include <action/action_interval.h>
|
||||
#include <core/math_types.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 速度控制动作
|
||||
*
|
||||
* 包装其他动作,实现动态速度控制。
|
||||
* 可以在运行时调整动作的播放速度。
|
||||
*/
|
||||
class Speed : public Action {
|
||||
public:
|
||||
/**
|
||||
* @brief 创建速度控制动作
|
||||
* @param action 内部动作
|
||||
* @param speed 速度倍率(1.0 为正常速度)
|
||||
* @return 动作指针
|
||||
*/
|
||||
static Speed* create(ActionInterval* action, float speed);
|
||||
|
||||
~Speed();
|
||||
|
||||
/**
|
||||
* @brief 获取速度倍率
|
||||
* @return 速度倍率
|
||||
*/
|
||||
float getSpeed() const { return speed_; }
|
||||
|
||||
/**
|
||||
* @brief 设置速度倍率
|
||||
* @param speed 速度倍率
|
||||
*/
|
||||
void setSpeed(float speed) { speed_ = speed; }
|
||||
|
||||
/**
|
||||
* @brief 获取内部动作
|
||||
* @return 内部动作指针
|
||||
*/
|
||||
ActionInterval* getInnerAction() const { return innerAction_; }
|
||||
|
||||
void startWithTarget(Node* target) override;
|
||||
void stop() override;
|
||||
void step(float dt) override;
|
||||
bool isDone() const override;
|
||||
Action* clone() const override;
|
||||
Action* reverse() const override;
|
||||
|
||||
protected:
|
||||
Speed() = default;
|
||||
|
||||
ActionInterval* innerAction_ = nullptr;
|
||||
float speed_ = 1.0f;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 跟随动作
|
||||
*
|
||||
* 使节点跟随另一个节点移动。
|
||||
* 常用于相机跟随玩家。
|
||||
*/
|
||||
class Follow : public Action {
|
||||
public:
|
||||
/**
|
||||
* @brief 创建跟随动作
|
||||
* @param followedNode 被跟随的节点
|
||||
* @return 动作指针
|
||||
*/
|
||||
static Follow* create(Node* followedNode);
|
||||
|
||||
/**
|
||||
* @brief 创建带边界的跟随动作
|
||||
* @param followedNode 被跟随的节点
|
||||
* @param boundary 边界矩形
|
||||
* @return 动作指针
|
||||
*/
|
||||
static Follow* create(Node* followedNode, const Rect& boundary);
|
||||
|
||||
~Follow();
|
||||
|
||||
/**
|
||||
* @brief 获取被跟随的节点
|
||||
* @return 被跟随的节点指针
|
||||
*/
|
||||
Node* getFollowedNode() const { return followedNode_; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否设置了边界
|
||||
* @return true 如果设置了边界
|
||||
*/
|
||||
bool isBoundarySet() const { return boundarySet_; }
|
||||
|
||||
void startWithTarget(Node* target) override;
|
||||
void stop() override;
|
||||
void step(float dt) override;
|
||||
bool isDone() const override;
|
||||
Action* clone() const override;
|
||||
Action* reverse() const override;
|
||||
|
||||
protected:
|
||||
Follow() = default;
|
||||
|
||||
Node* followedNode_ = nullptr;
|
||||
Rect boundary_;
|
||||
bool boundarySet_ = false;
|
||||
Vec2 halfScreenSize_;
|
||||
Vec2 fullScreenSize_;
|
||||
Vec2 leftBoundary_;
|
||||
Vec2 rightBoundary_;
|
||||
Vec2 topBoundary_;
|
||||
Vec2 bottomBoundary_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 目标动作
|
||||
*
|
||||
* 允许在一个节点上运行动作,但目标为另一个节点。
|
||||
*/
|
||||
class TargetedAction : public Action {
|
||||
public:
|
||||
/**
|
||||
* @brief 创建目标动作
|
||||
* @param target 目标节点
|
||||
* @param action 要运行的动作
|
||||
* @return 动作指针
|
||||
*/
|
||||
static TargetedAction* create(Node* target, FiniteTimeAction* action);
|
||||
|
||||
~TargetedAction();
|
||||
|
||||
/**
|
||||
* @brief 获取目标节点
|
||||
* @return 目标节点指针
|
||||
*/
|
||||
Node* getTargetNode() const { return targetNode_; }
|
||||
|
||||
/**
|
||||
* @brief 设置目标节点
|
||||
* @param target 目标节点
|
||||
*/
|
||||
void setTargetNode(Node* target) { targetNode_ = target; }
|
||||
|
||||
/**
|
||||
* @brief 获取内部动作
|
||||
* @return 内部动作指针
|
||||
*/
|
||||
FiniteTimeAction* getAction() const { return innerAction_; }
|
||||
|
||||
void startWithTarget(Node* target) override;
|
||||
void stop() override;
|
||||
void step(float dt) override;
|
||||
bool isDone() const override;
|
||||
Action* clone() const override;
|
||||
Action* reverse() const override;
|
||||
|
||||
protected:
|
||||
TargetedAction() = default;
|
||||
|
||||
Node* targetNode_ = nullptr;
|
||||
FiniteTimeAction* innerAction_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 缓动函数类型
|
||||
*/
|
||||
using EaseFunction = float (*)(float);
|
||||
|
||||
// ============================================================================
|
||||
// 线性缓动
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 线性缓动(无缓动)
|
||||
* @param t 归一化时间 [0, 1]
|
||||
* @return 缓动后的值
|
||||
*/
|
||||
float easeLinear(float t);
|
||||
|
||||
// ============================================================================
|
||||
// 二次缓动 (Quad)
|
||||
// ============================================================================
|
||||
|
||||
float easeInQuad(float t);
|
||||
float easeOutQuad(float t);
|
||||
float easeInOutQuad(float t);
|
||||
|
||||
// ============================================================================
|
||||
// 三次缓动 (Cubic)
|
||||
// ============================================================================
|
||||
|
||||
float easeInCubic(float t);
|
||||
float easeOutCubic(float t);
|
||||
float easeInOutCubic(float t);
|
||||
|
||||
// ============================================================================
|
||||
// 四次缓动 (Quart)
|
||||
// ============================================================================
|
||||
|
||||
float easeInQuart(float t);
|
||||
float easeOutQuart(float t);
|
||||
float easeInOutQuart(float t);
|
||||
|
||||
// ============================================================================
|
||||
// 五次缓动 (Quint)
|
||||
// ============================================================================
|
||||
|
||||
float easeInQuint(float t);
|
||||
float easeOutQuint(float t);
|
||||
float easeInOutQuint(float t);
|
||||
|
||||
// ============================================================================
|
||||
// 正弦缓动 (Sine)
|
||||
// ============================================================================
|
||||
|
||||
float easeInSine(float t);
|
||||
float easeOutSine(float t);
|
||||
float easeInOutSine(float t);
|
||||
|
||||
// ============================================================================
|
||||
// 指数缓动 (Exponential)
|
||||
// ============================================================================
|
||||
|
||||
float easeInExpo(float t);
|
||||
float easeOutExpo(float t);
|
||||
float easeInOutExpo(float t);
|
||||
|
||||
// ============================================================================
|
||||
// 圆形缓动 (Circular)
|
||||
// ============================================================================
|
||||
|
||||
float easeInCirc(float t);
|
||||
float easeOutCirc(float t);
|
||||
float easeInOutCirc(float t);
|
||||
|
||||
// ============================================================================
|
||||
// 回震缓动 (Back)
|
||||
// ============================================================================
|
||||
|
||||
float easeInBack(float t);
|
||||
float easeOutBack(float t);
|
||||
float easeInOutBack(float t);
|
||||
|
||||
// ============================================================================
|
||||
// 弹性缓动 (Elastic)
|
||||
// ============================================================================
|
||||
|
||||
float easeInElastic(float t);
|
||||
float easeOutElastic(float t);
|
||||
float easeInOutElastic(float t);
|
||||
|
||||
// ============================================================================
|
||||
// 弹跳缓动 (Bounce)
|
||||
// ============================================================================
|
||||
|
||||
float easeInBounce(float t);
|
||||
float easeOutBounce(float t);
|
||||
float easeInOutBounce(float t);
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <action/action.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 有限时间动作基类
|
||||
*
|
||||
* 所有具有持续时间的动作的基类。
|
||||
* 继承自 Action,添加了持续时间属性。
|
||||
*/
|
||||
class FiniteTimeAction : public Action {
|
||||
public:
|
||||
FiniteTimeAction() = default;
|
||||
explicit FiniteTimeAction(float duration);
|
||||
virtual ~FiniteTimeAction() = default;
|
||||
|
||||
/**
|
||||
* @brief 获取动作持续时间
|
||||
* @return 持续时间(秒)
|
||||
*/
|
||||
float getDuration() const { return duration_; }
|
||||
|
||||
/**
|
||||
* @brief 设置动作持续时间
|
||||
* @param duration 持续时间(秒)
|
||||
*/
|
||||
void setDuration(float duration) { duration_ = duration; }
|
||||
|
||||
/**
|
||||
* @brief 克隆动作
|
||||
* @return 动作的深拷贝
|
||||
*/
|
||||
FiniteTimeAction* clone() const override = 0;
|
||||
|
||||
/**
|
||||
* @brief 创建反向动作
|
||||
* @return 反向动作
|
||||
*/
|
||||
FiniteTimeAction* reverse() const override = 0;
|
||||
|
||||
protected:
|
||||
float duration_ = 0.0f;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
#include "action/action.h"
|
||||
#include "scene/node.h"
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
Action::Action() : tag_(-1), flags_(0) {}
|
||||
|
||||
bool Action::isDone() const {
|
||||
return state_ == ActionState::Completed;
|
||||
}
|
||||
|
||||
void Action::startWithTarget(Node* target) {
|
||||
target_ = target;
|
||||
originalTarget_ = target;
|
||||
state_ = ActionState::Running;
|
||||
onStart();
|
||||
}
|
||||
|
||||
void Action::stop() {
|
||||
target_ = nullptr;
|
||||
state_ = ActionState::Completed;
|
||||
}
|
||||
|
||||
void Action::step(float dt) {
|
||||
(void)dt;
|
||||
}
|
||||
|
||||
void Action::update(float time) {
|
||||
(void)time;
|
||||
}
|
||||
|
||||
void Action::pause() {
|
||||
if (state_ == ActionState::Running) {
|
||||
state_ = ActionState::Paused;
|
||||
}
|
||||
}
|
||||
|
||||
void Action::resume() {
|
||||
if (state_ == ActionState::Paused) {
|
||||
state_ = ActionState::Running;
|
||||
}
|
||||
}
|
||||
|
||||
void Action::restart() {
|
||||
state_ = ActionState::Running;
|
||||
onStart();
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,683 +0,0 @@
|
|||
#include "action/action_ease.h"
|
||||
#include <cmath>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846f
|
||||
#endif
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// ActionEase 基类
|
||||
// ============================================================================
|
||||
|
||||
ActionEase::~ActionEase() {
|
||||
delete innerAction_;
|
||||
}
|
||||
|
||||
bool ActionEase::initWithAction(ActionInterval* action) {
|
||||
if (!action) {
|
||||
return false;
|
||||
}
|
||||
innerAction_ = action;
|
||||
duration_ = action->getDuration();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ActionEase::startWithTarget(Node* target) {
|
||||
ActionInterval::startWithTarget(target);
|
||||
innerAction_->startWithTarget(target);
|
||||
}
|
||||
|
||||
void ActionEase::stop() {
|
||||
innerAction_->stop();
|
||||
ActionInterval::stop();
|
||||
}
|
||||
|
||||
void ActionEase::update(float time) {
|
||||
innerAction_->update(time);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 指数缓动
|
||||
// ============================================================================
|
||||
|
||||
EaseExponentialIn* EaseExponentialIn::create(ActionInterval* action) {
|
||||
auto* ease = new EaseExponentialIn();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseExponentialIn::update(float time) {
|
||||
innerAction_->update(easeInExpo(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseExponentialIn::clone() const {
|
||||
return EaseExponentialIn::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseExponentialIn::reverse() const {
|
||||
return EaseExponentialOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseExponentialOut* EaseExponentialOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseExponentialOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseExponentialOut::update(float time) {
|
||||
innerAction_->update(easeOutExpo(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseExponentialOut::clone() const {
|
||||
return EaseExponentialOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseExponentialOut::reverse() const {
|
||||
return EaseExponentialIn::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseExponentialInOut* EaseExponentialInOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseExponentialInOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseExponentialInOut::update(float time) {
|
||||
innerAction_->update(easeInOutExpo(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseExponentialInOut::clone() const {
|
||||
return EaseExponentialInOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseExponentialInOut::reverse() const {
|
||||
return EaseExponentialInOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 正弦缓动
|
||||
// ============================================================================
|
||||
|
||||
EaseSineIn* EaseSineIn::create(ActionInterval* action) {
|
||||
auto* ease = new EaseSineIn();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseSineIn::update(float time) {
|
||||
innerAction_->update(easeInSine(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseSineIn::clone() const {
|
||||
return EaseSineIn::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseSineIn::reverse() const {
|
||||
return EaseSineOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseSineOut* EaseSineOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseSineOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseSineOut::update(float time) {
|
||||
innerAction_->update(easeOutSine(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseSineOut::clone() const {
|
||||
return EaseSineOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseSineOut::reverse() const {
|
||||
return EaseSineIn::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseSineInOut* EaseSineInOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseSineInOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseSineInOut::update(float time) {
|
||||
innerAction_->update(easeInOutSine(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseSineInOut::clone() const {
|
||||
return EaseSineInOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseSineInOut::reverse() const {
|
||||
return EaseSineInOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 弹性缓动
|
||||
// ============================================================================
|
||||
|
||||
EaseElasticIn* EaseElasticIn::create(ActionInterval* action, float period) {
|
||||
auto* ease = new EaseElasticIn();
|
||||
ease->initWithAction(action);
|
||||
ease->period_ = period;
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseElasticIn::update(float time) {
|
||||
float newT = 0.0f;
|
||||
if (time == 0.0f || time == 1.0f) {
|
||||
newT = time;
|
||||
} else {
|
||||
float s = period_ / 4.0f;
|
||||
time = time - 1.0f;
|
||||
newT = -std::pow(2.0f, 10.0f * time) * std::sin((time - s) * M_PI * 2.0f / period_);
|
||||
}
|
||||
innerAction_->update(newT);
|
||||
}
|
||||
|
||||
ActionInterval* EaseElasticIn::clone() const {
|
||||
return EaseElasticIn::create(innerAction_->clone(), period_);
|
||||
}
|
||||
|
||||
ActionInterval* EaseElasticIn::reverse() const {
|
||||
return EaseElasticOut::create(innerAction_->reverse(), period_);
|
||||
}
|
||||
|
||||
EaseElasticOut* EaseElasticOut::create(ActionInterval* action, float period) {
|
||||
auto* ease = new EaseElasticOut();
|
||||
ease->initWithAction(action);
|
||||
ease->period_ = period;
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseElasticOut::update(float time) {
|
||||
float newT = 0.0f;
|
||||
if (time == 0.0f || time == 1.0f) {
|
||||
newT = time;
|
||||
} else {
|
||||
float s = period_ / 4.0f;
|
||||
newT = std::pow(2.0f, -10.0f * time) * std::sin((time - s) * M_PI * 2.0f / period_) + 1.0f;
|
||||
}
|
||||
innerAction_->update(newT);
|
||||
}
|
||||
|
||||
ActionInterval* EaseElasticOut::clone() const {
|
||||
return EaseElasticOut::create(innerAction_->clone(), period_);
|
||||
}
|
||||
|
||||
ActionInterval* EaseElasticOut::reverse() const {
|
||||
return EaseElasticIn::create(innerAction_->reverse(), period_);
|
||||
}
|
||||
|
||||
EaseElasticInOut* EaseElasticInOut::create(ActionInterval* action, float period) {
|
||||
auto* ease = new EaseElasticInOut();
|
||||
ease->initWithAction(action);
|
||||
ease->period_ = period;
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseElasticInOut::update(float time) {
|
||||
float newT = 0.0f;
|
||||
if (time == 0.0f || time == 1.0f) {
|
||||
newT = time;
|
||||
} else {
|
||||
time = time * 2.0f;
|
||||
if (period_ == 0.0f) {
|
||||
period_ = 0.3f * 1.5f;
|
||||
}
|
||||
float s = period_ / 4.0f;
|
||||
if (time < 1.0f) {
|
||||
time -= 1.0f;
|
||||
newT = -0.5f * std::pow(2.0f, 10.0f * time) * std::sin((time - s) * M_PI * 2.0f / period_);
|
||||
} else {
|
||||
time -= 1.0f;
|
||||
newT = std::pow(2.0f, -10.0f * time) * std::sin((time - s) * M_PI * 2.0f / period_) * 0.5f + 1.0f;
|
||||
}
|
||||
}
|
||||
innerAction_->update(newT);
|
||||
}
|
||||
|
||||
ActionInterval* EaseElasticInOut::clone() const {
|
||||
return EaseElasticInOut::create(innerAction_->clone(), period_);
|
||||
}
|
||||
|
||||
ActionInterval* EaseElasticInOut::reverse() const {
|
||||
return EaseElasticInOut::create(innerAction_->reverse(), period_);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 弹跳缓动
|
||||
// ============================================================================
|
||||
|
||||
EaseBounceIn* EaseBounceIn::create(ActionInterval* action) {
|
||||
auto* ease = new EaseBounceIn();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseBounceIn::update(float time) {
|
||||
innerAction_->update(easeInBounce(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseBounceIn::clone() const {
|
||||
return EaseBounceIn::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseBounceIn::reverse() const {
|
||||
return EaseBounceOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseBounceOut* EaseBounceOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseBounceOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseBounceOut::update(float time) {
|
||||
innerAction_->update(easeOutBounce(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseBounceOut::clone() const {
|
||||
return EaseBounceOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseBounceOut::reverse() const {
|
||||
return EaseBounceIn::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseBounceInOut* EaseBounceInOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseBounceInOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseBounceInOut::update(float time) {
|
||||
innerAction_->update(easeInOutBounce(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseBounceInOut::clone() const {
|
||||
return EaseBounceInOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseBounceInOut::reverse() const {
|
||||
return EaseBounceInOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 回震缓动
|
||||
// ============================================================================
|
||||
|
||||
EaseBackIn* EaseBackIn::create(ActionInterval* action) {
|
||||
auto* ease = new EaseBackIn();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseBackIn::update(float time) {
|
||||
innerAction_->update(easeInBack(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseBackIn::clone() const {
|
||||
return EaseBackIn::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseBackIn::reverse() const {
|
||||
return EaseBackOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseBackOut* EaseBackOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseBackOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseBackOut::update(float time) {
|
||||
innerAction_->update(easeOutBack(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseBackOut::clone() const {
|
||||
return EaseBackOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseBackOut::reverse() const {
|
||||
return EaseBackIn::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseBackInOut* EaseBackInOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseBackInOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseBackInOut::update(float time) {
|
||||
innerAction_->update(easeInOutBack(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseBackInOut::clone() const {
|
||||
return EaseBackInOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseBackInOut::reverse() const {
|
||||
return EaseBackInOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 二次缓动
|
||||
// ============================================================================
|
||||
|
||||
EaseQuadIn* EaseQuadIn::create(ActionInterval* action) {
|
||||
auto* ease = new EaseQuadIn();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseQuadIn::update(float time) {
|
||||
innerAction_->update(easeInQuad(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuadIn::clone() const {
|
||||
return EaseQuadIn::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuadIn::reverse() const {
|
||||
return EaseQuadOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseQuadOut* EaseQuadOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseQuadOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseQuadOut::update(float time) {
|
||||
innerAction_->update(easeOutQuad(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuadOut::clone() const {
|
||||
return EaseQuadOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuadOut::reverse() const {
|
||||
return EaseQuadIn::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseQuadInOut* EaseQuadInOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseQuadInOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseQuadInOut::update(float time) {
|
||||
innerAction_->update(easeInOutQuad(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuadInOut::clone() const {
|
||||
return EaseQuadInOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuadInOut::reverse() const {
|
||||
return EaseQuadInOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 三次缓动
|
||||
// ============================================================================
|
||||
|
||||
EaseCubicIn* EaseCubicIn::create(ActionInterval* action) {
|
||||
auto* ease = new EaseCubicIn();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseCubicIn::update(float time) {
|
||||
innerAction_->update(easeInCubic(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseCubicIn::clone() const {
|
||||
return EaseCubicIn::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseCubicIn::reverse() const {
|
||||
return EaseCubicOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseCubicOut* EaseCubicOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseCubicOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseCubicOut::update(float time) {
|
||||
innerAction_->update(easeOutCubic(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseCubicOut::clone() const {
|
||||
return EaseCubicOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseCubicOut::reverse() const {
|
||||
return EaseCubicIn::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseCubicInOut* EaseCubicInOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseCubicInOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseCubicInOut::update(float time) {
|
||||
innerAction_->update(easeInOutCubic(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseCubicInOut::clone() const {
|
||||
return EaseCubicInOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseCubicInOut::reverse() const {
|
||||
return EaseCubicInOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 四次缓动
|
||||
// ============================================================================
|
||||
|
||||
EaseQuartIn* EaseQuartIn::create(ActionInterval* action) {
|
||||
auto* ease = new EaseQuartIn();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseQuartIn::update(float time) {
|
||||
innerAction_->update(easeInQuart(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuartIn::clone() const {
|
||||
return EaseQuartIn::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuartIn::reverse() const {
|
||||
return EaseQuartOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseQuartOut* EaseQuartOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseQuartOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseQuartOut::update(float time) {
|
||||
innerAction_->update(easeOutQuart(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuartOut::clone() const {
|
||||
return EaseQuartOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuartOut::reverse() const {
|
||||
return EaseQuartIn::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseQuartInOut* EaseQuartInOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseQuartInOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseQuartInOut::update(float time) {
|
||||
innerAction_->update(easeInOutQuart(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuartInOut::clone() const {
|
||||
return EaseQuartInOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuartInOut::reverse() const {
|
||||
return EaseQuartInOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 五次缓动
|
||||
// ============================================================================
|
||||
|
||||
EaseQuintIn* EaseQuintIn::create(ActionInterval* action) {
|
||||
auto* ease = new EaseQuintIn();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseQuintIn::update(float time) {
|
||||
innerAction_->update(easeInQuint(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuintIn::clone() const {
|
||||
return EaseQuintIn::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuintIn::reverse() const {
|
||||
return EaseQuintOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseQuintOut* EaseQuintOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseQuintOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseQuintOut::update(float time) {
|
||||
innerAction_->update(easeOutQuint(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuintOut::clone() const {
|
||||
return EaseQuintOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuintOut::reverse() const {
|
||||
return EaseQuintIn::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseQuintInOut* EaseQuintInOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseQuintInOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseQuintInOut::update(float time) {
|
||||
innerAction_->update(easeInOutQuint(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuintInOut::clone() const {
|
||||
return EaseQuintInOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseQuintInOut::reverse() const {
|
||||
return EaseQuintInOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 圆形缓动
|
||||
// ============================================================================
|
||||
|
||||
EaseCircleIn* EaseCircleIn::create(ActionInterval* action) {
|
||||
auto* ease = new EaseCircleIn();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseCircleIn::update(float time) {
|
||||
innerAction_->update(easeInCirc(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseCircleIn::clone() const {
|
||||
return EaseCircleIn::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseCircleIn::reverse() const {
|
||||
return EaseCircleOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseCircleOut* EaseCircleOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseCircleOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseCircleOut::update(float time) {
|
||||
innerAction_->update(easeOutCirc(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseCircleOut::clone() const {
|
||||
return EaseCircleOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseCircleOut::reverse() const {
|
||||
return EaseCircleIn::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
EaseCircleInOut* EaseCircleInOut::create(ActionInterval* action) {
|
||||
auto* ease = new EaseCircleInOut();
|
||||
ease->initWithAction(action);
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseCircleInOut::update(float time) {
|
||||
innerAction_->update(easeInOutCirc(time));
|
||||
}
|
||||
|
||||
ActionInterval* EaseCircleInOut::clone() const {
|
||||
return EaseCircleInOut::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* EaseCircleInOut::reverse() const {
|
||||
return EaseCircleInOut::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 自定义缓动
|
||||
// ============================================================================
|
||||
|
||||
EaseCustom* EaseCustom::create(ActionInterval* action, EaseFunction easeFunc) {
|
||||
auto* ease = new EaseCustom();
|
||||
ease->initWithAction(action);
|
||||
ease->easeFunc_ = easeFunc;
|
||||
return ease;
|
||||
}
|
||||
|
||||
void EaseCustom::update(float time) {
|
||||
if (easeFunc_) {
|
||||
innerAction_->update(easeFunc_(time));
|
||||
} else {
|
||||
innerAction_->update(time);
|
||||
}
|
||||
}
|
||||
|
||||
ActionInterval* EaseCustom::clone() const {
|
||||
return EaseCustom::create(innerAction_->clone(), easeFunc_);
|
||||
}
|
||||
|
||||
ActionInterval* EaseCustom::reverse() const {
|
||||
return EaseCustom::create(innerAction_->reverse(), easeFunc_);
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#include "action/action_instant.h"
|
||||
#include "scene/node.h"
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
ActionInstant::ActionInstant() {
|
||||
duration_ = 0.0f;
|
||||
}
|
||||
|
||||
bool ActionInstant::isDone() const {
|
||||
return done_;
|
||||
}
|
||||
|
||||
void ActionInstant::startWithTarget(Node* target) {
|
||||
FiniteTimeAction::startWithTarget(target);
|
||||
done_ = false;
|
||||
}
|
||||
|
||||
void ActionInstant::step(float dt) {
|
||||
(void)dt;
|
||||
if (state_ != ActionState::Running) {
|
||||
return;
|
||||
}
|
||||
execute();
|
||||
done_ = true;
|
||||
state_ = ActionState::Completed;
|
||||
onComplete();
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
#include "action/action_instant_actions.h"
|
||||
#include "scene/node.h"
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 回调动作
|
||||
// ============================================================================
|
||||
|
||||
CallFunc* CallFunc::create(const Callback& callback) {
|
||||
auto* action = new CallFunc();
|
||||
action->callback_ = callback;
|
||||
return action;
|
||||
}
|
||||
|
||||
void CallFunc::execute() {
|
||||
if (callback_) {
|
||||
callback_();
|
||||
}
|
||||
}
|
||||
|
||||
ActionInstant* CallFunc::clone() const {
|
||||
return CallFunc::create(callback_);
|
||||
}
|
||||
|
||||
ActionInstant* CallFunc::reverse() const {
|
||||
return CallFunc::create(callback_);
|
||||
}
|
||||
|
||||
// CallFuncN
|
||||
CallFuncN* CallFuncN::create(const Callback& callback) {
|
||||
auto* action = new CallFuncN();
|
||||
action->callback_ = callback;
|
||||
return action;
|
||||
}
|
||||
|
||||
void CallFuncN::execute() {
|
||||
if (callback_ && target_) {
|
||||
callback_(target_);
|
||||
}
|
||||
}
|
||||
|
||||
ActionInstant* CallFuncN::clone() const {
|
||||
return CallFuncN::create(callback_);
|
||||
}
|
||||
|
||||
ActionInstant* CallFuncN::reverse() const {
|
||||
return CallFuncN::create(callback_);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 位置动作
|
||||
// ============================================================================
|
||||
|
||||
Place* Place::create(const Vec2& position) {
|
||||
auto* action = new Place();
|
||||
action->position_ = position;
|
||||
return action;
|
||||
}
|
||||
|
||||
void Place::execute() {
|
||||
if (target_) {
|
||||
target_->setPosition(position_);
|
||||
}
|
||||
}
|
||||
|
||||
ActionInstant* Place::clone() const {
|
||||
return Place::create(position_);
|
||||
}
|
||||
|
||||
ActionInstant* Place::reverse() const {
|
||||
return Place::create(position_);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 翻转动作
|
||||
// ============================================================================
|
||||
|
||||
FlipX* FlipX::create(bool flipX) {
|
||||
auto* action = new FlipX();
|
||||
action->flipX_ = flipX;
|
||||
return action;
|
||||
}
|
||||
|
||||
void FlipX::execute() {
|
||||
if (target_) {
|
||||
target_->setFlipX(flipX_);
|
||||
}
|
||||
}
|
||||
|
||||
ActionInstant* FlipX::clone() const {
|
||||
return FlipX::create(flipX_);
|
||||
}
|
||||
|
||||
ActionInstant* FlipX::reverse() const {
|
||||
return FlipX::create(!flipX_);
|
||||
}
|
||||
|
||||
// FlipY
|
||||
FlipY* FlipY::create(bool flipY) {
|
||||
auto* action = new FlipY();
|
||||
action->flipY_ = flipY;
|
||||
return action;
|
||||
}
|
||||
|
||||
void FlipY::execute() {
|
||||
if (target_) {
|
||||
target_->setFlipY(flipY_);
|
||||
}
|
||||
}
|
||||
|
||||
ActionInstant* FlipY::clone() const {
|
||||
return FlipY::create(flipY_);
|
||||
}
|
||||
|
||||
ActionInstant* FlipY::reverse() const {
|
||||
return FlipY::create(!flipY_);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 可见性动作
|
||||
// ============================================================================
|
||||
|
||||
Show* Show::create() {
|
||||
return new Show();
|
||||
}
|
||||
|
||||
void Show::execute() {
|
||||
if (target_) {
|
||||
target_->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
ActionInstant* Show::clone() const {
|
||||
return Show::create();
|
||||
}
|
||||
|
||||
ActionInstant* Show::reverse() const {
|
||||
return Hide::create();
|
||||
}
|
||||
|
||||
// Hide
|
||||
Hide* Hide::create() {
|
||||
return new Hide();
|
||||
}
|
||||
|
||||
void Hide::execute() {
|
||||
if (target_) {
|
||||
target_->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
ActionInstant* Hide::clone() const {
|
||||
return Hide::create();
|
||||
}
|
||||
|
||||
ActionInstant* Hide::reverse() const {
|
||||
return Show::create();
|
||||
}
|
||||
|
||||
// ToggleVisibility
|
||||
ToggleVisibility* ToggleVisibility::create() {
|
||||
return new ToggleVisibility();
|
||||
}
|
||||
|
||||
void ToggleVisibility::execute() {
|
||||
if (target_) {
|
||||
target_->setVisible(!target_->isVisible());
|
||||
}
|
||||
}
|
||||
|
||||
ActionInstant* ToggleVisibility::clone() const {
|
||||
return ToggleVisibility::create();
|
||||
}
|
||||
|
||||
ActionInstant* ToggleVisibility::reverse() const {
|
||||
return ToggleVisibility::create();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 节点管理动作
|
||||
// ============================================================================
|
||||
|
||||
RemoveSelf* RemoveSelf::create() {
|
||||
return new RemoveSelf();
|
||||
}
|
||||
|
||||
void RemoveSelf::execute() {
|
||||
if (target_) {
|
||||
target_->removeFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
ActionInstant* RemoveSelf::clone() const {
|
||||
return RemoveSelf::create();
|
||||
}
|
||||
|
||||
ActionInstant* RemoveSelf::reverse() const {
|
||||
return RemoveSelf::create();
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
#include "action/action_interval.h"
|
||||
#include "scene/node.h"
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
ActionInterval::ActionInterval(float duration)
|
||||
: FiniteTimeAction(duration) {
|
||||
}
|
||||
|
||||
bool ActionInterval::isDone() const {
|
||||
return elapsed_ >= duration_;
|
||||
}
|
||||
|
||||
void ActionInterval::startWithTarget(Node* target) {
|
||||
FiniteTimeAction::startWithTarget(target);
|
||||
elapsed_ = 0.0f;
|
||||
firstTick_ = true;
|
||||
onStart();
|
||||
}
|
||||
|
||||
void ActionInterval::stop() {
|
||||
FiniteTimeAction::stop();
|
||||
}
|
||||
|
||||
void ActionInterval::step(float dt) {
|
||||
if (state_ != ActionState::Running) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstTick_) {
|
||||
firstTick_ = false;
|
||||
elapsed_ = 0.0f;
|
||||
} else {
|
||||
elapsed_ += dt;
|
||||
}
|
||||
|
||||
float progress = 0.0f;
|
||||
if (duration_ > 0.0f) {
|
||||
progress = std::min(1.0f, elapsed_ / duration_);
|
||||
} else {
|
||||
progress = 1.0f;
|
||||
}
|
||||
|
||||
if (easeFunc_) {
|
||||
progress = easeFunc_(progress);
|
||||
}
|
||||
|
||||
onUpdate(progress);
|
||||
|
||||
if (progress >= 1.0f) {
|
||||
state_ = ActionState::Completed;
|
||||
onComplete();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,787 +0,0 @@
|
|||
#include "action/action_interval_actions.h"
|
||||
#include "scene/node.h"
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 移动动作
|
||||
// ============================================================================
|
||||
|
||||
MoveBy* MoveBy::create(float duration, const Vec2& delta) {
|
||||
auto* action = new MoveBy();
|
||||
action->duration_ = duration;
|
||||
action->delta_ = delta;
|
||||
return action;
|
||||
}
|
||||
|
||||
void MoveBy::onStart() {
|
||||
startPosition_ = target_->getPosition();
|
||||
}
|
||||
|
||||
void MoveBy::onUpdate(float progress) {
|
||||
Vec2 newPos = startPosition_ + delta_ * progress;
|
||||
target_->setPosition(newPos);
|
||||
}
|
||||
|
||||
ActionInterval* MoveBy::clone() const {
|
||||
return MoveBy::create(duration_, delta_);
|
||||
}
|
||||
|
||||
ActionInterval* MoveBy::reverse() const {
|
||||
return MoveBy::create(duration_, -delta_);
|
||||
}
|
||||
|
||||
// MoveTo
|
||||
MoveTo* MoveTo::create(float duration, const Vec2& position) {
|
||||
auto* action = new MoveTo();
|
||||
action->duration_ = duration;
|
||||
action->endPosition_ = position;
|
||||
return action;
|
||||
}
|
||||
|
||||
void MoveTo::onStart() {
|
||||
startPosition_ = target_->getPosition();
|
||||
delta_ = endPosition_ - startPosition_;
|
||||
}
|
||||
|
||||
void MoveTo::onUpdate(float progress) {
|
||||
Vec2 newPos = startPosition_ + delta_ * progress;
|
||||
target_->setPosition(newPos);
|
||||
}
|
||||
|
||||
ActionInterval* MoveTo::clone() const {
|
||||
return MoveTo::create(duration_, endPosition_);
|
||||
}
|
||||
|
||||
ActionInterval* MoveTo::reverse() const {
|
||||
return MoveTo::create(duration_, startPosition_);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 跳跃动作
|
||||
// ============================================================================
|
||||
|
||||
JumpBy* JumpBy::create(float duration, const Vec2& position, float height, int jumps) {
|
||||
auto* action = new JumpBy();
|
||||
action->duration_ = duration;
|
||||
action->delta_ = position;
|
||||
action->height_ = height;
|
||||
action->jumps_ = jumps;
|
||||
return action;
|
||||
}
|
||||
|
||||
void JumpBy::onStart() {
|
||||
startPosition_ = target_->getPosition();
|
||||
}
|
||||
|
||||
void JumpBy::onUpdate(float progress) {
|
||||
float frac = (progress * jumps_) - static_cast<int>(progress * jumps_);
|
||||
float y = height_ * 4.0f * frac * (1.0f - frac);
|
||||
y += delta_.y * progress;
|
||||
float x = delta_.x * progress;
|
||||
target_->setPosition(startPosition_ + Vec2(x, y));
|
||||
}
|
||||
|
||||
ActionInterval* JumpBy::clone() const {
|
||||
return JumpBy::create(duration_, delta_, height_, jumps_);
|
||||
}
|
||||
|
||||
ActionInterval* JumpBy::reverse() const {
|
||||
return JumpBy::create(duration_, -delta_, height_, jumps_);
|
||||
}
|
||||
|
||||
// JumpTo
|
||||
JumpTo* JumpTo::create(float duration, const Vec2& position, float height, int jumps) {
|
||||
auto* action = new JumpTo();
|
||||
action->duration_ = duration;
|
||||
action->endPosition_ = position;
|
||||
action->height_ = height;
|
||||
action->jumps_ = jumps;
|
||||
return action;
|
||||
}
|
||||
|
||||
void JumpTo::onStart() {
|
||||
JumpBy::onStart();
|
||||
delta_ = endPosition_ - startPosition_;
|
||||
}
|
||||
|
||||
ActionInterval* JumpTo::clone() const {
|
||||
return JumpTo::create(duration_, endPosition_, height_, jumps_);
|
||||
}
|
||||
|
||||
ActionInterval* JumpTo::reverse() const {
|
||||
return JumpTo::create(duration_, startPosition_, height_, jumps_);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 贝塞尔曲线动作
|
||||
// ============================================================================
|
||||
|
||||
BezierBy* BezierBy::create(float duration, const BezierConfig& config) {
|
||||
auto* action = new BezierBy();
|
||||
action->duration_ = duration;
|
||||
action->config_ = config;
|
||||
return action;
|
||||
}
|
||||
|
||||
void BezierBy::onStart() {
|
||||
startPosition_ = target_->getPosition();
|
||||
}
|
||||
|
||||
void BezierBy::onUpdate(float progress) {
|
||||
float xa = startPosition_.x;
|
||||
float xb = config_.controlPoint1.x;
|
||||
float xc = config_.controlPoint2.x;
|
||||
float xd = config_.endPosition.x;
|
||||
|
||||
float ya = startPosition_.y;
|
||||
float yb = config_.controlPoint1.y;
|
||||
float yc = config_.controlPoint2.y;
|
||||
float yd = config_.endPosition.y;
|
||||
|
||||
float x = bezierat(xa, xb, xc, xd, progress);
|
||||
float y = bezierat(ya, yb, yc, yd, progress);
|
||||
|
||||
target_->setPosition(Vec2(x, y));
|
||||
}
|
||||
|
||||
ActionInterval* BezierBy::clone() const {
|
||||
return BezierBy::create(duration_, config_);
|
||||
}
|
||||
|
||||
ActionInterval* BezierBy::reverse() const {
|
||||
BezierConfig rev;
|
||||
rev.controlPoint1 = config_.controlPoint2 + config_.endPosition;
|
||||
rev.controlPoint2 = config_.controlPoint1 + config_.endPosition;
|
||||
rev.endPosition = config_.endPosition;
|
||||
return BezierBy::create(duration_, rev);
|
||||
}
|
||||
|
||||
float BezierBy::bezierat(float a, float b, float c, float d, float t) {
|
||||
return (powf(1 - t, 3) * a +
|
||||
3.0f * t * powf(1 - t, 2) * b +
|
||||
3.0f * t * t * (1 - t) * c +
|
||||
t * t * t * d);
|
||||
}
|
||||
|
||||
// BezierTo
|
||||
BezierTo* BezierTo::create(float duration, const BezierConfig& config) {
|
||||
auto* action = new BezierTo();
|
||||
action->duration_ = duration;
|
||||
action->originalConfig_ = config;
|
||||
return action;
|
||||
}
|
||||
|
||||
void BezierTo::onStart() {
|
||||
BezierBy::onStart();
|
||||
config_.controlPoint1 = originalConfig_.controlPoint1 - startPosition_;
|
||||
config_.controlPoint2 = originalConfig_.controlPoint2 - startPosition_;
|
||||
config_.endPosition = originalConfig_.endPosition - startPosition_;
|
||||
}
|
||||
|
||||
ActionInterval* BezierTo::clone() const {
|
||||
return BezierTo::create(duration_, originalConfig_);
|
||||
}
|
||||
|
||||
ActionInterval* BezierTo::reverse() const {
|
||||
BezierConfig rev;
|
||||
rev.controlPoint1 = originalConfig_.controlPoint2;
|
||||
rev.controlPoint2 = originalConfig_.controlPoint1;
|
||||
rev.endPosition = startPosition_;
|
||||
return BezierTo::create(duration_, rev);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 缩放动作
|
||||
// ============================================================================
|
||||
|
||||
ScaleBy* ScaleBy::create(float duration, float scale) {
|
||||
return create(duration, scale, scale);
|
||||
}
|
||||
|
||||
ScaleBy* ScaleBy::create(float duration, float scaleX, float scaleY) {
|
||||
auto* action = new ScaleBy();
|
||||
action->duration_ = duration;
|
||||
action->deltaScale_ = Vec2(scaleX - 1.0f, scaleY - 1.0f);
|
||||
return action;
|
||||
}
|
||||
|
||||
ScaleBy* ScaleBy::create(float duration, const Vec2& scale) {
|
||||
return create(duration, scale.x, scale.y);
|
||||
}
|
||||
|
||||
void ScaleBy::onStart() {
|
||||
startScale_ = target_->getScale();
|
||||
}
|
||||
|
||||
void ScaleBy::onUpdate(float progress) {
|
||||
Vec2 newScale = startScale_ + deltaScale_ * progress;
|
||||
target_->setScale(newScale);
|
||||
}
|
||||
|
||||
ActionInterval* ScaleBy::clone() const {
|
||||
return ScaleBy::create(duration_, Vec2(startScale_.x + deltaScale_.x, startScale_.y + deltaScale_.y));
|
||||
}
|
||||
|
||||
ActionInterval* ScaleBy::reverse() const {
|
||||
return ScaleBy::create(duration_, Vec2(startScale_.x - deltaScale_.x, startScale_.y - deltaScale_.y));
|
||||
}
|
||||
|
||||
// ScaleTo
|
||||
ScaleTo* ScaleTo::create(float duration, float scale) {
|
||||
return create(duration, scale, scale);
|
||||
}
|
||||
|
||||
ScaleTo* ScaleTo::create(float duration, float scaleX, float scaleY) {
|
||||
auto* action = new ScaleTo();
|
||||
action->duration_ = duration;
|
||||
action->endScale_ = Vec2(scaleX, scaleY);
|
||||
return action;
|
||||
}
|
||||
|
||||
ScaleTo* ScaleTo::create(float duration, const Vec2& scale) {
|
||||
return create(duration, scale.x, scale.y);
|
||||
}
|
||||
|
||||
void ScaleTo::onStart() {
|
||||
startScale_ = target_->getScale();
|
||||
delta_ = endScale_ - startScale_;
|
||||
}
|
||||
|
||||
void ScaleTo::onUpdate(float progress) {
|
||||
Vec2 newScale = startScale_ + delta_ * progress;
|
||||
target_->setScale(newScale);
|
||||
}
|
||||
|
||||
ActionInterval* ScaleTo::clone() const {
|
||||
return ScaleTo::create(duration_, endScale_);
|
||||
}
|
||||
|
||||
ActionInterval* ScaleTo::reverse() const {
|
||||
return ScaleTo::create(duration_, startScale_);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 旋转动作
|
||||
// ============================================================================
|
||||
|
||||
RotateBy* RotateBy::create(float duration, float deltaAngle) {
|
||||
auto* action = new RotateBy();
|
||||
action->duration_ = duration;
|
||||
action->deltaAngle_ = deltaAngle;
|
||||
return action;
|
||||
}
|
||||
|
||||
void RotateBy::onStart() {
|
||||
startAngle_ = target_->getRotation();
|
||||
}
|
||||
|
||||
void RotateBy::onUpdate(float progress) {
|
||||
float newAngle = startAngle_ + deltaAngle_ * progress;
|
||||
target_->setRotation(newAngle);
|
||||
}
|
||||
|
||||
ActionInterval* RotateBy::clone() const {
|
||||
return RotateBy::create(duration_, deltaAngle_);
|
||||
}
|
||||
|
||||
ActionInterval* RotateBy::reverse() const {
|
||||
return RotateBy::create(duration_, -deltaAngle_);
|
||||
}
|
||||
|
||||
// RotateTo
|
||||
RotateTo* RotateTo::create(float duration, float angle) {
|
||||
auto* action = new RotateTo();
|
||||
action->duration_ = duration;
|
||||
action->endAngle_ = angle;
|
||||
return action;
|
||||
}
|
||||
|
||||
void RotateTo::onStart() {
|
||||
startAngle_ = target_->getRotation();
|
||||
deltaAngle_ = endAngle_ - startAngle_;
|
||||
|
||||
if (deltaAngle_ > 180.0f) deltaAngle_ -= 360.0f;
|
||||
if (deltaAngle_ < -180.0f) deltaAngle_ += 360.0f;
|
||||
}
|
||||
|
||||
void RotateTo::onUpdate(float progress) {
|
||||
float newAngle = startAngle_ + deltaAngle_ * progress;
|
||||
target_->setRotation(newAngle);
|
||||
}
|
||||
|
||||
ActionInterval* RotateTo::clone() const {
|
||||
return RotateTo::create(duration_, endAngle_);
|
||||
}
|
||||
|
||||
ActionInterval* RotateTo::reverse() const {
|
||||
return RotateTo::create(duration_, startAngle_);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 淡入淡出动作
|
||||
// ============================================================================
|
||||
|
||||
FadeIn* FadeIn::create(float duration) {
|
||||
auto* action = new FadeIn();
|
||||
action->duration_ = duration;
|
||||
return action;
|
||||
}
|
||||
|
||||
void FadeIn::onStart() {
|
||||
startOpacity_ = target_->getOpacity();
|
||||
target_->setOpacity(0.0f);
|
||||
}
|
||||
|
||||
void FadeIn::onUpdate(float progress) {
|
||||
target_->setOpacity(progress);
|
||||
}
|
||||
|
||||
ActionInterval* FadeIn::clone() const {
|
||||
return FadeIn::create(duration_);
|
||||
}
|
||||
|
||||
ActionInterval* FadeIn::reverse() const {
|
||||
return FadeOut::create(duration_);
|
||||
}
|
||||
|
||||
// FadeOut
|
||||
FadeOut* FadeOut::create(float duration) {
|
||||
auto* action = new FadeOut();
|
||||
action->duration_ = duration;
|
||||
return action;
|
||||
}
|
||||
|
||||
void FadeOut::onStart() {
|
||||
startOpacity_ = target_->getOpacity();
|
||||
target_->setOpacity(1.0f);
|
||||
}
|
||||
|
||||
void FadeOut::onUpdate(float progress) {
|
||||
target_->setOpacity(1.0f - progress);
|
||||
}
|
||||
|
||||
ActionInterval* FadeOut::clone() const {
|
||||
return FadeOut::create(duration_);
|
||||
}
|
||||
|
||||
ActionInterval* FadeOut::reverse() const {
|
||||
return FadeIn::create(duration_);
|
||||
}
|
||||
|
||||
// FadeTo
|
||||
FadeTo* FadeTo::create(float duration, float opacity) {
|
||||
auto* action = new FadeTo();
|
||||
action->duration_ = duration;
|
||||
action->endOpacity_ = opacity;
|
||||
return action;
|
||||
}
|
||||
|
||||
void FadeTo::onStart() {
|
||||
startOpacity_ = target_->getOpacity();
|
||||
deltaOpacity_ = endOpacity_ - startOpacity_;
|
||||
}
|
||||
|
||||
void FadeTo::onUpdate(float progress) {
|
||||
target_->setOpacity(startOpacity_ + deltaOpacity_ * progress);
|
||||
}
|
||||
|
||||
ActionInterval* FadeTo::clone() const {
|
||||
return FadeTo::create(duration_, endOpacity_);
|
||||
}
|
||||
|
||||
ActionInterval* FadeTo::reverse() const {
|
||||
return FadeTo::create(duration_, startOpacity_);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 闪烁动作
|
||||
// ============================================================================
|
||||
|
||||
Blink* Blink::create(float duration, int times) {
|
||||
auto* action = new Blink();
|
||||
action->duration_ = duration;
|
||||
action->times_ = times;
|
||||
return action;
|
||||
}
|
||||
|
||||
void Blink::onStart() {
|
||||
originalVisible_ = target_->isVisible();
|
||||
currentTimes_ = 0;
|
||||
}
|
||||
|
||||
void Blink::onUpdate(float progress) {
|
||||
float slice = 1.0f / times_;
|
||||
float m = fmodf(progress, slice);
|
||||
target_->setVisible(m > slice / 2.0f);
|
||||
}
|
||||
|
||||
ActionInterval* Blink::clone() const {
|
||||
return Blink::create(duration_, times_);
|
||||
}
|
||||
|
||||
ActionInterval* Blink::reverse() const {
|
||||
return Blink::create(duration_, times_);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 色调动作
|
||||
// ============================================================================
|
||||
|
||||
TintTo* TintTo::create(float duration, uint8_t red, uint8_t green, uint8_t blue) {
|
||||
auto* action = new TintTo();
|
||||
action->duration_ = duration;
|
||||
action->endColor_ = Color3B(red, green, blue);
|
||||
return action;
|
||||
}
|
||||
|
||||
void TintTo::onStart() {
|
||||
startColor_ = target_->getColor();
|
||||
deltaColor_ = Color3B(
|
||||
static_cast<int16_t>(endColor_.r) - static_cast<int16_t>(startColor_.r),
|
||||
static_cast<int16_t>(endColor_.g) - static_cast<int16_t>(startColor_.g),
|
||||
static_cast<int16_t>(endColor_.b) - static_cast<int16_t>(startColor_.b)
|
||||
);
|
||||
}
|
||||
|
||||
void TintTo::onUpdate(float progress) {
|
||||
Color3B newColor(
|
||||
static_cast<uint8_t>(startColor_.r + deltaColor_.r * progress),
|
||||
static_cast<uint8_t>(startColor_.g + deltaColor_.g * progress),
|
||||
static_cast<uint8_t>(startColor_.b + deltaColor_.b * progress)
|
||||
);
|
||||
target_->setColor(newColor);
|
||||
}
|
||||
|
||||
ActionInterval* TintTo::clone() const {
|
||||
return TintTo::create(duration_, endColor_.r, endColor_.g, endColor_.b);
|
||||
}
|
||||
|
||||
ActionInterval* TintTo::reverse() const {
|
||||
return TintTo::create(duration_, startColor_.r, startColor_.g, startColor_.b);
|
||||
}
|
||||
|
||||
// TintBy
|
||||
TintBy* TintBy::create(float duration, int16_t deltaRed, int16_t deltaGreen, int16_t deltaBlue) {
|
||||
auto* action = new TintBy();
|
||||
action->duration_ = duration;
|
||||
action->deltaR_ = deltaRed;
|
||||
action->deltaG_ = deltaGreen;
|
||||
action->deltaB_ = deltaBlue;
|
||||
return action;
|
||||
}
|
||||
|
||||
void TintBy::onStart() {
|
||||
startColor_ = target_->getColor();
|
||||
}
|
||||
|
||||
void TintBy::onUpdate(float progress) {
|
||||
Color3B newColor(
|
||||
static_cast<uint8_t>(startColor_.r + deltaR_ * progress),
|
||||
static_cast<uint8_t>(startColor_.g + deltaG_ * progress),
|
||||
static_cast<uint8_t>(startColor_.b + deltaB_ * progress)
|
||||
);
|
||||
target_->setColor(newColor);
|
||||
}
|
||||
|
||||
ActionInterval* TintBy::clone() const {
|
||||
return TintBy::create(duration_, deltaR_, deltaG_, deltaB_);
|
||||
}
|
||||
|
||||
ActionInterval* TintBy::reverse() const {
|
||||
return TintBy::create(duration_, -deltaR_, -deltaG_, -deltaB_);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 组合动作
|
||||
// ============================================================================
|
||||
|
||||
Sequence* Sequence::create(ActionInterval* action1, ...) {
|
||||
std::vector<ActionInterval*> actions;
|
||||
actions.push_back(action1);
|
||||
|
||||
va_list args;
|
||||
va_start(args, action1);
|
||||
ActionInterval* action = nullptr;
|
||||
while ((action = va_arg(args, ActionInterval*)) != nullptr) {
|
||||
actions.push_back(action);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return create(actions);
|
||||
}
|
||||
|
||||
Sequence* Sequence::create(const std::vector<ActionInterval*>& actions) {
|
||||
auto* seq = new Sequence();
|
||||
seq->duration_ = 0.0f;
|
||||
|
||||
for (auto* action : actions) {
|
||||
if (action) {
|
||||
seq->actions_.push_back(action);
|
||||
seq->duration_ += action->getDuration();
|
||||
}
|
||||
}
|
||||
return seq;
|
||||
}
|
||||
|
||||
Sequence::~Sequence() {
|
||||
for (auto* action : actions_) {
|
||||
delete action;
|
||||
}
|
||||
}
|
||||
|
||||
void Sequence::onStart() {
|
||||
currentIndex_ = 0;
|
||||
split_ = 0.0f;
|
||||
last_ = -1.0f;
|
||||
|
||||
if (!actions_.empty()) {
|
||||
actions_[0]->startWithTarget(target_);
|
||||
}
|
||||
}
|
||||
|
||||
void Sequence::onUpdate(float progress) {
|
||||
float newTime = progress * duration_;
|
||||
|
||||
if (newTime < last_) {
|
||||
for (auto* action : actions_) {
|
||||
action->stop();
|
||||
}
|
||||
}
|
||||
last_ = newTime;
|
||||
|
||||
float foundSplit = 0.0f;
|
||||
size_t found = 0;
|
||||
|
||||
for (size_t i = 0; i < actions_.size(); ++i) {
|
||||
foundSplit += actions_[i]->getDuration();
|
||||
if (foundSplit > newTime) {
|
||||
found = i;
|
||||
break;
|
||||
} else if (foundSplit == newTime) {
|
||||
found = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found != currentIndex_) {
|
||||
if (currentIndex_ < actions_.size()) {
|
||||
actions_[currentIndex_]->update(1.0f);
|
||||
}
|
||||
if (found < actions_.size()) {
|
||||
actions_[found]->startWithTarget(target_);
|
||||
}
|
||||
currentIndex_ = found;
|
||||
}
|
||||
|
||||
if (currentIndex_ < actions_.size()) {
|
||||
float localTime = newTime - (foundSplit - actions_[currentIndex_]->getDuration());
|
||||
float localProgress = actions_[currentIndex_]->getDuration() > 0.0f
|
||||
? localTime / actions_[currentIndex_]->getDuration() : 1.0f;
|
||||
actions_[currentIndex_]->update(localProgress);
|
||||
}
|
||||
}
|
||||
|
||||
ActionInterval* Sequence::clone() const {
|
||||
std::vector<ActionInterval*> cloned;
|
||||
for (auto* action : actions_) {
|
||||
cloned.push_back(action->clone());
|
||||
}
|
||||
return Sequence::create(cloned);
|
||||
}
|
||||
|
||||
ActionInterval* Sequence::reverse() const {
|
||||
std::vector<ActionInterval*> rev;
|
||||
for (auto it = actions_.rbegin(); it != actions_.rend(); ++it) {
|
||||
rev.push_back((*it)->reverse());
|
||||
}
|
||||
return Sequence::create(rev);
|
||||
}
|
||||
|
||||
// Spawn
|
||||
Spawn* Spawn::create(ActionInterval* action1, ...) {
|
||||
std::vector<ActionInterval*> actions;
|
||||
actions.push_back(action1);
|
||||
|
||||
va_list args;
|
||||
va_start(args, action1);
|
||||
ActionInterval* action = nullptr;
|
||||
while ((action = va_arg(args, ActionInterval*)) != nullptr) {
|
||||
actions.push_back(action);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return create(actions);
|
||||
}
|
||||
|
||||
Spawn* Spawn::create(const std::vector<ActionInterval*>& actions) {
|
||||
auto* spawn = new Spawn();
|
||||
spawn->duration_ = 0.0f;
|
||||
|
||||
for (auto* action : actions) {
|
||||
if (action) {
|
||||
spawn->actions_.push_back(action);
|
||||
spawn->duration_ = std::max(spawn->duration_, action->getDuration());
|
||||
}
|
||||
}
|
||||
return spawn;
|
||||
}
|
||||
|
||||
Spawn::~Spawn() {
|
||||
for (auto* action : actions_) {
|
||||
delete action;
|
||||
}
|
||||
}
|
||||
|
||||
void Spawn::onStart() {
|
||||
for (auto* action : actions_) {
|
||||
action->startWithTarget(target_);
|
||||
}
|
||||
}
|
||||
|
||||
void Spawn::onUpdate(float progress) {
|
||||
for (auto* action : actions_) {
|
||||
float localProgress = action->getDuration() > 0.0f
|
||||
? std::min(1.0f, (progress * duration_) / action->getDuration())
|
||||
: 1.0f;
|
||||
action->update(localProgress);
|
||||
}
|
||||
}
|
||||
|
||||
ActionInterval* Spawn::clone() const {
|
||||
std::vector<ActionInterval*> cloned;
|
||||
for (auto* action : actions_) {
|
||||
cloned.push_back(action->clone());
|
||||
}
|
||||
return Spawn::create(cloned);
|
||||
}
|
||||
|
||||
ActionInterval* Spawn::reverse() const {
|
||||
std::vector<ActionInterval*> rev;
|
||||
for (auto* action : actions_) {
|
||||
rev.push_back(action->reverse());
|
||||
}
|
||||
return Spawn::create(rev);
|
||||
}
|
||||
|
||||
// Repeat
|
||||
Repeat* Repeat::create(ActionInterval* action, int times) {
|
||||
auto* repeat = new Repeat();
|
||||
repeat->innerAction_ = action;
|
||||
repeat->times_ = times;
|
||||
repeat->duration_ = action->getDuration() * times;
|
||||
return repeat;
|
||||
}
|
||||
|
||||
ActionInterval* Repeat::clone() const {
|
||||
return Repeat::create(innerAction_->clone(), times_);
|
||||
}
|
||||
|
||||
ActionInterval* Repeat::reverse() const {
|
||||
return Repeat::create(innerAction_->reverse(), times_);
|
||||
}
|
||||
|
||||
bool Repeat::isDone() const {
|
||||
return currentTimes_ >= times_;
|
||||
}
|
||||
|
||||
void Repeat::onStart() {
|
||||
currentTimes_ = 0;
|
||||
innerAction_->startWithTarget(target_);
|
||||
}
|
||||
|
||||
void Repeat::onUpdate(float progress) {
|
||||
float t = progress * times_;
|
||||
int current = static_cast<int>(t);
|
||||
|
||||
if (current > currentTimes_) {
|
||||
innerAction_->update(1.0f);
|
||||
currentTimes_++;
|
||||
if (currentTimes_ < times_) {
|
||||
innerAction_->startWithTarget(target_);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentTimes_ < times_) {
|
||||
innerAction_->update(t - current);
|
||||
}
|
||||
}
|
||||
|
||||
// RepeatForever
|
||||
RepeatForever* RepeatForever::create(ActionInterval* action) {
|
||||
auto* repeat = new RepeatForever();
|
||||
repeat->innerAction_ = action;
|
||||
repeat->duration_ = action->getDuration();
|
||||
return repeat;
|
||||
}
|
||||
|
||||
ActionInterval* RepeatForever::clone() const {
|
||||
return RepeatForever::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* RepeatForever::reverse() const {
|
||||
return RepeatForever::create(innerAction_->reverse());
|
||||
}
|
||||
|
||||
bool RepeatForever::isDone() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void RepeatForever::onStart() {
|
||||
innerAction_->startWithTarget(target_);
|
||||
}
|
||||
|
||||
void RepeatForever::onUpdate(float progress) {
|
||||
innerAction_->update(progress);
|
||||
if (innerAction_->isDone()) {
|
||||
innerAction_->startWithTarget(target_);
|
||||
elapsed_ = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// DelayTime
|
||||
DelayTime* DelayTime::create(float duration) {
|
||||
auto* delay = new DelayTime();
|
||||
delay->duration_ = duration;
|
||||
return delay;
|
||||
}
|
||||
|
||||
ActionInterval* DelayTime::clone() const {
|
||||
return DelayTime::create(duration_);
|
||||
}
|
||||
|
||||
ActionInterval* DelayTime::reverse() const {
|
||||
return DelayTime::create(duration_);
|
||||
}
|
||||
|
||||
// ReverseTime
|
||||
ReverseTime* ReverseTime::create(ActionInterval* action) {
|
||||
auto* rev = new ReverseTime();
|
||||
rev->innerAction_ = action;
|
||||
rev->duration_ = action->getDuration();
|
||||
return rev;
|
||||
}
|
||||
|
||||
ReverseTime::~ReverseTime() {
|
||||
delete innerAction_;
|
||||
}
|
||||
|
||||
ActionInterval* ReverseTime::clone() const {
|
||||
return ReverseTime::create(innerAction_->clone());
|
||||
}
|
||||
|
||||
ActionInterval* ReverseTime::reverse() const {
|
||||
return innerAction_->clone();
|
||||
}
|
||||
|
||||
void ReverseTime::onStart() {
|
||||
innerAction_->startWithTarget(target_);
|
||||
}
|
||||
|
||||
void ReverseTime::onUpdate(float progress) {
|
||||
innerAction_->update(1.0f - progress);
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,244 +0,0 @@
|
|||
#include "action/action_manager.h"
|
||||
#include "scene/node.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
ActionManager* ActionManager::instance_ = nullptr;
|
||||
|
||||
ActionManager::ActionManager() {}
|
||||
|
||||
ActionManager::~ActionManager() {
|
||||
removeAllActions();
|
||||
}
|
||||
|
||||
ActionManager* ActionManager::getInstance() {
|
||||
if (!instance_) {
|
||||
instance_ = new ActionManager();
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
|
||||
void ActionManager::destroyInstance() {
|
||||
if (instance_) {
|
||||
delete instance_;
|
||||
instance_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ActionManager::addAction(Action* action, Node* target, bool paused) {
|
||||
if (!action || !target) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = targets_.find(target);
|
||||
if (it == targets_.end()) {
|
||||
ActionElement element;
|
||||
element.target = target;
|
||||
element.paused = paused;
|
||||
targets_[target] = element;
|
||||
it = targets_.find(target);
|
||||
}
|
||||
|
||||
auto& element = it->second;
|
||||
element.actions.push_back(action);
|
||||
action->startWithTarget(target);
|
||||
}
|
||||
|
||||
void ActionManager::removeAction(Action* action) {
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
|
||||
Node* target = action->getOriginalTarget();
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = targets_.find(target);
|
||||
if (it == targets_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& element = it->second;
|
||||
for (size_t i = 0; i < element.actions.size(); ++i) {
|
||||
if (element.actions[i] == action) {
|
||||
removeActionAt(i, element);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ActionManager::removeActionByTag(int tag, Node* target) {
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = targets_.find(target);
|
||||
if (it == targets_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& element = it->second;
|
||||
for (size_t i = 0; i < element.actions.size(); ++i) {
|
||||
if (element.actions[i]->getTag() == tag) {
|
||||
removeActionAt(i, element);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ActionManager::removeActionsByFlags(unsigned int flags, Node* target) {
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = targets_.find(target);
|
||||
if (it == targets_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& element = it->second;
|
||||
for (int i = static_cast<int>(element.actions.size()) - 1; i >= 0; --i) {
|
||||
if (element.actions[i]->getFlags() & flags) {
|
||||
removeActionAt(i, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ActionManager::removeAllActionsFromTarget(Node* target) {
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = targets_.find(target);
|
||||
if (it == targets_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& element = it->second;
|
||||
for (auto* action : element.actions) {
|
||||
action->stop();
|
||||
deleteAction(action);
|
||||
}
|
||||
element.actions.clear();
|
||||
targets_.erase(it);
|
||||
}
|
||||
|
||||
void ActionManager::removeAllActions() {
|
||||
for (auto& pair : targets_) {
|
||||
auto& element = pair.second;
|
||||
for (auto* action : element.actions) {
|
||||
action->stop();
|
||||
deleteAction(action);
|
||||
}
|
||||
}
|
||||
targets_.clear();
|
||||
}
|
||||
|
||||
Action* ActionManager::getActionByTag(int tag, Node* target) {
|
||||
if (!target) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto it = targets_.find(target);
|
||||
if (it == targets_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto& element = it->second;
|
||||
for (auto* action : element.actions) {
|
||||
if (action->getTag() == tag) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t ActionManager::getActionCount(Node* target) const {
|
||||
auto it = targets_.find(target);
|
||||
if (it == targets_.end()) {
|
||||
return 0;
|
||||
}
|
||||
return it->second.actions.size();
|
||||
}
|
||||
|
||||
void ActionManager::pauseTarget(Node* target) {
|
||||
auto it = targets_.find(target);
|
||||
if (it != targets_.end()) {
|
||||
it->second.paused = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ActionManager::resumeTarget(Node* target) {
|
||||
auto it = targets_.find(target);
|
||||
if (it != targets_.end()) {
|
||||
it->second.paused = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ActionManager::isPaused(Node* target) const {
|
||||
auto it = targets_.find(target);
|
||||
if (it == targets_.end()) {
|
||||
return false;
|
||||
}
|
||||
return it->second.paused;
|
||||
}
|
||||
|
||||
void ActionManager::update(float dt) {
|
||||
for (auto it = targets_.begin(); it != targets_.end(); ) {
|
||||
auto& element = it->second;
|
||||
Node* target = element.target;
|
||||
|
||||
if (!element.paused && target) {
|
||||
element.actionIndex = 0;
|
||||
while (static_cast<size_t>(element.actionIndex) < element.actions.size()) {
|
||||
element.currentAction = element.actions[element.actionIndex];
|
||||
element.currentActionSalvaged = false;
|
||||
|
||||
if (element.currentAction->getState() != ActionState::Paused) {
|
||||
element.currentAction->step(dt);
|
||||
}
|
||||
|
||||
if (element.currentActionSalvaged) {
|
||||
deleteAction(element.currentAction);
|
||||
} else if (element.currentAction->isDone()) {
|
||||
element.currentAction->stop();
|
||||
deleteAction(element.currentAction);
|
||||
element.actions.erase(element.actions.begin() + element.actionIndex);
|
||||
continue;
|
||||
}
|
||||
|
||||
element.actionIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (element.actions.empty()) {
|
||||
it = targets_.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ActionManager::removeActionAt(size_t index, ActionElement& element) {
|
||||
if (index >= element.actions.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Action* action = element.actions[index];
|
||||
if (action == element.currentAction) {
|
||||
element.currentActionSalvaged = true;
|
||||
}
|
||||
action->stop();
|
||||
deleteAction(action);
|
||||
element.actions.erase(element.actions.begin() + index);
|
||||
}
|
||||
|
||||
void ActionManager::deleteAction(Action* action) {
|
||||
if (action) {
|
||||
delete action;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
#include "action/action_special.h"
|
||||
#include "scene/node.h"
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// Speed
|
||||
// ============================================================================
|
||||
|
||||
Speed* Speed::create(ActionInterval* action, float speed) {
|
||||
auto* speedAction = new Speed();
|
||||
speedAction->innerAction_ = action;
|
||||
speedAction->speed_ = speed;
|
||||
return speedAction;
|
||||
}
|
||||
|
||||
Speed::~Speed() {
|
||||
delete innerAction_;
|
||||
}
|
||||
|
||||
void Speed::startWithTarget(Node* target) {
|
||||
Action::startWithTarget(target);
|
||||
innerAction_->startWithTarget(target);
|
||||
}
|
||||
|
||||
void Speed::stop() {
|
||||
innerAction_->stop();
|
||||
Action::stop();
|
||||
}
|
||||
|
||||
void Speed::step(float dt) {
|
||||
if (state_ != ActionState::Running) {
|
||||
return;
|
||||
}
|
||||
innerAction_->step(dt * speed_);
|
||||
if (innerAction_->isDone()) {
|
||||
state_ = ActionState::Completed;
|
||||
onComplete();
|
||||
}
|
||||
}
|
||||
|
||||
bool Speed::isDone() const {
|
||||
return innerAction_->isDone();
|
||||
}
|
||||
|
||||
Action* Speed::clone() const {
|
||||
return Speed::create(innerAction_->clone(), speed_);
|
||||
}
|
||||
|
||||
Action* Speed::reverse() const {
|
||||
return Speed::create(innerAction_->reverse(), speed_);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Follow
|
||||
// ============================================================================
|
||||
|
||||
Follow* Follow::create(Node* followedNode) {
|
||||
return create(followedNode, Rect::Zero());
|
||||
}
|
||||
|
||||
Follow* Follow::create(Node* followedNode, const Rect& boundary) {
|
||||
auto* follow = new Follow();
|
||||
follow->followedNode_ = followedNode;
|
||||
follow->boundary_ = boundary;
|
||||
follow->boundarySet_ = (boundary != Rect::Zero());
|
||||
return follow;
|
||||
}
|
||||
|
||||
Follow::~Follow() {
|
||||
followedNode_ = nullptr;
|
||||
}
|
||||
|
||||
void Follow::startWithTarget(Node* target) {
|
||||
Action::startWithTarget(target);
|
||||
if (target && followedNode_) {
|
||||
halfScreenSize_ = Vec2(0, 0);
|
||||
fullScreenSize_ = Vec2(0, 0);
|
||||
|
||||
if (boundarySet_) {
|
||||
leftBoundary_ = Vec2(boundary_.origin.x, 0);
|
||||
rightBoundary_ = Vec2(boundary_.origin.x + boundary_.size.width, 0);
|
||||
topBoundary_ = Vec2(0, boundary_.origin.y);
|
||||
bottomBoundary_ = Vec2(0, boundary_.origin.y + boundary_.size.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Follow::stop() {
|
||||
followedNode_ = nullptr;
|
||||
Action::stop();
|
||||
}
|
||||
|
||||
void Follow::step(float dt) {
|
||||
(void)dt;
|
||||
if (state_ != ActionState::Running || !followedNode_ || !target_) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vec2 pos = followedNode_->getPosition();
|
||||
|
||||
if (boundarySet_) {
|
||||
pos.x = std::clamp(pos.x, leftBoundary_.x, rightBoundary_.x);
|
||||
pos.y = std::clamp(pos.y, bottomBoundary_.y, topBoundary_.y);
|
||||
}
|
||||
|
||||
target_->setPosition(pos);
|
||||
}
|
||||
|
||||
bool Follow::isDone() const {
|
||||
return followedNode_ == nullptr || !followedNode_->isRunning();
|
||||
}
|
||||
|
||||
Action* Follow::clone() const {
|
||||
return Follow::create(followedNode_, boundary_);
|
||||
}
|
||||
|
||||
Action* Follow::reverse() const {
|
||||
return Follow::create(followedNode_, boundary_);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TargetedAction
|
||||
// ============================================================================
|
||||
|
||||
TargetedAction* TargetedAction::create(Node* target, FiniteTimeAction* action) {
|
||||
auto* targeted = new TargetedAction();
|
||||
targeted->targetNode_ = target;
|
||||
targeted->innerAction_ = action;
|
||||
return targeted;
|
||||
}
|
||||
|
||||
TargetedAction::~TargetedAction() {
|
||||
delete innerAction_;
|
||||
}
|
||||
|
||||
void TargetedAction::startWithTarget(Node* target) {
|
||||
Action::startWithTarget(target);
|
||||
if (targetNode_) {
|
||||
innerAction_->startWithTarget(targetNode_);
|
||||
}
|
||||
}
|
||||
|
||||
void TargetedAction::stop() {
|
||||
innerAction_->stop();
|
||||
Action::stop();
|
||||
}
|
||||
|
||||
void TargetedAction::step(float dt) {
|
||||
if (state_ != ActionState::Running) {
|
||||
return;
|
||||
}
|
||||
innerAction_->step(dt);
|
||||
if (innerAction_->isDone()) {
|
||||
state_ = ActionState::Completed;
|
||||
onComplete();
|
||||
}
|
||||
}
|
||||
|
||||
bool TargetedAction::isDone() const {
|
||||
return innerAction_->isDone();
|
||||
}
|
||||
|
||||
Action* TargetedAction::clone() const {
|
||||
return TargetedAction::create(targetNode_, innerAction_->clone());
|
||||
}
|
||||
|
||||
Action* TargetedAction::reverse() const {
|
||||
return TargetedAction::create(targetNode_, innerAction_->reverse());
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
#include "action/ease.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846f
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// 线性缓动
|
||||
// ============================================================================
|
||||
|
||||
float easeLinear(float t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 二次缓动 (Quad)
|
||||
// ============================================================================
|
||||
|
||||
float easeInQuad(float t) {
|
||||
return t * t;
|
||||
}
|
||||
|
||||
float easeOutQuad(float t) {
|
||||
return 1.0f - (1.0f - t) * (1.0f - t);
|
||||
}
|
||||
|
||||
float easeInOutQuad(float t) {
|
||||
return t < 0.5f ? 2.0f * t * t : 1.0f - std::pow(-2.0f * t + 2.0f, 2.0f) / 2.0f;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 三次缓动 (Cubic)
|
||||
// ============================================================================
|
||||
|
||||
float easeInCubic(float t) {
|
||||
return t * t * t;
|
||||
}
|
||||
|
||||
float easeOutCubic(float t) {
|
||||
return 1.0f - std::pow(1.0f - t, 3.0f);
|
||||
}
|
||||
|
||||
float easeInOutCubic(float t) {
|
||||
return t < 0.5f ? 4.0f * t * t * t : 1.0f - std::pow(-2.0f * t + 2.0f, 3.0f) / 2.0f;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 四次缓动 (Quart)
|
||||
// ============================================================================
|
||||
|
||||
float easeInQuart(float t) {
|
||||
return t * t * t * t;
|
||||
}
|
||||
|
||||
float easeOutQuart(float t) {
|
||||
return 1.0f - std::pow(1.0f - t, 4.0f);
|
||||
}
|
||||
|
||||
float easeInOutQuart(float t) {
|
||||
return t < 0.5f ? 8.0f * t * t * t * t : 1.0f - std::pow(-2.0f * t + 2.0f, 4.0f) / 2.0f;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 五次缓动 (Quint)
|
||||
// ============================================================================
|
||||
|
||||
float easeInQuint(float t) {
|
||||
return t * t * t * t * t;
|
||||
}
|
||||
|
||||
float easeOutQuint(float t) {
|
||||
return 1.0f - std::pow(1.0f - t, 5.0f);
|
||||
}
|
||||
|
||||
float easeInOutQuint(float t) {
|
||||
return t < 0.5f ? 16.0f * t * t * t * t * t : 1.0f - std::pow(-2.0f * t + 2.0f, 5.0f) / 2.0f;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 正弦缓动 (Sine)
|
||||
// ============================================================================
|
||||
|
||||
float easeInSine(float t) {
|
||||
return 1.0f - std::cos((t * M_PI) / 2.0f);
|
||||
}
|
||||
|
||||
float easeOutSine(float t) {
|
||||
return std::sin((t * M_PI) / 2.0f);
|
||||
}
|
||||
|
||||
float easeInOutSine(float t) {
|
||||
return -(std::cos(M_PI * t) - 1.0f) / 2.0f;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 指数缓动 (Exponential)
|
||||
// ============================================================================
|
||||
|
||||
float easeInExpo(float t) {
|
||||
return t == 0.0f ? 0.0f : std::pow(2.0f, 10.0f * (t - 1.0f));
|
||||
}
|
||||
|
||||
float easeOutExpo(float t) {
|
||||
return t == 1.0f ? 1.0f : 1.0f - std::pow(2.0f, -10.0f * t);
|
||||
}
|
||||
|
||||
float easeInOutExpo(float t) {
|
||||
if (t == 0.0f) return 0.0f;
|
||||
if (t == 1.0f) return 1.0f;
|
||||
return t < 0.5f
|
||||
? std::pow(2.0f, 20.0f * t - 10.0f) / 2.0f
|
||||
: (2.0f - std::pow(2.0f, -20.0f * t + 10.0f)) / 2.0f;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 圆形缓动 (Circular)
|
||||
// ============================================================================
|
||||
|
||||
float easeInCirc(float t) {
|
||||
return 1.0f - std::sqrt(1.0f - std::pow(t, 2.0f));
|
||||
}
|
||||
|
||||
float easeOutCirc(float t) {
|
||||
return std::sqrt(1.0f - std::pow(t - 1.0f, 2.0f));
|
||||
}
|
||||
|
||||
float easeInOutCirc(float t) {
|
||||
return t < 0.5f
|
||||
? (1.0f - std::sqrt(1.0f - std::pow(2.0f * t, 2.0f))) / 2.0f
|
||||
: (std::sqrt(1.0f - std::pow(-2.0f * t + 2.0f, 2.0f)) + 1.0f) / 2.0f;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 回震缓动 (Back)
|
||||
// ============================================================================
|
||||
|
||||
float easeInBack(float t) {
|
||||
const float c1 = 1.70158f;
|
||||
const float c3 = c1 + 1.0f;
|
||||
return c3 * t * t * t - c1 * t * t;
|
||||
}
|
||||
|
||||
float easeOutBack(float t) {
|
||||
const float c1 = 1.70158f;
|
||||
const float c3 = c1 + 1.0f;
|
||||
return 1.0f + c3 * std::pow(t - 1.0f, 3.0f) + c1 * std::pow(t - 1.0f, 2.0f);
|
||||
}
|
||||
|
||||
float easeInOutBack(float t) {
|
||||
const float c1 = 1.70158f;
|
||||
const float c2 = c1 * 1.525f;
|
||||
return t < 0.5f
|
||||
? (std::pow(2.0f * t, 2.0f) * ((c2 + 1.0f) * 2.0f * t - c2)) / 2.0f
|
||||
: (std::pow(2.0f * t - 2.0f, 2.0f) * ((c2 + 1.0f) * (t * 2.0f - 2.0f) + c2) + 2.0f) / 2.0f;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 弹性缓动 (Elastic)
|
||||
// ============================================================================
|
||||
|
||||
float easeInElastic(float t) {
|
||||
const float c4 = (2.0f * M_PI) / 3.0f;
|
||||
if (t == 0.0f) return 0.0f;
|
||||
if (t == 1.0f) return 1.0f;
|
||||
return -std::pow(2.0f, 10.0f * t - 10.0f) * std::sin((t * 10.0f - 10.75f) * c4);
|
||||
}
|
||||
|
||||
float easeOutElastic(float t) {
|
||||
const float c4 = (2.0f * M_PI) / 3.0f;
|
||||
if (t == 0.0f) return 0.0f;
|
||||
if (t == 1.0f) return 1.0f;
|
||||
return std::pow(2.0f, -10.0f * t) * std::sin((t * 10.0f - 0.75f) * c4) + 1.0f;
|
||||
}
|
||||
|
||||
float easeInOutElastic(float t) {
|
||||
const float c5 = (2.0f * M_PI) / 4.5f;
|
||||
if (t == 0.0f) return 0.0f;
|
||||
if (t == 1.0f) return 1.0f;
|
||||
return t < 0.5f
|
||||
? -(std::pow(2.0f, 20.0f * t - 10.0f) * std::sin((20.0f * t - 11.125f) * c5)) / 2.0f
|
||||
: (std::pow(2.0f, -20.0f * t + 10.0f) * std::sin((20.0f * t - 11.125f) * c5)) / 2.0f + 1.0f;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 弹跳缓动 (Bounce)
|
||||
// ============================================================================
|
||||
|
||||
namespace {
|
||||
float easeOutBounceInternal(float t) {
|
||||
const float n1 = 7.5625f;
|
||||
const float d1 = 2.75f;
|
||||
|
||||
if (t < 1.0f / d1) {
|
||||
return n1 * t * t;
|
||||
} else if (t < 2.0f / d1) {
|
||||
t -= 1.5f / d1;
|
||||
return n1 * t * t + 0.75f;
|
||||
} else if (t < 2.5f / d1) {
|
||||
t -= 2.25f / d1;
|
||||
return n1 * t * t + 0.9375f;
|
||||
} else {
|
||||
t -= 2.625f / d1;
|
||||
return n1 * t * t + 0.984375f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float easeInBounce(float t) {
|
||||
return 1.0f - easeOutBounceInternal(1.0f - t);
|
||||
}
|
||||
|
||||
float easeOutBounce(float t) {
|
||||
return easeOutBounceInternal(t);
|
||||
}
|
||||
|
||||
float easeInOutBounce(float t) {
|
||||
return t < 0.5f
|
||||
? (1.0f - easeOutBounceInternal(1.0f - 2.0f * t)) / 2.0f
|
||||
: (1.0f + easeOutBounceInternal(2.0f * t - 1.0f)) / 2.0f;
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#include "action/finite_time_action.h"
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
FiniteTimeAction::FiniteTimeAction(float duration)
|
||||
: duration_(duration) {
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -43,18 +43,14 @@ void GameOverLayer::onEnter() {
|
|||
// 初始化按钮
|
||||
initButtons();
|
||||
|
||||
// 创建向上移动的动画(从屏幕底部移动到正常位置)
|
||||
auto moveAction = extra2d::MoveBy::create(1.0f, extra2d::Vec2(0.0f, -screenHeight));
|
||||
moveAction->setCompletionCallback([this]() {
|
||||
animationDone_ = true;
|
||||
if (restartBtn_)
|
||||
restartBtn_->setEnabled(true);
|
||||
if (menuBtn_)
|
||||
menuBtn_->setEnabled(true);
|
||||
if (shareBtn_)
|
||||
shareBtn_->setEnabled(true);
|
||||
});
|
||||
runAction(moveAction);
|
||||
// 动画完成,启用按钮
|
||||
animationDone_ = true;
|
||||
if (restartBtn_)
|
||||
restartBtn_->setEnabled(true);
|
||||
if (menuBtn_)
|
||||
menuBtn_->setEnabled(true);
|
||||
if (shareBtn_)
|
||||
shareBtn_->setEnabled(true);
|
||||
}
|
||||
|
||||
void GameOverLayer::initPanel(int score, float screenHeight) {
|
||||
|
|
|
|||
|
|
@ -64,18 +64,6 @@
|
|||
#include <ui/radio_button.h>
|
||||
#include <ui/slider.h>
|
||||
|
||||
// Action
|
||||
#include <action/action.h>
|
||||
#include <action/finite_time_action.h>
|
||||
#include <action/action_interval.h>
|
||||
#include <action/action_instant.h>
|
||||
#include <action/action_interval_actions.h>
|
||||
#include <action/action_instant_actions.h>
|
||||
#include <action/action_ease.h>
|
||||
#include <action/action_special.h>
|
||||
#include <action/action_manager.h>
|
||||
#include <action/ease.h>
|
||||
|
||||
// Event
|
||||
#include <event/event.h>
|
||||
#include <event/event_queue.h>
|
||||
|
|
@ -1,21 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <audio/sound.h>
|
||||
#include <core/types.h>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <graphics/alpha_mask.h>
|
||||
#include <graphics/font.h>
|
||||
#include <graphics/texture.h>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -25,14 +25,14 @@ namespace extra2d {
|
|||
|
||||
// 纹理格式枚举
|
||||
enum class TextureFormat {
|
||||
Auto = 0, // 自动选择最佳格式
|
||||
RGBA8, // 32位 RGBA
|
||||
RGB8, // 24位 RGB
|
||||
DXT1, // BC1/DXT1 压缩(1 bit alpha)
|
||||
DXT5, // BC3/DXT5 压缩(完整 alpha)
|
||||
ETC2, // ETC2 压缩(移动平台)
|
||||
ASTC4x4, // ASTC 4x4 压缩(高质量)
|
||||
ASTC8x8, // ASTC 8x8 压缩(高压缩率)
|
||||
Auto = 0, // 自动选择最佳格式
|
||||
RGBA8, // 32位 RGBA
|
||||
RGB8, // 24位 RGB
|
||||
DXT1, // BC1/DXT1 压缩(1 bit alpha)
|
||||
DXT5, // BC3/DXT5 压缩(完整 alpha)
|
||||
ETC2, // ETC2 压缩(移动平台)
|
||||
ASTC4x4, // ASTC 4x4 压缩(高质量)
|
||||
ASTC8x8, // ASTC 8x8 压缩(高压缩率)
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -40,9 +40,9 @@ enum class TextureFormat {
|
|||
// ============================================================================
|
||||
struct TextureCacheEntry {
|
||||
Ptr<Texture> texture;
|
||||
size_t size = 0; // 纹理大小(字节)
|
||||
float lastAccessTime = 0.0f; // 最后访问时间
|
||||
uint32_t accessCount = 0; // 访问次数
|
||||
size_t size = 0; // 纹理大小(字节)
|
||||
float lastAccessTime = 0.0f; // 最后访问时间
|
||||
uint32_t accessCount = 0; // 访问次数
|
||||
};
|
||||
|
||||
// 异步加载回调类型
|
||||
|
|
@ -66,13 +66,16 @@ public:
|
|||
Ptr<Texture> loadTexture(const std::string &filepath, bool async);
|
||||
|
||||
/// 加载纹理(完整参数:异步 + 压缩格式)
|
||||
Ptr<Texture> loadTexture(const std::string &filepath, bool async, TextureFormat format);
|
||||
Ptr<Texture> loadTexture(const std::string &filepath, bool async,
|
||||
TextureFormat format);
|
||||
|
||||
/// 异步加载纹理(带回调)
|
||||
void loadTextureAsync(const std::string &filepath, TextureLoadCallback callback);
|
||||
void loadTextureAsync(const std::string &filepath,
|
||||
TextureLoadCallback callback);
|
||||
|
||||
/// 异步加载纹理(指定格式 + 回调)
|
||||
void loadTextureAsync(const std::string &filepath, TextureFormat format, TextureLoadCallback callback);
|
||||
void loadTextureAsync(const std::string &filepath, TextureFormat format,
|
||||
TextureLoadCallback callback);
|
||||
|
||||
/// 加载纹理并生成Alpha遮罩(用于不规则形状图片)
|
||||
Ptr<Texture> loadTextureWithAlphaMask(const std::string &filepath);
|
||||
|
|
@ -146,7 +149,8 @@ public:
|
|||
/// @param filepath 文件路径
|
||||
/// @param encoding 文件编码(默认 UTF-8)
|
||||
/// @return 文件内容字符串
|
||||
std::string loadTextFile(const std::string &filepath, const std::string &encoding);
|
||||
std::string loadTextFile(const std::string &filepath,
|
||||
const std::string &encoding);
|
||||
|
||||
/// 通过key获取已缓存的文本内容
|
||||
std::string getTextFile(const std::string &key) const;
|
||||
|
|
@ -251,14 +255,16 @@ private:
|
|||
bool useSDF) const;
|
||||
|
||||
// 内部加载实现
|
||||
Ptr<Texture> loadTextureInternal(const std::string &filepath, TextureFormat format);
|
||||
Ptr<Texture> loadTextureInternal(const std::string &filepath,
|
||||
TextureFormat format);
|
||||
|
||||
// 选择最佳纹理格式
|
||||
TextureFormat selectBestFormat(TextureFormat requested) const;
|
||||
|
||||
// 压缩纹理数据
|
||||
std::vector<uint8_t> compressTexture(const uint8_t* data, int width, int height,
|
||||
int channels, TextureFormat format);
|
||||
std::vector<uint8_t> compressTexture(const uint8_t *data, int width,
|
||||
int height, int channels,
|
||||
TextureFormat format);
|
||||
|
||||
// 互斥锁保护缓存
|
||||
mutable std::mutex textureMutex_;
|
||||
|
|
@ -282,24 +288,24 @@ private:
|
|||
// LRU链表节点
|
||||
struct LRUNode {
|
||||
std::string key;
|
||||
uint32_t prev = 0; // 数组索引,0表示无效
|
||||
uint32_t next = 0; // 数组索引,0表示无效
|
||||
uint32_t prev = 0; // 数组索引,0表示无效
|
||||
uint32_t next = 0; // 数组索引,0表示无效
|
||||
bool valid = false;
|
||||
};
|
||||
|
||||
// 纹理缓存配置
|
||||
size_t maxCacheSize_ = 64 * 1024 * 1024; // 最大缓存大小 (64MB)
|
||||
size_t maxTextureCount_ = 256; // 最大纹理数量
|
||||
float unloadInterval_ = 30.0f; // 自动清理间隔 (秒)
|
||||
size_t maxCacheSize_ = 64 * 1024 * 1024; // 最大缓存大小 (64MB)
|
||||
size_t maxTextureCount_ = 256; // 最大纹理数量
|
||||
float unloadInterval_ = 30.0f; // 自动清理间隔 (秒)
|
||||
|
||||
// 纹理缓存 - 使用强指针保持引用
|
||||
std::unordered_map<std::string, TextureCacheEntry> textureCache_;
|
||||
|
||||
// 侵入式LRU链表 - 使用数组索引代替指针,提高缓存局部性
|
||||
std::vector<LRUNode> lruNodes_;
|
||||
uint32_t lruHead_ = 0; // 最近使用
|
||||
uint32_t lruTail_ = 0; // 最久未使用
|
||||
uint32_t freeList_ = 0; // 空闲节点链表
|
||||
uint32_t lruHead_ = 0; // 最近使用
|
||||
uint32_t lruTail_ = 0; // 最久未使用
|
||||
uint32_t freeList_ = 0; // 空闲节点链表
|
||||
|
||||
// 统计
|
||||
size_t totalTextureSize_ = 0;
|
||||
|
|
@ -14,7 +14,6 @@ namespace extra2d {
|
|||
|
||||
// 前向声明
|
||||
class Scene;
|
||||
class Action;
|
||||
class RenderBackend;
|
||||
struct RenderCommand;
|
||||
|
||||
|
|
@ -155,58 +154,6 @@ public:
|
|||
// 更新空间索引(手动调用,通常在边界框变化后)
|
||||
void updateSpatialIndex();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 动作系统
|
||||
// ------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief 运行动作
|
||||
* @param action 动作指针(所有权转移)
|
||||
* @return 动作指针
|
||||
*/
|
||||
Action* runAction(Action* action);
|
||||
|
||||
/**
|
||||
* @brief 停止所有动作
|
||||
*/
|
||||
void stopAllActions();
|
||||
|
||||
/**
|
||||
* @brief 停止指定动作
|
||||
* @param action 动作指针
|
||||
*/
|
||||
void stopAction(Action* action);
|
||||
|
||||
/**
|
||||
* @brief 根据标签停止动作
|
||||
* @param tag 标签值
|
||||
*/
|
||||
void stopActionByTag(int tag);
|
||||
|
||||
/**
|
||||
* @brief 根据标志位停止动作
|
||||
* @param flags 标志位
|
||||
*/
|
||||
void stopActionsByFlags(unsigned int flags);
|
||||
|
||||
/**
|
||||
* @brief 根据标签获取动作
|
||||
* @param tag 标签值
|
||||
* @return 动作指针,未找到返回 nullptr
|
||||
*/
|
||||
Action* getActionByTag(int tag);
|
||||
|
||||
/**
|
||||
* @brief 获取运行中的动作数量
|
||||
* @return 动作数量
|
||||
*/
|
||||
size_t getActionCount() const;
|
||||
|
||||
/**
|
||||
* @brief 检查是否有动作在运行
|
||||
* @return true 如果有动作在运行
|
||||
*/
|
||||
bool isRunningActions() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 事件系统
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
@ -1,782 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Extra2D 项目脚手架工具
|
||||
用于快速创建新的 Extra2D 游戏项目
|
||||
|
||||
用法:
|
||||
python create_project.py <项目名称> [选项]
|
||||
|
||||
示例:
|
||||
python create_project.py my_game
|
||||
python create_project.py my_game --path ./games
|
||||
python create_project.py my_game --author "Your Name"
|
||||
|
||||
项目结构:
|
||||
my_game/
|
||||
├── src/
|
||||
│ └── main.cpp
|
||||
├── romfs/
|
||||
│ └── assets/
|
||||
├── xmake.lua
|
||||
├── README.md
|
||||
└── Extra2D/ # 引擎源码(自动克隆)
|
||||
├── Extra2D/
|
||||
├── xmake/
|
||||
└── ...
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import subprocess
|
||||
import platform
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
ENGINE_REPO = "https://github.com/ChestnutYueyue/Extra2D.git"
|
||||
DEVKITPRO_URL = "https://github.com/devkitPro/installer/releases/download/v3.0.3/devkitProUpdater-3.0.3.exe"
|
||||
MINGW_URL = "https://github.com/brechtsanders/winlibs_mingw/releases/download/16.0.0-snapshot20251026posix-14.0.0-ucrt-r1/winlibs-i686-posix-dwarf-gcc-16.0.0-snapshot20251026-mingw-w64ucrt-14.0.0-r1.zip"
|
||||
|
||||
|
||||
class DevToolsChecker:
|
||||
"""开发工具检测器"""
|
||||
|
||||
def __init__(self):
|
||||
self.is_windows = platform.system() == "Windows"
|
||||
|
||||
def check_git(self) -> bool:
|
||||
"""检查 Git 是否安装"""
|
||||
return shutil.which("git") is not None
|
||||
|
||||
def check_xmake(self) -> bool:
|
||||
"""检查 xmake 是否安装"""
|
||||
return shutil.which("xmake") is not None
|
||||
|
||||
def check_mingw(self) -> bool:
|
||||
"""检查 MinGW 是否安装"""
|
||||
if shutil.which("gcc"):
|
||||
result = subprocess.run(
|
||||
["gcc", "-dumpmachine"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
creationflags=subprocess.CREATE_NO_WINDOW if self.is_windows else 0
|
||||
)
|
||||
return "mingw" in result.stdout.lower()
|
||||
return False
|
||||
|
||||
def check_devkitpro(self) -> bool:
|
||||
"""检查 devkitPro 是否安装"""
|
||||
devkitpro = os.environ.get("DEVKITPRO", "C:/devkitPro")
|
||||
devkita64 = os.path.join(devkitpro, "devkitA64")
|
||||
return os.path.isdir(devkita64)
|
||||
|
||||
def get_missing_tools(self) -> dict:
|
||||
"""获取缺失的工具列表"""
|
||||
missing = {}
|
||||
|
||||
if not self.check_git():
|
||||
missing["git"] = "Git 版本控制工具"
|
||||
|
||||
if not self.check_xmake():
|
||||
missing["xmake"] = "xmake 构建工具"
|
||||
|
||||
return missing
|
||||
|
||||
def get_missing_dev_tools(self) -> dict:
|
||||
"""获取缺失的开发工具链"""
|
||||
missing = {}
|
||||
|
||||
if not self.check_mingw():
|
||||
missing["mingw"] = MINGW_URL
|
||||
|
||||
if not self.check_devkitpro():
|
||||
missing["devkitpro"] = DEVKITPRO_URL
|
||||
|
||||
return missing
|
||||
|
||||
def print_tool_status(self):
|
||||
"""打印工具状态"""
|
||||
print("\n========================================")
|
||||
print("开发环境检测")
|
||||
print("========================================")
|
||||
|
||||
tools = [
|
||||
("Git", self.check_git()),
|
||||
("xmake", self.check_xmake()),
|
||||
("MinGW (Windows开发)", self.check_mingw()),
|
||||
("devkitPro (Switch开发)", self.check_devkitpro()),
|
||||
]
|
||||
|
||||
for name, installed in tools:
|
||||
status = "✓ 已安装" if installed else "✗ 未安装"
|
||||
print(f" {name}: {status}")
|
||||
|
||||
print("========================================\n")
|
||||
|
||||
|
||||
class ProjectCreator:
|
||||
"""Extra2D 项目创建器"""
|
||||
|
||||
def __init__(self, project_name: str, output_path: str = None, author: str = "Extra2D Team"):
|
||||
self.project_name = project_name
|
||||
self.author = author
|
||||
self.output_path = Path(output_path) if output_path else Path.cwd()
|
||||
self.project_path = self.output_path / project_name
|
||||
self.engine_path = self.project_path / "Extra2D"
|
||||
|
||||
def create(self) -> bool:
|
||||
"""创建项目"""
|
||||
print(f"\n正在创建 Extra2D 项目: {self.project_name}")
|
||||
print(f"项目路径: {self.project_path}")
|
||||
|
||||
if self.project_path.exists():
|
||||
print(f"错误: 项目目录已存在: {self.project_path}")
|
||||
return False
|
||||
|
||||
try:
|
||||
self._create_directories()
|
||||
self._copy_system_font()
|
||||
self._create_main_cpp()
|
||||
self._create_xmake_lua()
|
||||
self._create_gitignore()
|
||||
self._create_readme()
|
||||
|
||||
print(f"\n✓ 项目创建成功!")
|
||||
|
||||
if self._clone_engine():
|
||||
self._print_next_steps()
|
||||
else:
|
||||
print("\n请手动克隆引擎源码:")
|
||||
print(f" cd {self.project_path}")
|
||||
print(f" git clone {ENGINE_REPO} Extra2D")
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"创建项目时出错: {e}")
|
||||
return False
|
||||
|
||||
def _create_directories(self):
|
||||
"""创建项目目录结构"""
|
||||
print("创建目录结构...")
|
||||
self.project_path.mkdir(parents=True, exist_ok=True)
|
||||
(self.project_path / "romfs" / "assets" / "images").mkdir(parents=True, exist_ok=True)
|
||||
(self.project_path / "romfs" / "assets" / "audio").mkdir(parents=True, exist_ok=True)
|
||||
(self.project_path / "src").mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def _copy_system_font(self):
|
||||
"""复制系统字体到项目 assets 目录"""
|
||||
print("复制系统字体...")
|
||||
font_dest = self.project_path / "romfs" / "assets" / "font.ttf"
|
||||
|
||||
if platform.system() == "Windows":
|
||||
font_sources = [
|
||||
Path("C:/Windows/Fonts/msyh.ttc"), # 微软雅黑
|
||||
Path("C:/Windows/Fonts/msyh.ttf"), # 微软雅黑 (部分系统)
|
||||
Path("C:/Windows/Fonts/simhei.ttf"), # 黑体
|
||||
Path("C:/Windows/Fonts/simsun.ttc"), # 宋体
|
||||
]
|
||||
else:
|
||||
font_sources = [
|
||||
Path("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"),
|
||||
Path("/usr/share/fonts/TTF/DejaVuSans.ttf"),
|
||||
Path("/System/Library/Fonts/PingFang.ttc"), # macOS
|
||||
]
|
||||
|
||||
for font_src in font_sources:
|
||||
if font_src.exists():
|
||||
try:
|
||||
shutil.copy2(str(font_src), str(font_dest))
|
||||
print(f"✓ 已复制字体: {font_src.name}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 复制字体失败: {e}")
|
||||
continue
|
||||
|
||||
print("⚠ 未找到系统字体,请手动添加字体文件到 romfs/assets/font.ttf")
|
||||
return False
|
||||
|
||||
def _clone_engine(self) -> bool:
|
||||
"""克隆引擎源码到项目目录内的 Extra2D 子目录"""
|
||||
print(f"\n正在克隆 Extra2D 引擎源码...")
|
||||
print(f"仓库地址: {ENGINE_REPO}")
|
||||
print(f"目标路径: {self.engine_path}")
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["git", "clone", ENGINE_REPO, str(self.engine_path)],
|
||||
cwd=str(self.project_path),
|
||||
creationflags=subprocess.CREATE_NO_WINDOW if platform.system() == "Windows" else 0
|
||||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
print("✓ 引擎源码克隆成功!")
|
||||
return True
|
||||
else:
|
||||
print("✗ 引擎源码克隆失败!")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"✗ 克隆过程中出错: {e}")
|
||||
return False
|
||||
|
||||
def _create_main_cpp(self):
|
||||
"""创建 main.cpp 文件(放在 src 目录下)"""
|
||||
print("创建 src/main.cpp...")
|
||||
content = f'''#include <extra2d/extra2d.h>
|
||||
|
||||
using namespace extra2d;
|
||||
|
||||
// ============================================================================
|
||||
// 主场景
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 主游戏场景
|
||||
*/
|
||||
class MainScene : public Scene {{
|
||||
public:
|
||||
/**
|
||||
* @brief 场景进入时调用
|
||||
*/
|
||||
void onEnter() override {{
|
||||
E2D_LOG_INFO("MainScene::onEnter - 进入场景");
|
||||
|
||||
// 设置背景颜色
|
||||
setBackgroundColor(Color(0.1f, 0.1f, 0.2f, 1.0f));
|
||||
|
||||
// 加载字体(请确保 assets 目录下有 font.ttf 文件)
|
||||
auto &resources = Application::instance().resources();
|
||||
font_ = resources.loadFont("assets/font.ttf", 32, true);
|
||||
|
||||
if (!font_) {{
|
||||
E2D_LOG_ERROR("字体加载失败!请确保 assets 目录下有 font.ttf 文件");
|
||||
return;
|
||||
}}
|
||||
|
||||
// 创建标题文本
|
||||
auto title = Text::create("{self.project_name}", font_);
|
||||
title->setCoordinateSpace(CoordinateSpace::Screen);
|
||||
title->setScreenPosition(640.0f, 200.0f);
|
||||
title->setAnchor(0.5f, 0.5f);
|
||||
title->setTextColor(Color(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
addChild(title);
|
||||
|
||||
// 创建提示文本
|
||||
auto hint = Text::create("按 START 退出", font_);
|
||||
hint->setCoordinateSpace(CoordinateSpace::Screen);
|
||||
hint->setScreenPosition(640.0f, 650.0f);
|
||||
hint->setAnchor(0.5f, 0.5f);
|
||||
hint->setTextColor(Color(0.7f, 0.7f, 0.7f, 1.0f));
|
||||
addChild(hint);
|
||||
}}
|
||||
|
||||
/**
|
||||
* @brief 每帧更新时调用
|
||||
* @param dt 时间间隔(秒)
|
||||
*/
|
||||
void onUpdate(float dt) override {{
|
||||
Scene::onUpdate(dt);
|
||||
|
||||
// 检查退出按键
|
||||
auto &input = Application::instance().input();
|
||||
if (input.isButtonPressed(GamepadButton::Start)) {{
|
||||
E2D_LOG_INFO("退出应用");
|
||||
Application::instance().quit();
|
||||
}}
|
||||
}}
|
||||
|
||||
private:
|
||||
Ptr<FontAtlas> font_;
|
||||
}};
|
||||
|
||||
// ============================================================================
|
||||
// 程序入口
|
||||
// ============================================================================
|
||||
|
||||
int main(int argc, char **argv) {{
|
||||
// 初始化日志系统
|
||||
Logger::init();
|
||||
Logger::setLevel(LogLevel::Debug);
|
||||
|
||||
E2D_LOG_INFO("========================");
|
||||
E2D_LOG_INFO("{self.project_name}");
|
||||
E2D_LOG_INFO("========================");
|
||||
|
||||
// 获取应用实例
|
||||
auto &app = Application::instance();
|
||||
|
||||
// 配置应用
|
||||
AppConfig config;
|
||||
config.title = "{self.project_name}";
|
||||
config.width = 1280;
|
||||
config.height = 720;
|
||||
config.vsync = true;
|
||||
config.fpsLimit = 60;
|
||||
|
||||
// 初始化应用
|
||||
if (!app.init(config)) {{
|
||||
E2D_LOG_ERROR("应用初始化失败!");
|
||||
return -1;
|
||||
}}
|
||||
|
||||
// 进入主场景
|
||||
app.enterScene(makePtr<MainScene>());
|
||||
|
||||
E2D_LOG_INFO("开始主循环...");
|
||||
|
||||
// 运行应用
|
||||
app.run();
|
||||
|
||||
E2D_LOG_INFO("应用结束");
|
||||
|
||||
return 0;
|
||||
}}
|
||||
'''
|
||||
with open(self.project_path / "src" / "main.cpp", "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
|
||||
def _create_xmake_lua(self):
|
||||
"""创建 xmake.lua 文件(使用项目内的引擎源码)"""
|
||||
print("创建 xmake.lua...")
|
||||
content = f'''-- ==============================================
|
||||
-- {self.project_name} - Extra2D 游戏项目
|
||||
-- 构建系统: Xmake
|
||||
-- 支持平台: MinGW (Windows), Nintendo Switch
|
||||
-- ==============================================
|
||||
|
||||
-- 项目元信息
|
||||
set_project("{self.project_name}")
|
||||
set_version("1.0.0")
|
||||
set_license("MIT")
|
||||
|
||||
-- 语言设置
|
||||
set_languages("c++17")
|
||||
set_encodings("utf-8")
|
||||
|
||||
-- 构建模式
|
||||
add_rules("mode.debug", "mode.release")
|
||||
|
||||
-- ==============================================
|
||||
-- 平台检测与配置
|
||||
-- ==============================================
|
||||
|
||||
local host_plat = os.host()
|
||||
local target_plat = get_config("plat") or host_plat
|
||||
local supported_plats = {{mingw = true, switch = true}}
|
||||
|
||||
if not supported_plats[target_plat] then
|
||||
if host_plat == "windows" then
|
||||
target_plat = "mingw"
|
||||
else
|
||||
error("Unsupported platform: " .. target_plat .. ". Supported platforms: mingw, switch")
|
||||
end
|
||||
end
|
||||
|
||||
set_plat(target_plat)
|
||||
|
||||
if target_plat == "switch" then
|
||||
set_arch("arm64")
|
||||
elseif target_plat == "mingw" then
|
||||
set_arch("x86_64")
|
||||
end
|
||||
|
||||
-- ==============================================
|
||||
-- 加载工具链配置
|
||||
-- ==============================================
|
||||
|
||||
-- 引擎目录(克隆的仓库目录)
|
||||
local engine_repo = "Extra2D"
|
||||
-- 引擎源码目录(仓库内的 Extra2D 子目录)
|
||||
local engine_src = path.join(engine_repo, "Extra2D")
|
||||
|
||||
if target_plat == "switch" then
|
||||
includes(path.join(engine_repo, "xmake/toolchains/switch.lua"))
|
||||
set_toolchains("switch")
|
||||
elseif target_plat == "mingw" then
|
||||
set_toolchains("mingw")
|
||||
end
|
||||
|
||||
-- ==============================================
|
||||
-- 添加依赖包 (MinGW)
|
||||
-- ==============================================
|
||||
|
||||
if target_plat == "mingw" then
|
||||
add_requires("glm", "libsdl2", "libsdl2_mixer")
|
||||
end
|
||||
|
||||
-- ==============================================
|
||||
-- 引擎库定义
|
||||
-- ==============================================
|
||||
|
||||
target("extra2d")
|
||||
set_kind("static")
|
||||
|
||||
-- 引擎源文件
|
||||
add_files(path.join(engine_src, "src/**.cpp"))
|
||||
add_files(path.join(engine_src, "src/glad/glad.c"))
|
||||
|
||||
-- 头文件路径
|
||||
add_includedirs(path.join(engine_src, "include"), {{public = true}})
|
||||
add_includedirs(path.join(engine_src, "include/extra2d/platform"), {{public = true}})
|
||||
|
||||
-- 平台配置
|
||||
if target_plat == "switch" then
|
||||
local devkitPro = os.getenv("DEVKITPRO") or "C:/devkitPro"
|
||||
add_includedirs(devkitPro .. "/portlibs/switch/include", {{public = true}})
|
||||
add_linkdirs(devkitPro .. "/portlibs/switch/lib")
|
||||
add_syslinks("SDL2_mixer", "SDL2", "opusfile", "opus", "vorbisidec", "ogg",
|
||||
"modplug", "mpg123", "FLAC", "GLESv2", "EGL", "glapi", "drm_nouveau",
|
||||
{{public = true}})
|
||||
elseif target_plat == "mingw" then
|
||||
add_packages("glm", "libsdl2", "libsdl2_mixer", {{public = true}})
|
||||
add_syslinks("opengl32", "glu32", "winmm", "imm32", "version", "setupapi", {{public = true}})
|
||||
end
|
||||
|
||||
-- 编译器标志
|
||||
add_cxflags("-Wall", "-Wextra", {{force = true}})
|
||||
add_cxflags("-Wno-unused-variable", "-Wno-unused-function", "-Wno-unused-parameter", {{force = true}})
|
||||
add_cxflags("-Wno-strict-aliasing", "-Wno-implicit-fallthrough", {{force = true}})
|
||||
add_cxflags("-Wno-missing-field-initializers", {{force = true}})
|
||||
add_cxxflags("-Wno-deprecated-copy", "-Wno-class-memaccess", {{force = true}})
|
||||
|
||||
if is_mode("debug") then
|
||||
add_defines("E2D_DEBUG", "_DEBUG", {{public = true}})
|
||||
add_cxxflags("-O0", "-g", {{force = true}})
|
||||
else
|
||||
add_defines("NDEBUG", {{public = true}})
|
||||
add_cxxflags("-O2", {{force = true}})
|
||||
end
|
||||
target_end()
|
||||
|
||||
-- ==============================================
|
||||
-- 目标定义
|
||||
-- ==============================================
|
||||
|
||||
target("{self.project_name}")
|
||||
set_kind("binary")
|
||||
add_files("src/**.cpp")
|
||||
add_deps("extra2d")
|
||||
|
||||
-- Nintendo Switch 平台配置
|
||||
if is_plat("switch") then
|
||||
set_targetdir("build/switch")
|
||||
|
||||
-- 构建后生成 NRO 文件
|
||||
after_build(function (target)
|
||||
local devkitPro = os.getenv("DEVKITPRO") or "C:/devkitPro"
|
||||
local elf_file = target:targetfile()
|
||||
local output_dir = path.directory(elf_file)
|
||||
local nacp_file = path.join(output_dir, "{self.project_name}.nacp")
|
||||
local nro_file = path.join(output_dir, "{self.project_name}.nro")
|
||||
local nacptool = path.join(devkitPro, "tools/bin/nacptool.exe")
|
||||
local elf2nro = path.join(devkitPro, "tools/bin/elf2nro.exe")
|
||||
|
||||
if os.isfile(nacptool) and os.isfile(elf2nro) then
|
||||
os.vrunv(nacptool, {{"--create", "{self.project_name}", "{self.author}", "1.0.0", nacp_file}})
|
||||
local project_dir = os.scriptdir()
|
||||
local romfs = path.join(project_dir, "romfs")
|
||||
if os.isdir(romfs) then
|
||||
os.vrunv(elf2nro, {{elf_file, nro_file, "--nacp=" .. nacp_file, "--romfsdir=" .. romfs}})
|
||||
else
|
||||
os.vrunv(elf2nro, {{elf_file, nro_file, "--nacp=" .. nacp_file}})
|
||||
end
|
||||
print("Generated NRO: " .. nro_file)
|
||||
end
|
||||
end)
|
||||
|
||||
-- 打包时将 NRO 文件复制到 package 目录
|
||||
after_package(function (target)
|
||||
local nro_file = path.join(target:targetdir(), "{self.project_name}.nro")
|
||||
local package_dir = target:packagedir()
|
||||
if os.isfile(nro_file) and package_dir then
|
||||
os.cp(nro_file, package_dir)
|
||||
print("Copied NRO to package: " .. package_dir)
|
||||
end
|
||||
end)
|
||||
|
||||
-- Windows 平台配置
|
||||
elseif is_plat("mingw", "windows") then
|
||||
set_targetdir("build/windows")
|
||||
add_ldflags("-mwindows", {{force = true}})
|
||||
|
||||
-- 复制资源到输出目录
|
||||
after_build(function (target)
|
||||
local project_dir = os.scriptdir()
|
||||
local romfs = path.join(project_dir, "romfs")
|
||||
if os.isdir(romfs) then
|
||||
local target_dir = path.directory(target:targetfile())
|
||||
local assets_dir = path.join(target_dir, "assets")
|
||||
|
||||
if not os.isdir(assets_dir) then
|
||||
os.mkdir(assets_dir)
|
||||
end
|
||||
|
||||
os.cp(path.join(romfs, "assets/**"), assets_dir)
|
||||
print("Copied assets to: " .. assets_dir)
|
||||
end
|
||||
end)
|
||||
end
|
||||
target_end()
|
||||
|
||||
-- ==============================================
|
||||
-- 项目信息输出
|
||||
-- ==============================================
|
||||
|
||||
print("========================================")
|
||||
print("{self.project_name} Build Configuration")
|
||||
print("========================================")
|
||||
print("Platform: " .. target_plat)
|
||||
print("Architecture: " .. (get_config("arch") or "auto"))
|
||||
print("Mode: " .. (is_mode("debug") and "debug" or "release"))
|
||||
print("========================================")
|
||||
'''
|
||||
with open(self.project_path / "xmake.lua", "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
|
||||
def _create_gitignore(self):
|
||||
"""创建 .gitignore 文件"""
|
||||
print("创建 .gitignore...")
|
||||
content = '''# 构建产物
|
||||
.build/
|
||||
build/
|
||||
.xmake/
|
||||
|
||||
# IDE 配置
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# 操作系统文件
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# 临时文件
|
||||
*.tmp
|
||||
*.temp
|
||||
*.log
|
||||
'''
|
||||
with open(self.project_path / ".gitignore", "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
|
||||
def _create_readme(self):
|
||||
"""创建 README.md 文件"""
|
||||
print("创建 README.md...")
|
||||
content = f'''# {self.project_name}
|
||||
|
||||
使用 Extra2D 游戏引擎开发的游戏项目。
|
||||
|
||||
## 支持平台
|
||||
|
||||
- MinGW (Windows)
|
||||
- Nintendo Switch
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
{self.project_name}/
|
||||
├── src/ # 源代码目录
|
||||
│ └── main.cpp # 主程序入口
|
||||
├── romfs/ # 资源文件目录
|
||||
│ └── assets/
|
||||
│ ├── images/ # 图片资源
|
||||
│ └── audio/ # 音频资源
|
||||
├── Extra2D/ # 引擎源码
|
||||
├── xmake.lua # 构建配置
|
||||
└── README.md # 项目说明
|
||||
```
|
||||
|
||||
## 构建说明
|
||||
|
||||
### 前置要求
|
||||
|
||||
- [xmake](https://xmake.io/) 构建工具
|
||||
- MinGW-w64 工具链 (Windows) 或 devkitPro (Switch)
|
||||
|
||||
### 构建步骤
|
||||
|
||||
#### Windows 平台
|
||||
|
||||
```bash
|
||||
# 配置项目
|
||||
xmake config -p mingw
|
||||
|
||||
# 构建项目
|
||||
xmake build
|
||||
|
||||
# 运行项目
|
||||
xmake run {self.project_name}
|
||||
```
|
||||
|
||||
#### Nintendo Switch 平台
|
||||
|
||||
```bash
|
||||
# 配置项目
|
||||
xmake config -p switch
|
||||
|
||||
# 构建项目
|
||||
xmake build
|
||||
|
||||
# 生成的 NRO 文件位于 build/switch/ 目录
|
||||
```
|
||||
|
||||
## 资源文件
|
||||
|
||||
请将游戏所需的资源文件放入 `romfs/assets/` 目录:
|
||||
|
||||
- `images/` - 图片资源(PNG, JPG 等)
|
||||
- `audio/` - 音频资源(WAV, OGG 等)
|
||||
- `font.ttf` - 字体文件(需要手动添加)
|
||||
|
||||
## 作者
|
||||
|
||||
{self.author}
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT License
|
||||
'''
|
||||
with open(self.project_path / "README.md", "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
|
||||
def _print_next_steps(self):
|
||||
"""打印后续步骤"""
|
||||
print(f"\n后续步骤:")
|
||||
print(f" 1. cd {self.project_path}")
|
||||
print(f" 2. xmake config -p mingw")
|
||||
print(f" 3. xmake build")
|
||||
print(f" 4. xmake run {self.project_name}")
|
||||
|
||||
|
||||
def prompt_download_tools(dev_tools: dict):
|
||||
"""
|
||||
提示用户下载缺失的开发工具链
|
||||
|
||||
@param dev_tools: 缺失的开发工具链
|
||||
"""
|
||||
if not dev_tools:
|
||||
return
|
||||
|
||||
print("\n========================================")
|
||||
print("检测到以下开发工具链未安装:")
|
||||
print("========================================")
|
||||
|
||||
if "mingw" in dev_tools:
|
||||
print(" - MinGW-w64 (Windows 开发)")
|
||||
if "devkitpro" in dev_tools:
|
||||
print(" - devkitPro (Switch 开发)")
|
||||
|
||||
print("\n是否需要下载这些工具?")
|
||||
print(" 1. 下载 MinGW-w64 (Windows 开发)")
|
||||
print(" 2. 下载 devkitPro (Switch 开发)")
|
||||
print(" 3. 下载全部")
|
||||
print(" 4. 跳过下载")
|
||||
|
||||
try:
|
||||
choice = input("\n请选择 (1-4): ").strip()
|
||||
|
||||
import webbrowser
|
||||
|
||||
if choice == "1" and "mingw" in dev_tools:
|
||||
print(f"\n正在打开 MinGW 下载页面...")
|
||||
print(f"下载地址: {MINGW_URL}")
|
||||
webbrowser.open(MINGW_URL)
|
||||
elif choice == "2" and "devkitpro" in dev_tools:
|
||||
print(f"\n正在打开 devkitPro 下载页面...")
|
||||
print(f"下载地址: {DEVKITPRO_URL}")
|
||||
webbrowser.open(DEVKITPRO_URL)
|
||||
elif choice == "3":
|
||||
if "mingw" in dev_tools:
|
||||
print(f"\n正在打开 MinGW 下载页面...")
|
||||
print(f"下载地址: {MINGW_URL}")
|
||||
webbrowser.open(MINGW_URL)
|
||||
if "devkitpro" in dev_tools:
|
||||
print(f"\n正在打开 devkitPro 下载页面...")
|
||||
print(f"下载地址: {DEVKITPRO_URL}")
|
||||
webbrowser.open(DEVKITPRO_URL)
|
||||
else:
|
||||
print("\n已跳过下载。")
|
||||
|
||||
if dev_tools:
|
||||
print("\n安装提示:")
|
||||
if "mingw" in dev_tools:
|
||||
print(" MinGW: 解压后将 bin 目录添加到系统 PATH 环境变量")
|
||||
if "devkitpro" in dev_tools:
|
||||
print(" devkitPro: 运行安装程序,按提示完成安装")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n已取消。")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Extra2D 项目脚手架工具",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
示例:
|
||||
python create_project.py my_game
|
||||
python create_project.py my_game --path ./games
|
||||
python create_project.py my_game --author "Your Name"
|
||||
|
||||
项目结构:
|
||||
my_game/
|
||||
├── src/
|
||||
│ └── main.cpp
|
||||
├── romfs/
|
||||
│ └── assets/
|
||||
├── xmake.lua
|
||||
├── README.md
|
||||
└── Extra2D/ # 引擎源码(自动克隆)
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"name",
|
||||
help="项目名称(只能包含字母、数字和下划线)"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--path", "-p",
|
||||
help="项目创建路径(默认为当前目录)"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--author", "-a",
|
||||
default="Extra2D Team",
|
||||
help="项目作者(默认: Extra2D Team)"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
checker = DevToolsChecker()
|
||||
checker.print_tool_status()
|
||||
|
||||
missing_tools = checker.get_missing_tools()
|
||||
if missing_tools:
|
||||
print("错误: 缺少必要的工具:")
|
||||
for tool, desc in missing_tools.items():
|
||||
print(f" - {desc}")
|
||||
print("\n请先安装这些工具后再创建项目。")
|
||||
sys.exit(1)
|
||||
|
||||
dev_tools = checker.get_missing_dev_tools()
|
||||
if dev_tools:
|
||||
prompt_download_tools(dev_tools)
|
||||
|
||||
if not args.name.replace("_", "").isalnum():
|
||||
print("错误: 项目名称只能包含字母、数字和下划线")
|
||||
sys.exit(1)
|
||||
|
||||
creator = ProjectCreator(
|
||||
project_name=args.name,
|
||||
output_path=args.path,
|
||||
author=args.author
|
||||
)
|
||||
|
||||
if not creator.create():
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -1,147 +0,0 @@
|
|||
/**
|
||||
* @file move_dirs_to_include.js
|
||||
* @brief 将 extra2d 子目录移动到 include 根目录
|
||||
* @description 此脚本将 Extra2D/include/extra2d/ 下的所有子目录(如 action、animation 等)
|
||||
* 移动到 Extra2D/include/ 根目录下
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// 配置路径
|
||||
const SOURCE_DIR = path.join(__dirname, '..', 'Extra2D', 'include', 'extra2d');
|
||||
const TARGET_DIR = path.join(__dirname, '..', 'Extra2D', 'include');
|
||||
|
||||
/**
|
||||
* @brief 获取目录下的所有子目录
|
||||
* @param {string} dir - 要扫描的目录
|
||||
* @returns {string[]} 子目录路径数组
|
||||
*/
|
||||
function getSubdirectories(dir) {
|
||||
const items = fs.readdirSync(dir);
|
||||
const dirs = [];
|
||||
|
||||
for (const item of items) {
|
||||
const fullPath = path.join(dir, item);
|
||||
const stat = fs.statSync(fullPath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
dirs.push(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
return dirs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移动目录到目标位置
|
||||
* @param {string} sourcePath - 源目录路径
|
||||
* @param {string} targetPath - 目标目录路径
|
||||
* @returns {boolean} 是否成功
|
||||
*/
|
||||
function moveDirectory(sourcePath, targetPath) {
|
||||
const dirName = path.basename(sourcePath);
|
||||
|
||||
// 检查目标目录是否已存在
|
||||
if (fs.existsSync(targetPath)) {
|
||||
console.warn(`⚠️ 目标目录已存在,跳过: ${dirName}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
fs.renameSync(sourcePath, targetPath);
|
||||
console.log(`✅ 已移动: extra2d/${dirName} -> ${dirName}/`);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error(`❌ 移动失败: ${sourcePath}`, err.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 主函数
|
||||
*/
|
||||
function main() {
|
||||
console.log('========================================');
|
||||
console.log('🚀 开始移动 extra2d 子目录到 include 根目录');
|
||||
console.log('========================================');
|
||||
console.log(`📁 源目录: ${SOURCE_DIR}`);
|
||||
console.log(`📁 目标目录: ${TARGET_DIR}`);
|
||||
console.log('');
|
||||
|
||||
// 检查源目录是否存在
|
||||
if (!fs.existsSync(SOURCE_DIR)) {
|
||||
console.error(`❌ 源目录不存在: ${SOURCE_DIR}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 获取所有子目录
|
||||
const subdirs = getSubdirectories(SOURCE_DIR);
|
||||
console.log(`📊 发现 ${subdirs.length} 个子目录`);
|
||||
console.log('');
|
||||
|
||||
if (subdirs.length === 0) {
|
||||
console.log('⚠️ 没有找到子目录');
|
||||
return;
|
||||
}
|
||||
|
||||
// 移动目录
|
||||
let successCount = 0;
|
||||
let skipCount = 0;
|
||||
|
||||
for (const dirPath of subdirs) {
|
||||
const dirName = path.basename(dirPath);
|
||||
const targetPath = path.join(TARGET_DIR, dirName);
|
||||
|
||||
if (moveDirectory(dirPath, targetPath)) {
|
||||
successCount++;
|
||||
} else {
|
||||
skipCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// 移动 extra2d.h 文件(如果存在)
|
||||
const extra2dHeader = path.join(SOURCE_DIR, 'extra2d.h');
|
||||
if (fs.existsSync(extra2dHeader)) {
|
||||
const targetHeader = path.join(TARGET_DIR, 'extra2d.h');
|
||||
if (!fs.existsSync(targetHeader)) {
|
||||
try {
|
||||
fs.renameSync(extra2dHeader, targetHeader);
|
||||
console.log(`✅ 已移动: extra2d/extra2d.h -> extra2d.h`);
|
||||
successCount++;
|
||||
} catch (err) {
|
||||
console.error(`❌ 移动失败: extra2d.h`, err.message);
|
||||
skipCount++;
|
||||
}
|
||||
} else {
|
||||
console.warn(`⚠️ extra2d.h 已存在,跳过`);
|
||||
skipCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试删除空的 extra2d 目录
|
||||
try {
|
||||
const remainingItems = fs.readdirSync(SOURCE_DIR);
|
||||
if (remainingItems.length === 0) {
|
||||
fs.rmdirSync(SOURCE_DIR);
|
||||
console.log('');
|
||||
console.log('🗑️ 已删除空目录: extra2d/');
|
||||
} else {
|
||||
console.log('');
|
||||
console.log(`⚠️ extra2d 目录中仍有 ${remainingItems.length} 个项目,保留目录`);
|
||||
remainingItems.forEach(item => console.log(` - ${item}`));
|
||||
}
|
||||
} catch (err) {
|
||||
// 忽略错误
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('========================================');
|
||||
console.log('✨ 处理完成!');
|
||||
console.log(` 成功移动: ${successCount} 个项目`);
|
||||
console.log(` 跳过: ${skipCount} 个项目`);
|
||||
console.log('========================================');
|
||||
}
|
||||
|
||||
// 执行主函数
|
||||
main();
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
/**
|
||||
* @file update_includes.js
|
||||
* @brief 更新头文件包含路径
|
||||
* @description 将 #include <extra2d/xxx/xxx.h> 替换为 #include <xxx/xxx.h>
|
||||
* 扫描所有 .h, .hpp, .cpp 文件进行替换
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// 配置
|
||||
const TARGET_DIRS = [
|
||||
path.join(__dirname, '..', 'Extra2D', 'include'),
|
||||
path.join(__dirname, '..', 'Extra2D', 'src'),
|
||||
path.join(__dirname, '..', 'examples')
|
||||
];
|
||||
|
||||
const FILE_EXTENSIONS = ['.h', '.hpp', '.cpp'];
|
||||
|
||||
// 替换规则:将 <extra2d/ 替换为 <
|
||||
const OLD_PREFIX = /<extra2d\//g;
|
||||
const NEW_PREFIX = '<';
|
||||
|
||||
/**
|
||||
* @brief 递归获取所有目标文件
|
||||
* @param {string} dir - 要扫描的目录
|
||||
* @param {string[]} files - 文件列表(用于递归)
|
||||
* @returns {string[]} 文件路径数组
|
||||
*/
|
||||
function getTargetFiles(dir, files = []) {
|
||||
if (!fs.existsSync(dir)) {
|
||||
return files;
|
||||
}
|
||||
|
||||
const items = fs.readdirSync(dir);
|
||||
|
||||
for (const item of items) {
|
||||
const fullPath = path.join(dir, item);
|
||||
const stat = fs.statSync(fullPath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
// 递归扫描子目录
|
||||
getTargetFiles(fullPath, files);
|
||||
} else if (stat.isFile()) {
|
||||
// 检查是否为目标文件类型
|
||||
const ext = path.extname(item).toLowerCase();
|
||||
if (FILE_EXTENSIONS.includes(ext)) {
|
||||
files.push(fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理单个文件,替换包含路径
|
||||
* @param {string} filePath - 文件路径
|
||||
* @returns {object} 处理结果 { modified: boolean, changes: number }
|
||||
*/
|
||||
function processFile(filePath) {
|
||||
let content = fs.readFileSync(filePath, 'utf-8');
|
||||
const originalContent = content;
|
||||
|
||||
// 统计替换次数
|
||||
let matchCount = 0;
|
||||
const matches = content.match(OLD_PREFIX);
|
||||
if (matches) {
|
||||
matchCount = matches.length;
|
||||
}
|
||||
|
||||
// 执行替换
|
||||
content = content.replace(OLD_PREFIX, NEW_PREFIX);
|
||||
|
||||
// 检查是否有修改
|
||||
if (content !== originalContent) {
|
||||
fs.writeFileSync(filePath, content, 'utf-8');
|
||||
return { modified: true, changes: matchCount };
|
||||
}
|
||||
|
||||
return { modified: false, changes: 0 };
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 主函数
|
||||
*/
|
||||
function main() {
|
||||
console.log('========================================');
|
||||
console.log('🚀 开始更新头文件包含路径');
|
||||
console.log('========================================');
|
||||
console.log('替换规则: #include <extra2d/xxx.h> -> #include <xxx.h>');
|
||||
console.log('');
|
||||
|
||||
// 收集所有目标文件
|
||||
let allFiles = [];
|
||||
for (const dir of TARGET_DIRS) {
|
||||
const files = getTargetFiles(dir);
|
||||
allFiles = allFiles.concat(files);
|
||||
}
|
||||
|
||||
console.log(`📊 发现 ${allFiles.length} 个目标文件`);
|
||||
console.log('');
|
||||
|
||||
if (allFiles.length === 0) {
|
||||
console.log('⚠️ 没有找到目标文件');
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理文件
|
||||
let modifiedCount = 0;
|
||||
let totalChanges = 0;
|
||||
const modifiedFiles = [];
|
||||
|
||||
for (const filePath of allFiles) {
|
||||
const result = processFile(filePath);
|
||||
if (result.modified) {
|
||||
modifiedCount++;
|
||||
totalChanges += result.changes;
|
||||
const relativePath = path.relative(path.join(__dirname, '..'), filePath);
|
||||
modifiedFiles.push({ path: relativePath, changes: result.changes });
|
||||
console.log(`✅ 已更新: ${relativePath} (${result.changes} 处替换)`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('========================================');
|
||||
console.log('✨ 处理完成!');
|
||||
console.log(` 扫描文件: ${allFiles.length} 个`);
|
||||
console.log(` 修改文件: ${modifiedCount} 个`);
|
||||
console.log(` 总替换数: ${totalChanges} 处`);
|
||||
console.log('========================================');
|
||||
|
||||
// 显示修改的文件列表
|
||||
if (modifiedFiles.length > 0) {
|
||||
console.log('');
|
||||
console.log('📋 修改的文件列表:');
|
||||
modifiedFiles.forEach((file, index) => {
|
||||
console.log(` ${index + 1}. ${file.path} (${file.changes} 处)`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 执行主函数
|
||||
main();
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue