Day 11 - Video Functions ← Previous

Day 12 - Quick Demos

This part of the tutorial will contain a few small codes, either new or based on some of the other examples, which can help you a little more in DS development...

Following the Stylus

This is an example with a ship following the stylus. You could use this for a GTA 2D like movement system. You can look at the final version of this code in the PAlib Examples, under Demos/FollowStylus/. It simply shows a sprite following the stylus, turning towards it.

I’ll only post and comment the difference with the other code Trajectory Example :

s32 x = (128) << 8; // ship x position in 8bit fixed point
s32 y = (96) << 8; // Y
u16 angle = 0; // direction in which to move !
 
while(1)
{
	angle = PA_GetAngle(x>>8, y>>8, Stylus.X, Stylus.Y);
	PA_SetRotsetNoZoom(0, 0, angle); // Turn the ship in the correct direction
		
	if (Stylus.Held){ // Move forward
		x += PA_Cos(angle);
		y -= PA_Sin(angle);
	}
 
	PA_OutputText(1, 5, 10, "Angle : %d  ", angle);
	
	PA_SetSpriteXY(0, 0, (x>>8)-16, (y>>8)-16); // Sprite position converted to normal...
		
	PA_WaitForVBL();
}
  • First off, x and y are now the sprite’s central point, and not the sprite’s upper left corner... why ? Because it gives a better result, you’ll see...
  • angle = PA_GetAngle(x»8, y»8, Stylus.X, Stylus.Y); This is completely different from the other angle code... This time, we get the angle using the sprite’s center and the stylus (hence the »8, and using x and y as the center of the sprite...).
  • if (Stylus.Held){ was changed in order to move when the stylus is pressed...

And that’s it ! It was a pretty simple demo, I must admit, but that’s because it’s the first one in here :-)

Throwing and Bouncing Frisbees

This will be a tutorial in several steps... The end goal will be to have a nice demo with 10 frisbees flying around, thrown by the stylus, and colliding... We’ll do this in 3 easy steps :

  • First, displaying one frisbee flying around on both screens, thrown by the stylus
  • Then, modifying that code to have 10 frisbees, using a structure array
  • In the end, adding collisions to that code !

Part 1 - 1 Frisbee

Here comes a nice little example : it shows how you can use the stylus codes to catch a frisbee, throw it, and have it bounce on the walls (on both screens...). And have it turn on itself, just because I wanted it too...

You’ll find this example in Demos/Frisbee in the next PAlib version (there was an old outdated one without stylus support)

I’ll post a large chunk of code :

 
#define FRISBEE 10 // Sprite number...
#define SCREENHOLE 48 // Size of the space between the screens... This is what looked the best
 
 
typedef struct{
	s16 x, y; // This is for the frisbee's position
	s16 vx, vy; // Frisbee speed
	s16 angle; // To make the frisbee turn on itself
}frisinfos;
 
frisinfos frisbee;  // Frisbee structure variable
 
 
 
