Original Post

Here’s my submission for the competition, Mario Kart Virtual Cup. It should work fine in the latest Reality Boy, and it works (best) on hardware. I’ll probably upload a video of it when I get home tonight for those without a flash cart, or those too lazy to burn it ;-). Enjoy!


32 Replies

WOW :-O I’m impressed DogP!, great work!.


BTW, I’m curious about how do you implement collision detection and how do you define the circuit? If is not a problem to ask 🙂


Wow, this is really great DogP!

Pretty much everything is done with the BGMap… the track is a 2×2 BGMap world (standard image, affine transformed of course), and I have a collision table for each char in the charset to tell whether it’s track, wall, dirt, pit, etc. I check my position in the BGMap to get the char, then check my position in the char with my table for the exact action.

BTW, Thanks for the compliments.


The affine 3D track effect is very impressive. Nice work.

  • This reply was modified 15 years, 5 months ago by dasi.

Very cleaver, thanks for sharing.


I can’t get the accelerator to work, (did you implement the “spin-out” w/out the animation?) and the converted kart 3D effect is somewhat lacking, at least in the emu (I probably would have just had “cardboard cutouts”) but given the time, man-power, and technology constraints, this is really fine work! I will so totally consume that source code when (if?) it’s released. 😉

The right trigger is accelerate. I used to have A for accelerate, but it was too difficult to hold A and press the Right D-Pad to look around. I figured there’s no real need to have both triggers do the same thing anyway. And you can do the spin out (and boost) by hitting the gas and brake at the same time during the start. I’ll put up a video showing some of the features in a little bit.


Wow! It looks really great, but there are a few things i noticed:
– the 3d effect of the player/kart looks a little bit strange
– the ground seems to be sometimes quite choppy. maybe because of too low accuracy in fixedpoint calculations and/or low precision LUTs??
– it looks like there is a bug in your parallax (MP) calculations for the ground. there is a hardly visible bent where MP becomes zero. If you increase the paralax value, it should become more visible. (its only visible on the vb, not in rboy)

Thanks for the comments… yeah, the player 3D effect isn’t perfect on all characters because I’m using kart images from the SNES SMK, and to get the 3D effect I’m using images of a turn slightly off center on each eye, but the original images aren’t necessarily good for stereoscopic viewing. I think it looked better than 2D cutouts like I originally was using though, and I plan on tweaking/redoing the graphics for the characters in the future.

The affine ground and parallax are probably not perfect, and I plan on checking over it again in the future, but especially when a map is rotated at intermediate angles there is inherently less precision in the affine tables. Of course imperfections are more visible with textured ground rather than plain ground, but tracks like the Ghost House are much cooler looking than the untextured track in Mario Circuit IMO.

Overall, the minor imperfections weren’t worth spending too much time on though, since the idea is to be racing rather than staring at the track ;-). I thought it was more important (and fun) to add some interesting things like having Lakitu, background music, speech, sound effects, rotating camera, etc.


Alright… for the people too lazy to burn this to a cart, or those without a cart, here’s a video I posted of it on youtube: http://www.youtube.com/watch?v=k2FKFqO8Kpw .

Oh, and to answer the questions about controls… the right trigger is gas, B the is brake/reverse, the left trigger is jump, the left D-Pad turns, and the right D-Pad changes camera angle.

To get the boost at startup you have to do a burnout while waiting for the light to go “green”. If you do a burnout too long it stalls… and to get the most boost, you want your engine to be at max rev, and you have to let off the brake the moment before the light changes (if you’re holding the brake after the light changes, you spin the tires at the start). It’s a little more complex than most Mario Kart games, but I find them to be too easy, and this way can give you a partial boost if you’re close, but it’s really tough to get the max boost.


Hey DogP, I’m really curious about what kind of tricks are you putting off to made all those affine calculations.

I’ve changed the code provided in libgccvb to use always fixed point math:

