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();
|
initButtons();
|
||||||
|
|
||||||
// 创建向上移动的动画(从屏幕底部移动到正常位置)
|
// 动画完成,启用按钮
|
||||||
auto moveAction = extra2d::MoveBy::create(1.0f, extra2d::Vec2(0.0f, -screenHeight));
|
animationDone_ = true;
|
||||||
moveAction->setCompletionCallback([this]() {
|
if (restartBtn_)
|
||||||
animationDone_ = true;
|
restartBtn_->setEnabled(true);
|
||||||
if (restartBtn_)
|
if (menuBtn_)
|
||||||
restartBtn_->setEnabled(true);
|
menuBtn_->setEnabled(true);
|
||||||
if (menuBtn_)
|
if (shareBtn_)
|
||||||
menuBtn_->setEnabled(true);
|
shareBtn_->setEnabled(true);
|
||||||
if (shareBtn_)
|
|
||||||
shareBtn_->setEnabled(true);
|
|
||||||
});
|
|
||||||
runAction(moveAction);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameOverLayer::initPanel(int score, float screenHeight) {
|
void GameOverLayer::initPanel(int score, float screenHeight) {
|
||||||
|
|
|
||||||
|
|
@ -64,18 +64,6 @@
|
||||||
#include <ui/radio_button.h>
|
#include <ui/radio_button.h>
|
||||||
#include <ui/slider.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
|
// Event
|
||||||
#include <event/event.h>
|
#include <event/event.h>
|
||||||
#include <event/event_queue.h>
|
#include <event/event_queue.h>
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <audio/sound.h>
|
#include <audio/sound.h>
|
||||||
#include <core/types.h>
|
#include <core/types.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <future>
|
||||||
#include <graphics/alpha_mask.h>
|
#include <graphics/alpha_mask.h>
|
||||||
#include <graphics/font.h>
|
#include <graphics/font.h>
|
||||||
#include <graphics/texture.h>
|
#include <graphics/texture.h>
|
||||||
#include <functional>
|
|
||||||
#include <future>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <atomic>
|
#include <unordered_map>
|
||||||
#include <list>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
@ -25,14 +25,14 @@ namespace extra2d {
|
||||||
|
|
||||||
// 纹理格式枚举
|
// 纹理格式枚举
|
||||||
enum class TextureFormat {
|
enum class TextureFormat {
|
||||||
Auto = 0, // 自动选择最佳格式
|
Auto = 0, // 自动选择最佳格式
|
||||||
RGBA8, // 32位 RGBA
|
RGBA8, // 32位 RGBA
|
||||||
RGB8, // 24位 RGB
|
RGB8, // 24位 RGB
|
||||||
DXT1, // BC1/DXT1 压缩(1 bit alpha)
|
DXT1, // BC1/DXT1 压缩(1 bit alpha)
|
||||||
DXT5, // BC3/DXT5 压缩(完整 alpha)
|
DXT5, // BC3/DXT5 压缩(完整 alpha)
|
||||||
ETC2, // ETC2 压缩(移动平台)
|
ETC2, // ETC2 压缩(移动平台)
|
||||||
ASTC4x4, // ASTC 4x4 压缩(高质量)
|
ASTC4x4, // ASTC 4x4 压缩(高质量)
|
||||||
ASTC8x8, // ASTC 8x8 压缩(高压缩率)
|
ASTC8x8, // ASTC 8x8 压缩(高压缩率)
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
@ -40,9 +40,9 @@ enum class TextureFormat {
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
struct TextureCacheEntry {
|
struct TextureCacheEntry {
|
||||||
Ptr<Texture> texture;
|
Ptr<Texture> texture;
|
||||||
size_t size = 0; // 纹理大小(字节)
|
size_t size = 0; // 纹理大小(字节)
|
||||||
float lastAccessTime = 0.0f; // 最后访问时间
|
float lastAccessTime = 0.0f; // 最后访问时间
|
||||||
uint32_t accessCount = 0; // 访问次数
|
uint32_t accessCount = 0; // 访问次数
|
||||||
};
|
};
|
||||||
|
|
||||||
// 异步加载回调类型
|
// 异步加载回调类型
|
||||||
|
|
@ -61,18 +61,21 @@ public:
|
||||||
|
|
||||||
/// 加载纹理(带缓存)
|
/// 加载纹理(带缓存)
|
||||||
Ptr<Texture> loadTexture(const std::string &filepath);
|
Ptr<Texture> loadTexture(const std::string &filepath);
|
||||||
|
|
||||||
/// 加载纹理(指定是否异步)
|
/// 加载纹理(指定是否异步)
|
||||||
Ptr<Texture> loadTexture(const std::string &filepath, bool async);
|
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遮罩(用于不规则形状图片)
|
/// 加载纹理并生成Alpha遮罩(用于不规则形状图片)
|
||||||
Ptr<Texture> loadTextureWithAlphaMask(const std::string &filepath);
|
Ptr<Texture> loadTextureWithAlphaMask(const std::string &filepath);
|
||||||
|
|
@ -146,7 +149,8 @@ public:
|
||||||
/// @param filepath 文件路径
|
/// @param filepath 文件路径
|
||||||
/// @param encoding 文件编码(默认 UTF-8)
|
/// @param encoding 文件编码(默认 UTF-8)
|
||||||
/// @return 文件内容字符串
|
/// @return 文件内容字符串
|
||||||
std::string loadTextFile(const std::string &filepath, const std::string &encoding);
|
std::string loadTextFile(const std::string &filepath,
|
||||||
|
const std::string &encoding);
|
||||||
|
|
||||||
/// 通过key获取已缓存的文本内容
|
/// 通过key获取已缓存的文本内容
|
||||||
std::string getTextFile(const std::string &key) const;
|
std::string getTextFile(const std::string &key) const;
|
||||||
|
|
@ -249,16 +253,18 @@ private:
|
||||||
// 生成字体缓存key
|
// 生成字体缓存key
|
||||||
std::string makeFontKey(const std::string &filepath, int fontSize,
|
std::string makeFontKey(const std::string &filepath, int fontSize,
|
||||||
bool useSDF) const;
|
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;
|
TextureFormat selectBestFormat(TextureFormat requested) const;
|
||||||
|
|
||||||
// 压缩纹理数据
|
// 压缩纹理数据
|
||||||
std::vector<uint8_t> compressTexture(const uint8_t* data, int width, int height,
|
std::vector<uint8_t> compressTexture(const uint8_t *data, int width,
|
||||||
int channels, TextureFormat format);
|
int height, int channels,
|
||||||
|
TextureFormat format);
|
||||||
|
|
||||||
// 互斥锁保护缓存
|
// 互斥锁保护缓存
|
||||||
mutable std::mutex textureMutex_;
|
mutable std::mutex textureMutex_;
|
||||||
|
|
@ -282,31 +288,31 @@ private:
|
||||||
// LRU链表节点
|
// LRU链表节点
|
||||||
struct LRUNode {
|
struct LRUNode {
|
||||||
std::string key;
|
std::string key;
|
||||||
uint32_t prev = 0; // 数组索引,0表示无效
|
uint32_t prev = 0; // 数组索引,0表示无效
|
||||||
uint32_t next = 0; // 数组索引,0表示无效
|
uint32_t next = 0; // 数组索引,0表示无效
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 纹理缓存配置
|
// 纹理缓存配置
|
||||||
size_t maxCacheSize_ = 64 * 1024 * 1024; // 最大缓存大小 (64MB)
|
size_t maxCacheSize_ = 64 * 1024 * 1024; // 最大缓存大小 (64MB)
|
||||||
size_t maxTextureCount_ = 256; // 最大纹理数量
|
size_t maxTextureCount_ = 256; // 最大纹理数量
|
||||||
float unloadInterval_ = 30.0f; // 自动清理间隔 (秒)
|
float unloadInterval_ = 30.0f; // 自动清理间隔 (秒)
|
||||||
|
|
||||||
// 纹理缓存 - 使用强指针保持引用
|
// 纹理缓存 - 使用强指针保持引用
|
||||||
std::unordered_map<std::string, TextureCacheEntry> textureCache_;
|
std::unordered_map<std::string, TextureCacheEntry> textureCache_;
|
||||||
|
|
||||||
// 侵入式LRU链表 - 使用数组索引代替指针,提高缓存局部性
|
// 侵入式LRU链表 - 使用数组索引代替指针,提高缓存局部性
|
||||||
std::vector<LRUNode> lruNodes_;
|
std::vector<LRUNode> lruNodes_;
|
||||||
uint32_t lruHead_ = 0; // 最近使用
|
uint32_t lruHead_ = 0; // 最近使用
|
||||||
uint32_t lruTail_ = 0; // 最久未使用
|
uint32_t lruTail_ = 0; // 最久未使用
|
||||||
uint32_t freeList_ = 0; // 空闲节点链表
|
uint32_t freeList_ = 0; // 空闲节点链表
|
||||||
|
|
||||||
// 统计
|
// 统计
|
||||||
size_t totalTextureSize_ = 0;
|
size_t totalTextureSize_ = 0;
|
||||||
uint64_t textureHitCount_ = 0;
|
uint64_t textureHitCount_ = 0;
|
||||||
uint64_t textureMissCount_ = 0;
|
uint64_t textureMissCount_ = 0;
|
||||||
float autoUnloadTimer_ = 0.0f;
|
float autoUnloadTimer_ = 0.0f;
|
||||||
|
|
||||||
// 异步加载相关
|
// 异步加载相关
|
||||||
struct AsyncLoadTask {
|
struct AsyncLoadTask {
|
||||||
std::string filepath;
|
std::string filepath;
|
||||||
|
|
@ -314,14 +320,14 @@ private:
|
||||||
TextureLoadCallback callback;
|
TextureLoadCallback callback;
|
||||||
std::promise<Ptr<Texture>> promise;
|
std::promise<Ptr<Texture>> promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::queue<AsyncLoadTask> asyncTaskQueue_;
|
std::queue<AsyncLoadTask> asyncTaskQueue_;
|
||||||
std::mutex asyncQueueMutex_;
|
std::mutex asyncQueueMutex_;
|
||||||
std::condition_variable asyncCondition_;
|
std::condition_variable asyncCondition_;
|
||||||
std::unique_ptr<std::thread> asyncThread_;
|
std::unique_ptr<std::thread> asyncThread_;
|
||||||
std::atomic<bool> asyncRunning_{false};
|
std::atomic<bool> asyncRunning_{false};
|
||||||
std::atomic<int> pendingAsyncLoads_{0};
|
std::atomic<int> pendingAsyncLoads_{0};
|
||||||
|
|
||||||
void asyncLoadLoop();
|
void asyncLoadLoop();
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
@ -14,7 +14,6 @@ namespace extra2d {
|
||||||
|
|
||||||
// 前向声明
|
// 前向声明
|
||||||
class Scene;
|
class Scene;
|
||||||
class Action;
|
|
||||||
class RenderBackend;
|
class RenderBackend;
|
||||||
struct RenderCommand;
|
struct RenderCommand;
|
||||||
|
|
||||||
|
|
@ -155,58 +154,6 @@ public:
|
||||||
// 更新空间索引(手动调用,通常在边界框变化后)
|
// 更新空间索引(手动调用,通常在边界框变化后)
|
||||||
void updateSpatialIndex();
|
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