axmolengine / axmol

Axmol Engine – A Multi-platform Engine for Desktop, XBOX (UWP) and Mobile games. (A fork of Cocos2d-x-4.0)
https://axmol.dev
MIT License
868 stars 195 forks source link

Add support for ActionCoroutine like Unity #1471

Closed lich426 closed 9 months ago

lich426 commented 10 months ago

I referred to the source code here

C++ compiler with Coroutines TS support

Is it possible to test on another platform?

ActionCoroutine.h ```c++ #ifndef __ACTION_CCCOROUTINE_ACTION_H__ #define __ACTION_CCCOROUTINE_ACTION_H__ #include "2d/Action.h" #include #include #include NS_AX_BEGIN class Coroutine { public: class promise_type; using handle = std::experimental::coroutine_handle; class promise_type { public: virtual ~promise_type() { AX_SAFE_RELEASE(_currentAction); } Action* currentAction() const noexcept { return _currentAction; } auto final_suspend() const noexcept { return std::experimental::suspend_always{}; } auto get_return_object() noexcept { return Coroutine(handle::from_promise(*this)); } auto initial_suspend() const noexcept { return std::experimental::suspend_always{}; } auto yield_value(Action* action) { AX_SAFE_RELEASE(_currentAction); _currentAction = action; AX_SAFE_RETAIN(_currentAction); return std::experimental::suspend_always{}; } void return_void() {} void unhandled_exception() {} void resume() { handle::from_promise(*this).resume(); } private: Action* _currentAction{ nullptr }; }; Coroutine() = default; Coroutine(const Coroutine&) = delete; Coroutine(Coroutine&& rhs) noexcept; virtual ~Coroutine(); Coroutine& operator=(const Coroutine&) = delete; Coroutine& operator=(Coroutine&& rhs) noexcept; Action* currentAction() const noexcept; bool isDone() const; bool moveNext() const; private: Coroutine(handle h) noexcept : _handle{ h } {} handle _handle; }; class AX_DLL ActionCoroutine : public Action { public: static ActionCoroutine* create(Coroutine&& coroutine); virtual bool isDone() const override; virtual void step(float dt) override; public: ActionCoroutine() = default; virtual ~ActionCoroutine() {} bool initWithCoroutine(Coroutine&& coroutine) noexcept; private: AX_DISALLOW_COPY_AND_ASSIGN(ActionCoroutine); Coroutine _coroutine; }; NS_AX_END #endif //__ACTION_CCCOROUTINE_ACTION_H__ ```
ActionCoroutine.cpp ```c++ #include "ActionCoroutine.h" NS_AX_BEGIN Coroutine::Coroutine(Coroutine&& rhs) noexcept : _handle(rhs._handle) { rhs._handle = nullptr; } Coroutine::~Coroutine() { if (_handle) { _handle.destroy(); } } Coroutine& Coroutine::operator=(Coroutine&& rhs) noexcept { if (this != std::addressof(rhs)) { _handle = rhs._handle; rhs._handle = nullptr; } return *this; } Action* Coroutine::currentAction() const noexcept { return _handle.promise().currentAction(); } bool Coroutine::isDone() const { return _handle && _handle.done(); } bool Coroutine::moveNext() const { if (_handle) { _handle.promise().resume(); return !_handle.done(); } return false; } ActionCoroutine* ActionCoroutine::create(Coroutine&& coroutine) { auto ret = new (std::nothrow) ActionCoroutine(); if (ret && ret->initWithCoroutine(std::forward(coroutine))) { ret->autorelease(); return ret; } delete ret; return nullptr; } bool ActionCoroutine::isDone() const { auto action = _coroutine.currentAction(); if (action && !action->isDone()) return false; return _coroutine.isDone(); } void ActionCoroutine::step(float dt) { auto action = _coroutine.currentAction(); if (action && !action->isDone()) { action->step(dt); return; } _coroutine.moveNext(); } bool ActionCoroutine::initWithCoroutine(Coroutine&& coroutine) noexcept { _coroutine = std::forward(coroutine); return true; } NS_AX_END ```
Coroutine HelloWorld::testCoroutine()
{
    AXLOG("HelloWorld::testCoroutine() : frame count(%llu)", mFrameCount);
    co_yield DelayTime::create(3.0f);
    AXLOG("HelloWorld::testCoroutine() : frame count(%llu), after 3sec", mFrameCount);
    co_yield nullptr;
    AXLOG("HelloWorld::testCoroutine() : frame count(%llu), next frame", mFrameCount);
}

void HelloWorld::onTouchesBegan(const std::vector<ax::Touch*>& touches, ax::Event* event)
{
    auto action = ActionCoroutine::create(testCoroutine());
    this->runAction(action);

    for (auto&& t : touches)
    {
        //AXLOG("onTouchesBegan detected, X:%f  Y:%f", t->getLocation().x, t->getLocation().y);
    }
}

void HelloWorld::update(float delta)
{
    mFrameCount++;
}

image

halx99 commented 10 months ago

could you create pr directly?

aismann commented 10 months ago

could you create pr directly?

Maybe as a new third party entry?

lich426 commented 10 months ago

could you create pr directly?

I haven't tested it on iOS and Linux yet, so I'm not sure if it's compatible with them. Could you please test this code?

halx99 commented 10 months ago

I think you can create PR to check compiling by github ci firstly.

halx99 commented 10 months ago

non-android platforms

halx99 commented 10 months ago

could you create pr directly?

I haven't tested it on iOS and Linux yet, so I'm not sure if it's compatible with them. Could you please test this code?

tested osx,ios,wasm worked without any additional compiler flags

Edit: since axmol c++ standard is 20, visual studio 2022 c++20 also don't require any additional compiler flags