Question

Cocos2D defines the static method 'actions' for the Sequence class as such:

+(id) actions: (FiniteTimeAction *) action1, ... { /* omitted */ }

How could I build a list of actions to perform at run-time, perhaps read from a disk file or such?

I read that the variable length argument list can be translated into a (char *) and passed in that way ...

NSMutableArray *actions = [[NSMutableArray alloc] init];
[actions addObject: [DelayTime actionWithDuration:1]];
[actions addObject: [ScaleBy actionWithDuration:2 scale:4];

char *argList = (char *)malloc(sizeof(FiniteTimeAction *) * [actions count]);
[actions getObjects:(id *)argList];

[self runActions: actions];

Is this the 'best way' or the 'correct' way to do this? Are their better alternatives, faster alternatives?

Was it helpful?

Solution

The vaargs is just a helper to build nested Sequence objects. It returns a FiniteTimeAction* which is built by successive calls to [Sequence actionOne:one_ two:two_]. You could do this yourself in your code by looping through your set or array. It should go something like this:

FiniteTimeAction *seq = nil;
for (FiniteTimeAction *action in actions) {
    if (!seq) {
        seq = action;
    } else {
        seq = [Sequence actionOne:seq two:action];
    }
}
[self runActions:seq];

OTHER TIPS

I would look at using NSInvocation - you can basically build one using the method signature you are targeting, and then use the setters for each object like so:

NSInvocation *invoker = setup invoker here...
for ( int i = 0; i < actions.count; i++ ) 
{
    NSObject *arg = [actions objectatIndex:i];
    [invoker setArgument:&arg atIndex:i+2];
}
[invoker setArgument:nil atIndex:i+2];

The i+2 bit is because the first two arguments are really self and _cmd, so you set everything from index 2 and on... read the docs on setArgument:atIndex: in NSInvocation for more detail.

Once you have that you can invoke the operation with a target. I've never used this with variable argument methods so I'm unsure how well it works there, but it's the only means I know of to dynamically construct a call at runtime.

Given the options provided, it appears that the only real way to accomplish what I was after is to use the approach I mentioned in the question, which is was:

NSMutableArray *actions = [[NSMutableArray alloc] init];
[actions addObject: [DelayTime actionWithDuration:1]];
[actions addObject: [ScaleBy actionWithDuration:2 scale:4];

char *argList = (char *)malloc(sizeof(FiniteTimeAction *) * [actions count]);
[actions getObjects:(id *)argList];

[self runActions: actions];

Perhaps a set of pre-built sequences?

id move = [MoveBy actionWithDuration:3 position:ccp(350,0)];
id move_back = [move reverse];

id move_ease_in = [EaseIn actionWithAction:[[move copy] autorelease] rate:3.0f];
id move_ease_in_back = [move_ease_in reverse];

id move_ease_out = [EaseOut actionWithAction:[[move copy] autorelease] rate:3.0f];
id move_ease_out_back = [move_ease_out reverse];


id seq1 = [Sequence actions: move, move_back, nil];
id seq2 = [Sequence actions: move_ease_in, move_ease_in_back, nil];
id seq3 = [Sequence actions: move_ease_out, move_ease_out_back, nil];


[grossini runAction: [RepeatForever actionWithAction:seq1]];
[tamara runAction: [RepeatForever actionWithAction:seq2]];
[kathia runAction: [RepeatForever actionWithAction:seq3]];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top