[C preprocessor] generating "mirrored" functions

SGDK only sub forum

Moderator: Stef

Post Reply
tryphon
Very interested
Posts: 316
Joined: Sat Aug 17, 2013 9:38 pm
Location: France

[C preprocessor] generating "mirrored" functions

Post by tryphon » Tue Jun 21, 2016 8:14 am

While implementing my state machines for handling characters moves, I'm often forced to make two almost identical functions : one for the character facing to the right, the other for the character facing to the left. Here's a simple example :

Code: Select all

void musashi_walk_left(Object *self) {
	set_physics(LEFT_DX, 0, 0, 0);
	set_anim(MUSASHI_WALK_LEFT);
	self->update_function = (state_function*) musashi_walk_left_update;
}

void musashi_walk_right(Object *self) {
	set_physics(RIGHT_DX, 0, 0, 0);
	set_anim(MUSASHI_WALK_RIGHT);
	self->update_function = (state_function*) musashi_walk_right_update;
}
Of course, some functions can be much longer and convoluted, so I made a Python script that generates the C file with the mirrored functions. I was wondering if it was possible to do that using some tricky #defines or other hidden features of the preprocessor ?

MintyTheCat
Very interested
Posts: 484
Joined: Sat Mar 05, 2011 11:11 pm
Location: Berlin, Germany

Re: [C preprocessor] generating "mirrored" functions

Post by MintyTheCat » Tue Jun 21, 2016 9:34 am

Hi,

your best bet is to implement your state-machines using the table method. It does not look like you are aware of it - have a look into it but if you cannot find anything useful then I will dig out an example.

Also look up 'hierarchical state-tables' too as the method is the same. Using the SM table method allows you to quickly make any logic changes quickly too.

Edit: here's an example: https://gist.github.com/nmandery/1717405. One other benefit to using the table method is that your state table is the same in C and Assembly and it is much cheaper for the stack deref a function-pointer than to enter a function to then modify the 'effective state' through an extra function call.
UMDK Fanboy

tryphon
Very interested
Posts: 316
Joined: Sat Aug 17, 2013 9:38 pm
Location: France

Re: [C preprocessor] generating "mirrored" functions

Post by tryphon » Wed Jun 22, 2016 1:56 pm

First, thanks for this interesting answer :)

Second, you don't really answer my question, even if I think I understand why you did that.

Third, I read your code, and while it's undoubtedly cleaner (and would I be coding on anything else than a MD, I suppose I'd use it) I don't see why it would be more efficient.

What I do for now :
  • the call to a state_function is, from the asm side, I suppose it'll be a :

    Code: Select all

    	move.l	(state_fun), a0
    	jsr	(a0)
    
  • At each iteration, the current state function takes care of modifying the value at state_fun
In your method :
  • the call to the state_function should be something like :

    Code: Select all

    	move.w	(cur_state), d0
    	move.l	(state), a0
    	jsr	(a0, d0)
    

    Difference with former code is not signifiant (likely a little slower).
  • at each iteration, you'll have to find in the table the dst_state from the pair (src_state, ret_code).

    I bet it can be done in constant time if each src_state has exactly (number of ret_codes) entries (I'm assuming you forgot one line in state_transitions[] which would be {entry, repeat, entry}) but there would be a multiplication involved and it's slow (it could be optimized of course, but if you decide to add a new ret_code, you'll have to change the optimization, and then to change the whole state_transition).

    Another drawback is that there are in my program maybe 15 different events that could trigger a transition, but for a given state, only 3 of them actually triggers it. So I'd need to make a huge array where most lines would be {state, ret, state} (if you prefer, the transition matrix is sparse). If I decide that ignored transitions don't have to appear in the state_transitions array, then I can't determine the dst_state in constant time.

    So, I'm not really convinced it's faster. And I'm not sure the compromise between clarity and speed is favourable.
Concerning my initial question, I suppose I can do something like (not really sure about where to put the ##) :

Code: Select all

#define MUSASHI_WALK_(dir, DIR) \
void musashi_walk_##dir(Object *self) {\
   set_physics(DIR##_DX, 0, 0, 0);\
   set_anim(MUSASHI_WALK_##DIR);\
   self->update_function = (state_function*) musashi_walk_##dir##_update;\
}

MUSASHI_WALK(left, LEFT)
MUSASHI_WALK(right, RIGHT)
Could be a little more polished if there's a mean to make a token UPPERCASE.

Miquel
Very interested
Posts: 514
Joined: Sat Jul 30, 2016 12:33 am

Re: [C preprocessor] generating "mirrored" functions

Post by Miquel » Mon Aug 22, 2016 9:02 pm

You're going to turn crazy that way.

Behave physics differently if you go left or right?
Is not just the left and right animation just a y-flip of each other?
Behave differently the object if you go left or right?

Probably all you need is a flag to know in which direction are you going. And in the painting function a code to change y-flip of sprites (also x & y, but can be figured easily).

Also, if you are beginning to repeat code, probably you need to develop you own tools to stuff it into data, and let the engine be a player of that data.
HELP. Spanish TVs are brain washing people to be hostile to me.

Post Reply