refactor: 重构项目结构,优化代码组织与文件布局

将源代码从Extra2D/src迁移到src目录,统一文件路径
更新xmake构建配置以适配新路径
清理冗余代码文件,合并重复实现
调整头文件包含路径,确保编译通过
优化过渡动画场景实现,移除不必要的动画效果
This commit is contained in:
ChestnutYueyue 2026-02-25 06:46:13 +08:00
parent f9c8f080eb
commit 5039b1d9fc
169 changed files with 58 additions and 5606 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +0,0 @@
#include "action/finite_time_action.h"
namespace extra2d {
FiniteTimeAction::FiniteTimeAction(float duration)
: duration_(duration) {
}
} // namespace extra2d

View File

@ -43,18 +43,14 @@ void GameOverLayer::onEnter() {
// 初始化按钮
initButtons();
// 创建向上移动的动画(从屏幕底部移动到正常位置)
auto moveAction = extra2d::MoveBy::create(1.0f, extra2d::Vec2(0.0f, -screenHeight));
moveAction->setCompletionCallback([this]() {
animationDone_ = true;
if (restartBtn_)
restartBtn_->setEnabled(true);
if (menuBtn_)
menuBtn_->setEnabled(true);
if (shareBtn_)
shareBtn_->setEnabled(true);
});
runAction(moveAction);
// 动画完成,启用按钮
animationDone_ = true;
if (restartBtn_)
restartBtn_->setEnabled(true);
if (menuBtn_)
menuBtn_->setEnabled(true);
if (shareBtn_)
shareBtn_->setEnabled(true);
}
void GameOverLayer::initPanel(int score, float screenHeight) {

View File

@ -64,18 +64,6 @@
#include <ui/radio_button.h>
#include <ui/slider.h>
// Action
#include <action/action.h>
#include <action/finite_time_action.h>
#include <action/action_interval.h>
#include <action/action_instant.h>
#include <action/action_interval_actions.h>
#include <action/action_instant_actions.h>
#include <action/action_ease.h>
#include <action/action_special.h>
#include <action/action_manager.h>
#include <action/ease.h>
// Event
#include <event/event.h>
#include <event/event_queue.h>

View File

@ -1,21 +1,21 @@
#pragma once
#include <atomic>
#include <audio/sound.h>
#include <core/types.h>
#include <functional>
#include <future>
#include <graphics/alpha_mask.h>
#include <graphics/font.h>
#include <graphics/texture.h>
#include <functional>
#include <future>
#include <mutex>
#include <string>
#include <unordered_map>
#include <queue>
#include <string>
#include <thread>
#include <atomic>
#include <list>
#include <unordered_map>
#include <vector>
namespace extra2d {
// ============================================================================
@ -25,14 +25,14 @@ namespace extra2d {
// 纹理格式枚举
enum class TextureFormat {
Auto = 0, // 自动选择最佳格式
RGBA8, // 32位 RGBA
RGB8, // 24位 RGB
DXT1, // BC1/DXT1 压缩1 bit alpha
DXT5, // BC3/DXT5 压缩(完整 alpha
ETC2, // ETC2 压缩(移动平台)
ASTC4x4, // ASTC 4x4 压缩(高质量)
ASTC8x8, // ASTC 8x8 压缩(高压缩率)
Auto = 0, // 自动选择最佳格式
RGBA8, // 32位 RGBA
RGB8, // 24位 RGB
DXT1, // BC1/DXT1 压缩1 bit alpha
DXT5, // BC3/DXT5 压缩(完整 alpha
ETC2, // ETC2 压缩(移动平台)
ASTC4x4, // ASTC 4x4 压缩(高质量)
ASTC8x8, // ASTC 8x8 压缩(高压缩率)
};
// ============================================================================
@ -40,9 +40,9 @@ enum class TextureFormat {
// ============================================================================
struct TextureCacheEntry {
Ptr<Texture> texture;
size_t size = 0; // 纹理大小(字节)
float lastAccessTime = 0.0f; // 最后访问时间
uint32_t accessCount = 0; // 访问次数
size_t size = 0; // 纹理大小(字节)
float lastAccessTime = 0.0f; // 最后访问时间
uint32_t accessCount = 0; // 访问次数
};
// 异步加载回调类型
@ -66,13 +66,16 @@ public:
Ptr<Texture> loadTexture(const std::string &filepath, bool async);
/// 加载纹理(完整参数:异步 + 压缩格式)
Ptr<Texture> loadTexture(const std::string &filepath, bool async, TextureFormat format);
Ptr<Texture> loadTexture(const std::string &filepath, bool async,
TextureFormat format);
/// 异步加载纹理(带回调)
void loadTextureAsync(const std::string &filepath, TextureLoadCallback callback);
void loadTextureAsync(const std::string &filepath,
TextureLoadCallback callback);
/// 异步加载纹理(指定格式 + 回调)
void loadTextureAsync(const std::string &filepath, TextureFormat format, TextureLoadCallback callback);
void loadTextureAsync(const std::string &filepath, TextureFormat format,
TextureLoadCallback callback);
/// 加载纹理并生成Alpha遮罩用于不规则形状图片
Ptr<Texture> loadTextureWithAlphaMask(const std::string &filepath);
@ -146,7 +149,8 @@ public:
/// @param filepath 文件路径
/// @param encoding 文件编码(默认 UTF-8
/// @return 文件内容字符串
std::string loadTextFile(const std::string &filepath, const std::string &encoding);
std::string loadTextFile(const std::string &filepath,
const std::string &encoding);
/// 通过key获取已缓存的文本内容
std::string getTextFile(const std::string &key) const;
@ -251,14 +255,16 @@ private:
bool useSDF) const;
// 内部加载实现
Ptr<Texture> loadTextureInternal(const std::string &filepath, TextureFormat format);
Ptr<Texture> loadTextureInternal(const std::string &filepath,
TextureFormat format);
// 选择最佳纹理格式
TextureFormat selectBestFormat(TextureFormat requested) const;
// 压缩纹理数据
std::vector<uint8_t> compressTexture(const uint8_t* data, int width, int height,
int channels, TextureFormat format);
std::vector<uint8_t> compressTexture(const uint8_t *data, int width,
int height, int channels,
TextureFormat format);
// 互斥锁保护缓存
mutable std::mutex textureMutex_;
@ -282,24 +288,24 @@ private:
// LRU链表节点
struct LRUNode {
std::string key;
uint32_t prev = 0; // 数组索引0表示无效
uint32_t next = 0; // 数组索引0表示无效
uint32_t prev = 0; // 数组索引0表示无效
uint32_t next = 0; // 数组索引0表示无效
bool valid = false;
};
// 纹理缓存配置
size_t maxCacheSize_ = 64 * 1024 * 1024; // 最大缓存大小 (64MB)
size_t maxTextureCount_ = 256; // 最大纹理数量
float unloadInterval_ = 30.0f; // 自动清理间隔 (秒)
size_t maxCacheSize_ = 64 * 1024 * 1024; // 最大缓存大小 (64MB)
size_t maxTextureCount_ = 256; // 最大纹理数量
float unloadInterval_ = 30.0f; // 自动清理间隔 (秒)
// 纹理缓存 - 使用强指针保持引用
std::unordered_map<std::string, TextureCacheEntry> textureCache_;
// 侵入式LRU链表 - 使用数组索引代替指针,提高缓存局部性
std::vector<LRUNode> lruNodes_;
uint32_t lruHead_ = 0; // 最近使用
uint32_t lruTail_ = 0; // 最久未使用
uint32_t freeList_ = 0; // 空闲节点链表
uint32_t lruHead_ = 0; // 最近使用
uint32_t lruTail_ = 0; // 最久未使用
uint32_t freeList_ = 0; // 空闲节点链表
// 统计
size_t totalTextureSize_ = 0;

View File

@ -14,7 +14,6 @@ namespace extra2d {
// 前向声明
class Scene;
class Action;
class RenderBackend;
struct RenderCommand;
@ -155,58 +154,6 @@ public:
// 更新空间索引(手动调用,通常在边界框变化后)
void updateSpatialIndex();
// ------------------------------------------------------------------------
// 动作系统
// ------------------------------------------------------------------------
/**
* @brief
* @param action
* @return
*/
Action* runAction(Action* action);
/**
* @brief
*/
void stopAllActions();
/**
* @brief
* @param action
*/
void stopAction(Action* action);
/**
* @brief
* @param tag
*/
void stopActionByTag(int tag);
/**
* @brief
* @param flags
*/
void stopActionsByFlags(unsigned int flags);
/**
* @brief
* @param tag
* @return nullptr
*/
Action* getActionByTag(int tag);
/**
* @brief
* @return
*/
size_t getActionCount() const;
/**
* @brief
* @return true
*/
bool isRunningActions() const;
// ------------------------------------------------------------------------
// 事件系统
// ------------------------------------------------------------------------

View File

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

View File

@ -1,147 +0,0 @@
/**
* @file move_dirs_to_include.js
* @brief extra2d 子目录移动到 include 根目录
* @description 此脚本将 Extra2D/include/extra2d/ 下的所有子目录 actionanimation
* 移动到 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();

View File

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