typedef struct PDx_ST {
fix7_9 pa;
fix13_3 pb;
fix7_9 pc;
fix13_3 pd;
fix13_3 dx;
fix13_3 dy;
s16 paralax;
} PDx_ST ;

and using the following code to write the param table:

void affineSetAll(u16 param, PDx_ST * pdx, s16 max) {
s16 i ;
AFFINE_ST *affine;
affine = (AFFINE_ST*)PARAM(param);
for (i = 0; i < max; i++) { fix13_3 iFix = ITOFIX13_3(i); affine.pb_y = FIX13_3_MULT(iFix, pdx->pb) + pdx->dx;
.paralax = pdx->paralax;
.pd_y = FIX13_3_MULT(iFix , pdx->pd) + pdx->dy;
.pa = pdx->pa;
.pc = pdx->pc;

but I suspect it is still too slow, are you writing your functions in asm?


Thanks dasi.


Nope… no ASM (yet). I’m not using the affineSetAll function though… I’ve rolled the initial calculations of the pa, pb, etc into the same loop, taking out parts that are constant throughout the calculation, and enabling cache over the entire loop (the pa, pb, etc calculations take the majority of the time since the affineSetAll stuff can be done w/ just bit shifts and a few additions). I actually have some other speed improvements that I took out while I was debugging some other stuff which I haven’t put back in, since it was working fine, so I’ll put them back soon and see what happens.


Do you mean something like this?

void affineScale(u16 param, fix7_9 zoomX, fix7_9 zoomY,
····································s16 bg_x, s16 bg_y, s16 fg_x, s16 fg_y) {
········PDx_ST pdx;


········if(zoomX < 0){ ··················fg_x *= (-1); ········} ········pdx.pa = FIX7_9_DIV(ITOFIX7_9(1), zoomX); ········pdx.pb = ITOFIX13_3(0); ········pdx.pc = ITOFIX7_9(0); ········pdx.pd = FIX7_9TOFIX13_3(FIX7_9_DIV(ITOFIX7_9(1), zoomY)); ········pdx.dx = ITOFIX13_3(bg_x - (fg_x)); ········pdx.dy = ITOFIX13_3(bg_y-(fg_y)); ········pdx.paralax = 0x0000; ········{ ················AFFINE_ST *affine = (AFFINE_ST*)PARAM(param); ················AFFINE_ST source = { ································pdx.dx, ································pdx.paralax, ································pdx.dy, ································pdx.pa, ································pdx.pc ···············}; ················int max = FIX7_9TOI(FIX7_9_MULT(ITOFIX7_9(fg_y << 1), zoomY)); ················int i = 1; ················affine[0] = source; ················for (; i < max; i++) { ························fix13_3 iFix = ITOFIX13_3(i); ························source.pb_y = FIX13_3_MULT(iFix, pdx.pb) + pdx.dx; ························source.pd_y = FIX13_3_MULT(iFix, pdx.pd) + pdx.dy; ························affine = source;


Yeah, all in one function like that, and cache enabled around the whole thing. Of course I’m doing scaling, rotation, and a tilted view, so mine does a lot more computation than that, but I was able to break down all the variables and move some of the calculations outside of the loop and do minimal expensive calculations inside the loop.


Cool thanks!, I plan to have different methods for rotating/scaling/skew, etc, to make my Sprite interface very simple:

void Sprite_scale(Sprite this);

void Sprite_rotate(Sprite this, int angle);

and doing the heavy stuff there.


good game, to bad all the levels are from snes and there are no unique vb levels but still very good

Hope the game will be made within a year, cant wait 😉

Thanks… yeah, I took the levels from SNES, but I plan on making an editor so others can make unique tracks, since my time is better spent finishing the game engine, but others who aren’t programmers, but are good at level design could make cool levels.



Write a reply

The forum ‘PVB Coding Competition 2008’ is closed to new topics and replies.