int main(void)
{
 
// Initialise the lib...
PA_Init();
PA_InitVBL(); 
 
PA_InitText(1, 0);
 
// Load the palettes for the sprites on both screens
PA_DualLoadSpritePal(0, (void*)sprite0_Pal);
 
// Create the sprite on both screens...
PA_DualCreateSprite(FRISBEE, (void*)frisbee_Sprite, OBJ_SIZE_32X32, 1, 0, 96, 300); // Bottom screen
PA_DualSetSpriteRotEnable(FRISBEE, 0); // Enable rotation/zoom, rotset 0
 
// Sprite initial position...
frisbee.x = 96+16; 
frisbee.y = 300+16; // on the bottom screen
 
// Speed of frisbee in both ways
frisbee.vx = 0;
frisbee.vy = 0;
 
while(1)
{
	// Move with the stylus, or move on...
	if (PA_MoveSprite(FRISBEE)){
		frisbee.x = PA_MovedSprite.X;
		frisbee.y = PA_MovedSprite.Y + 192 + SCREENHOLE;
		frisbee.vx = PA_MovedSprite.Vx;		frisbee.vy = PA_MovedSprite.Vy; 
	}
	else{
		// Now, the frisbee's fixed point position will be updated according to the speed...
		frisbee.x += frisbee.vx;
		frisbee.y += frisbee.vy;
		
		// If the sprite touches the left or right border, flip the horizontal speed
		if ((frisbee.x -16 <= 0) && (frisbee.vx < 0)) frisbee.vx = -frisbee.vx; 
		else if ((frisbee.x + 16 >= 256)&&(frisbee.vx > 0)) frisbee.vx = - frisbee.vx;
	
		// Same thing, for top and bottom limits...
		if ((frisbee.y -16 <= 0) && (frisbee.vy < 0)) frisbee.vy = -frisbee.vy;
		else if ((frisbee.y + 16 >= 192 + 192 + SCREENHOLE)&& (frisbee.vy > 0)) frisbee.vy = - frisbee.vy;		
		// The bottom limit is at the bottom of the bottom screen, so that would be 2 screen heights, plus the space in between...
		PA_DualSetSpriteXY(FRISBEE, frisbee.x-16, frisbee.y-16);
	}
		
	PA_OutputText(1, 2, 10, "SpeedX : %d    ", frisbee.vx);
	PA_OutputText(1, 2, 11, "SpeedY : %d    ", frisbee.vy);
		
	frisbee.angle+=4; // Make the frisbee turn...
	PA_DualSetRotsetNoZoom(0, frisbee.angle);
 
	PA_WaitForVBL();  // Synch to the framerate...
	}

And now, the comments...

#define FRISBEE 10 // Sprite number...
#define SCREENHOLE 48 // Size of the space between the screens... This is what looked the best

Are just 2 definitions that will make our life easier... FRISBEE is the frisbee’s sprite number, and SCREENHOLE the space in between the screens, in pixels.

// Load the palettes for the sprites on both screens
PA_DualLoadSpritePal(0, (void*)sprite0_Pal);
 
// Create the sprite on both screens...
PA_DualCreateSprite(FRISBEE, (void*)frisbee_Sprite, OBJ_SIZE_32X32, 1, 0, 96, 300); // Bottom screen
PA_DualSetSpriteRotEnable(FRISBEE, 0); // Enable rotation/zoom, rotset 0

Here we load the palette, create the sprite on both screens (hence the Dual prefix), and enable rotations... Have you noticed the sprite’s Y coordinate ? 300... That’s on the bottom screen. In Dual Mode, PAlib considers the DS like having a single screen of 384+SCREENHOLE pixels, in our case 48 pixels... (which looks the best on DS, but is horrible on emulators...)

Then we initialise the frisbee structure values :

frisbee.x = 96+16; 
frisbee.y = 300+16; // on the bottom screen
 
frisbee.vx = 0;
frisbee.vy = 0;

The position is set to 96, 300... +16 because we’ll use the sprite’s center... and it’s a 32×32 sprite. And the speed to 0... This does not use fixed point, but we could have...

Next comes one of the important parts of code...

if (PA_MoveSprite(FRISBEE)){
	frisbee.x = PA_MovedSprite.X;
	frisbee.y = PA_MovedSprite.Y + 192 + SCREENHOLE;
	frisbee.vx = PA_MovedSprite.Vx;		frisbee.vy = PA_MovedSprite.Vy; 
}

This part of the code has multiple functions :

  • PA_MoveSprite(sprite number) is an important PAlib function we’ve already seen. It checks if the stylus’s touches the sprites, and moves it around according to the stylus position... If it does move the stylus, it will return 1... If that’s the case, we have several things to do :
  • Memorise the new X and Y coordinate of the frisbee... That’s done by doing frisbee.x = PA_MovedSprite.X;.
    • Why PA_MovedSprite.X ? Because PA_MovedSprite.X returns the moved sprite’s central point...
    • Why PA_MovedSprite.Y + 192 + SCREENHOLE; ?? Because the MoveSprite function returns the position for a sprite on the bottom screen, so that would be y being between 0 and 191... However, we are considering the 2 screens as only 1, so we have to convert that to the correct positiono... So we add 192 for the top screen, SCREENHOLE for the space inbetween the screens...
  • Then we memorise the stylus’s speed, horizontally and vertically (respectively vx and vy).

In the end, what you’ll want to remember, is the PA_MovedSprite structure, which stores information on the sprite’s position, as well as the current moving speed... So as you see, there actually is more the PA_MoveSprite than just moving the sprite around :-P

Now, if the sprite wasn’t touched, we go into a different loop, which starts with

else{
	// Now, the frisbee's fixed point position will be updated according to the speed...
	frisbee.x += frisbee.vx;
	frisbee.y += frisbee.vy;

This bit of code moves the sprite according to the current speed... Nothing special about that

// If the sprite touches the left or right border, flip the horizontal speed
if ((frisbee.x -16 <= 0) && (frisbee.vx < 0)) frisbee.vx = -frisbee.vx; 
else if ((frisbee.x + 16 >= 256)&&(frisbee.vx > 0)) frisbee.vx = - frisbee.vx;
	
// Same thing, for top and bottom limits...
if ((frisbee.y -16 <= 0) && (frisbee.vy < 0)) frisbee.vy = -frisbee.vy;
else if ((frisbee.y + 16 >= 192 + 192 + SCREENHOLE)&& (frisbee.vy > 0)) frisbee.vy = - frisbee.vy

This is more important... It checks if the frisbee is moving out of the screen ! If that’s the case, it’ll change the speed to make the frisbee move in the correct direction... Concerning the Y position, you’ll notice that we have to check with 192+192+SCREENHOLE, because that’s the total height of both screens, taking into account the space...

	PA_DualSetSpriteXY(FRISBEE, frisbee.x-16, frisbee.y-16);
}

This ends the else loop... It just positions the sprite at the correct place. Notice the Dual prefix, to use both screens as 1... -16 is there because x and y are the central position, and we need to give the top left corner position...

The end of the code is pretty trivial... First we show the current speed on the top screen, just to check it out. And then we make the frisbee turn, with

frisbee.angle+=4; // Make the frisbee turn...
PA_DualSetRotsetNoZoom(0, frisbee.angle);

It turns at a speed of 4 PAlib degrees per frame, which looks pretty good... I used DualSetRotset to make it turn on both screens...

And that it ! I recommend compiling and testing the code (even works on Dualis r11, except that the colors are wrong), and you’ll see it was a pretty nice example...

Guess what ? For the next example, I’ll do the exact same thing, but with 10 frisbees :-P You’ll see there are like 2 lines of code to add, using an array of structures...

Part 2 - 10 Frisbees

As said before, this should be fairly easy... I’ll post most of the code, but won’t comment the things we have already seen right before...

typedef struct{
	s16 x, y; // This is for the frisbee's position
	s16 vx, vy; // Frisbee speed
	s16 angle; // To make the frisbee turn on itself
}frisinfos;
 
frisinfos frisbee[10];  // 10 Frisbees !!
 
 
 
int main(void)
{
 
// Initialise the lib...
PA_Init();
PA_InitVBL(); 
 
PA_InitText(1, 0);
 
// Load the palettes for the sprites on both screens
PA_DualLoadSpritePal(0, (void*)sprite0_Pal);
 
s32 i; // will be used in for loops to cycle through the frisbees...
 
PA_InitRand(); // Init the random stuff...
 
for (i = 0; i < 10; i++){
	// Sprite initial position...
	frisbee[i].x = (PA_Rand()%256)-16; // random position on the screen
	frisbee[i].y = 192+SCREENHOLE + (PA_Rand()%192)-16; // random position on the bottom screen; 
	
	// Speed of frisbee in both ways
	frisbee[i].vx = 0;
	frisbee[i].vy = 0;
	
	frisbee[i].angle = 0;	
	
	// Create the sprite on both screens...
	PA_DualCreateSprite(FRISBEE+i, (void*)frisbee_Sprite, OBJ_SIZE_32X32, 1, 0, frisbee[i].x-16, frisbee[i].y-16); 
	PA_DualSetSpriteRotEnable(FRISBEE+i, i); // Enable rotation/zoom, rotset 0
}
 
	while(1)
	{
		for (i = 0; i < 10; i++){
			// Move with the stylus, or move on...
			if (PA_MoveSprite(FRISBEE+i)){
				frisbee[i].x = PA_MovedSprite.X;
				frisbee[i].y = PA_MovedSprite.Y + 192 + SCREENHOLE;
				frisbee[i].vx = PA_MovedSprite.Vx;		frisbee[i].vy = PA_MovedSprite.Vy; 
			}
			else{
				// Now, the frisbee's fixed point position will be updated according to the speed...
				frisbee[i].x += frisbee[i].vx;
				frisbee[i].y += frisbee[i].vy;
			
				// If the sprite touches the left or right border, flip the horizontal speed
				if ((frisbee[i].x - 16 <= 0) && (frisbee[i].vx < 0)) frisbee[i].vx = -frisbee[i].vx; 
				else if ((frisbee[i].x + 16 >= 256)&&(frisbee[i].vx > 0)) frisbee[i].vx = - frisbee[i].vx;
		
				// Same thing, for top and bottom limits...
				if ((frisbee[i].y - 16 <= 0) && (frisbee[i].vy < 0)) frisbee[i].vy = -frisbee[i].vy;
				else if ((frisbee[i].y + 16 >= 192 + 192 + SCREENHOLE)&& (frisbee[i].vy > 0)) frisbee[i].vy = - frisbee[i].vy;		
				// The bottom limit is at the bottom of the bottom screen, so that would be 2 screen heights, plus the space in between...
				PA_DualSetSpriteXY(FRISBEE+i, frisbee[i].x-16, frisbee[i].y-16);
		
			}
			frisbee[i].angle+=4; // Make the frisbee turn...
			PA_DualSetRotsetNoZoom(i, frisbee[i].angle);
		}

Ok, as you may see, there are a few differences...

  • First one : frisinfos frisbee[10]; /, this is now an array !! Yahoo ! Of a total size of 10, for 10 frisbees...
  • Then comes the s32 i;, which will be used for the for loops...
  • There’s also PA_InitRand();, which isn’t much, but means that on DS you should have the frisbees at different places each time you try it...

The frisbee init code has changed a bit, too :

for (i = 0; i < 10; i++){
	// Sprite initial position...
	frisbee[i].x = (PA_Rand()%256)-16; // random position on the screen
	frisbee[i].y = 192+SCREENHOLE + (PA_Rand()%192)-16; // random position on the bottom screen; 
	
	// Speed of frisbee in both ways
	frisbee[i].vx = 0;
	frisbee[i].vy = 0;
	
	frisbee[i].angle = 0;	
	
	// Create the sprite on both screens...
	PA_DualCreateSprite(FRISBEE+i, (void*)frisbee_Sprite, OBJ_SIZE_32X32, 1, 0, frisbee[i].x-16, frisbee[i].y-16); 
	PA_DualSetSpriteRotEnable(FRISBEE+i, i); // Enable rotation/zoom, rotset 0
}
  • This gives a random position on the screen, and creates the sprite at that position...
  • Plus, notice the FRISBEE+i instead of the sprite number ? This means the first frisbee will have number FRISBEE (10), then FRISBEE+1 (11), etc... pretty cool, isn’t it ?
  • Same thing for the rotset, they each have one number (0-9)
  • Instead of frisbee.x, you now have frisbee[i].x, as it’s an array... this accesses frisbee number i... You’ll see the same thing in the rest of the demo...

The last bit of code that changes is in the infinite loop...

  • for (i = 0; i < 10; i++){ was added to run the sequence for each sprite ! Yes, it’s THAT simple.
  • The rest is strictly identical, just replaces frisbee by frisbee[i], to move all the frisbees 1 by 1...

And that’s all there is to know for this time ! Next tutorial to come up ? 10 frisbees with collisions !

Part 3 - 10 Frisbees Colliding

This example is just another quick modification of the Firsbee2 example, but adding a basic collision system so that the frisbees don’t run into each other... As it is the exact same code with only a few lines added at 1 part of it, I decided to only post the new code... I left in the DualSetSpriteXY(...) so that you see where to add it...

	PA_DualSetSpriteXY(FRISBEE+i, frisbee[i].x-16, frisbee[i].y-16);
}
			
u8 j;
for (j = 0; j < i; j++){ // Test collisions for all frisbees with a smaller number...
	if (PA_Distance(frisbee[i].x, frisbee[i].y, frisbee[j].x, frisbee[j].y) < 32*32) {
		frisbee[i].vx = (frisbee[i].x - frisbee[j].x)/6;
		frisbee[i].vy = (frisbee[i].y - frisbee[j].y)/6;
		frisbee[j].vx = -frisbee[i].vx;
		frisbee[j].vy = -frisbee[i].vy;				
	}
}

Yes, that’s all you need to have ALL the frisbees hitting each other pretty well !

The first thing that was needed was to check for collisions between all the frisbees... This is done with a for loop : for (j = 0; j < i; j++). Have you noticed anything strange about this loop ? If it had been like the first for loop, it would be from 0 to 10... but here, it’s from 0 to... i ??? Why ?

  • We are already in a for loop, which moves all frisbees, from 0 to 9 included. by adding another similar loop in it, we could test, for every frisbee, if it hits with frisbees 0 to 9... This would however lead to 2 problems :
    • It would test every frisbee collision twice : testing frisbees 0 vs 1, then 1 vs 0, for example... This is a huge waste of time.
    • It would test the collision with twice the same number : between 0 and 0, for example ! And as that’s the same frisbee, it would return a collision, and bug...
  • So to avoid this, it tests the collisions only with the frisbees already moved at that frame. Even if it might not look intuitive, let’s write down the different tests :
    • Frisbee 0 : doesn’t do any test (exists if j < i, and i is 0, so exits before doing anything)
    • Frisbee 1 : tests only with frisbee 0 (only frisbee to be lower than 1 in number)
    • Frisbee 2 : tests with frisbees 0 and 1, which weren’t tested again frisbee 2, so that’s ok
    • Frisbee 3 : tests versus 0, 1, and 2, that’s perfect...
    • etc...
  • So it works perfectly !

Next comes the collision check, taken from the Circular Collision tutorial (in the Math Dev stuff) : if (PA_Distance(frisbee[i].x, frisbee[i].y, frisbee[j].x, frisbee[j].y) < 32*32), which checks if the distance between the 2 frisbees is compatible with a collision... if that’s the case, it’ll just modify the speed of both of the frisbees in collision For the first one :

frisbee[i].vx = (frisbee[i].x - frisbee[j].x)/6;
frisbee[i].vy = (frisbee[i].y - frisbee[j].y)/6;

The new speed is defined by the substraction of the frisbee’s position. This guarantees that they will move appart from one another. I divided by 6 to have a nice speed, if not it would be way too fast... You can change the 6 to get a different speed when it collides...

frisbee[j].vx = -frisbee[i].vx;
frisbee[j].vy = -frisbee[i].vy;

This code gives the opposite direction to the second frisbee, nothing special about it...

And that’s it ! It was really simple, wasn’t it ? There is one flaw to this system, though... It doesn’t come from the collision detection code, but from the new speed code... It does not take into account the speed at which the frisbees were moving. So even if they hit really hard or really slowly, they’ll move apart at the same speed...

If you need more precise speed correction, I recommend that you check the next example, as it takes speed into account in a pretty effective way...

Puck Hitting

Here comes another demo ! This one is derived from the circular collision code, as well as the frisbee example... What does it do ? You have a Puck in the middle of the screen (just a blue circle, nothing special, but if anyone wants to change the graphics...), and you have your ‘raquette’ (another blue circle). When you hit the puck with the raquette, it sends the puck bouncing all over the place. The harder you hit, the faster it’ll go.

Here’s the code, you’ll see it’s almost nothing new... Most of it is just recycled code...

typedef struct{
	s16 x, y; // position
	s16 vx, vy; // speed
}puckinfos;
 
puckinfos puck;
 
#define SCREENHOLE 48
 
int main(void){
 
	PA_Init();
	PA_InitVBL();
	
	PA_InitText(1,0); // On the top screen
 
	PA_DualLoadSpritePal(0, (void*)sprite0_Pal);
	
	// This'll be the movable sprite...
	PA_CreateSprite(0, 0,(void*)circle_Sprite, OBJ_SIZE_32X32,1, 0, 16, 16); 	
	s32 x = 16; s32 y = 16; // Sprite's center position
	
	// This will be the hit circle
	PA_DualCreateSprite(1,(void*)circle_Sprite, OBJ_SIZE_32X32,1, 0, 128-16, 96-16); 
	puck.x = 128; puck.y = 96+192+SCREENHOLE; // central position on bottom screen
	puck.vx = 0; puck.vy = 0; // No speed
	
	
	while(1)
	{
		if (PA_MoveSprite(0)){
			x = PA_MovedSprite.X;
			y = PA_MovedSprite.Y;
		}
		
		// Collision ?
		if (PA_Distance(x, y, puck.x, puck.y-192-SCREENHOLE) < 32*32) {
			// Collision, so we'l change the pucks speed to move it out of our 'raquette'
			u16 angle = PA_GetAngle(x, y, puck.x, puck.y-192-SCREENHOLE); // New direction angle
			u16 speed = (32*32-PA_Distance(x, y, puck.x, puck.y-192-SCREENHOLE))/32; // The closer they are, the harder the hit was...
			puck.vx = (PA_Cos(angle)*speed)>>8;
			puck.vy = -(PA_Sin(angle)*speed)>>8;
		}
		
		puck.x += puck.vx;
		puck.y += puck.vy;
	
		// If the sprite touches the left or right border, flip the horizontal speed
		if ((puck.x -16 <= 0) && (puck.vx < 0)) puck.vx = -puck.vx; 
		else if ((puck.x + 16 >= 256)&&(puck.vx > 0)) puck.vx = - puck.vx;
 
		// Same thing, for top and bottom limits...
		if ((puck.y -16 <= 0) && (puck.vy < 0)) puck.vy = -puck.vy;
		else if ((puck.y + 16 >= 192 + 192 + SCREENHOLE)&& (puck.vy > 0)) puck.vy = - puck.vy;		
		// The bottom limit is at the bottom of the bottom screen, so that would be 2 screen heights, plus the space in between...
		PA_DualSetSpriteXY(1, puck.x-16, puck.y-16);
		
		
 
		PA_WaitForVBL();
	}
	return 0;
}

And the comments...

typedef struct{
	s16 x, y; // position
	s16 vx, vy; // speed
}puckinfos;
 
puckinfos puck;

Classic definition we used over and over again, to store the puck’s position and speed... In this example, we haven’t used fixed point, though we could have.

Then the palette is loaded, the first sprite too, and then

PA_DualCreateSprite(1,(void*)circle_Sprite, OBJ_SIZE_32X32,1, 0, 128-16, 96-16); 
puck.x = 128; puck.y = 96+192+SCREENHOLE; // central position on bottom screen
puck.vx = 0; puck.vy = 0; // No speed

This loads the puck for both screens, and sets its current position and speed...

Then comes the classic

if (PA_MoveSprite(0)){
	x = PA_MovedSprite.X;
	y = PA_MovedSprite.Y;
}

Just to store the raquette’s position (central point)...

The next part is the only new code... It’s what is used to hit the puck with a different speed depending on the way you hit it, and send it in the correct direction...

if (PA_Distance(x, y, puck.x, puck.y-192-SCREENHOLE) < 32*32) {
	// Collision, so we'l change the pucks speed to move it out of our 'raquette'
	u16 angle = PA_GetAngle(x, y, puck.x, puck.y-192-SCREENHOLE); // New direction angle
	u16 speed = (32*32-PA_Distance(x, y, puck.x, puck.y-192-SCREENHOLE))/32; // The closer they are, the harder the hit was...
	puck.vx = (PA_Cos(angle)*speed)>>8;
	puck.vy = -(PA_Sin(angle)*speed)>>8;
}
  • if (PA_Distance(x, y, puck.x, puck.y-192-SCREENHOLE) < 32*32) Check if there’s a collision, like said before... 32 is the distance between the 2 circles (must be change if you change the size of one of the circles), and 32×32 because we use the squared distance, for speed issues...
  • We used puck.y-192-SCREENHOLE, because the coordinate is for 2 screens in height for the puck, while the raquette is only on the bottom screen.... So ywe have to substract the size of the top screen (192) and the screen space (SCREENHOLE)...
  • u16 angle = PA_GetAngle(x, y, puck.x, puck.y-192-SCREENHOLE); is to get the angle formed with the puck’s and the raquette’s centers... What for ? You can draw this on a paper, and you’ll see that this angle is the direction in which the puck should go !! Yup ! I don’t have the time to do another drawing for this, but if someone ever does one, I’ll add it here...
  • u16 speed = (32*32-PA_Distance(x, y, puck.x, puck.y-192-SCREENHOLE))/32; is the second very important line, as it will determine the puck’s speed ! How does it work ? The closer you are from the puck when it hits, the faster you were moving... why ? Because if you touch the puck by only 1 pixel, it means you were moving very slowly... But if you touch the puck by like 16 pixels ? It means that before the frame was updated, you had the time to move by at least 16 pixels, which is 16 times faster than the 1 pixel hit...
    • 32×32 is the square of the distance needed to hit. If you had a collision by just 0 pixels, you didn’t hit the puck, since your speed wasn’t high enough...
    • Then the distance (PA_Distance(x, y, puck.x, puck.y-192-SCREENHOLE)) is recalculated, and substracted to the squared distance... This will give a higher speed when you move fast...
    • And at last, this speed is divided by 32... why ? because it was just trial and error, lol... YOu can change 32 to have higher or lower speeds, and thus adjust it to your need...
  • puck.vx = (PA_Cos(angle)*speed)»8; determines the horizontal (vx) speed of the puck, with the new hit. This speed is found by using the Cos of the angle and the global speed it will have... It’s just like the Trajectory tutorial, but with the speed added in...
    • But in that case, why is there a »8 ??? Because, as said at the beginning, I haven’t used fixed point math in this example. And PA_Cos returns a number in fixed point math, so I had to convert it to a normal number again...
    • Then why is the »8 after the speed, and not right after the Cos ?? Because if done after the PA_Cos, as it’s an integer, the result would always be 0 ! When done after the multiplication with the speed, the total value before division is superior to 256, so dividing by 256 (which is the same as »8) will not result in given you 0, but rather the correct speed in pixels, rounded down (a true speed of 2.5 will give you 2, etc...).
  • The same then applies to the vertical speed, with a negative sign because it’s Sin... (and Sin is bad, negative, lol... you must not Sin ! ;-))

And that’s about it ! I won’t comment the rest of the code, as it’s just a copy/paste of the frisbee code (I just replaced ‘frisbee’ by ‘puck’ ).

Hope this was clear enough ! Enjoy :-)

 
day12.txt · Last modified: 21/07/2009 21:36 by 94.192.202.138
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki