Skip to content

Swoosh2 Rewrite ActionLists #26

@TheMaverickProgrammer

Description

@TheMaverickProgrammer

In original Swoosh, the Actions for an ActionList required the user to allocate on the heap while the ActionList deleted memory for the user. This is not intuitive. Generally the expectations are that, if a user allocates memory, then they must also delete their own memory too. Therefore a clearer API would use smart pointers and constructs to do this behind-the-scenes as Swoosh's mission statement is to let the user be free of any memory management and one of the reasons why segue effects are wrapped in meta template syntax.

Similarly, ActionList type and constructor arguments can be bound, but not allocated on the heap until needed. This is not a complete example, but for illustrative purposes describes what I mean:

auto checkHealth = [this]() {
    return creatureHealth > 0;
};

sw::ActionListBuilder builder = { 
   sw::Concurrent<AttackAction>(3.0, &decalSpr),
   sw::Blocking<WaitForInput>(Input::Key_Enter),
   // args: query func, list if true, list if false
   // both lists are intentionally std::nullopt for this example
   sw::Conditional(checkCreatureHealth, std::nullopt, std::nullopt),
   ...
... };

while(actionList.empty() == false) {
    sw::ActionRef currAction = actionList.top();
    currAction.tick();
    
    //Later, a conditional execution path changes the next actions
   if(currAction.is<sw::Conditional>()) {
    sw::ConditionalRef condition = currAction.as<sw::Conditional>();
    if(condition.isTrue()) {
       actionList.clear();
       // Do something else
    } else {
        // The builder list at the top of this example defers construction
        // until this moment - using the data to configure the necessary
        // internals that would otherwise be tedious "plumbing".
        actionList.insert(actionList.begin(), builder.buildList());
    }
}

The idea is that all memory management is safe and hidden away from the user. They should receive primitive-like handles which wrap the complex logic. Only when a direct call to buildList() should any of the "registered" action metadata allocate memory for those Actions.

It's debatable whether or not the ActionList itself needs to be a UDT type at all as it can be represented by std::stack or some other satisfactory data structure. Mutation of the list could occur in the underlining class of the sw::ActionRef itself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions