Vous êtes sur la page 1sur 4

Part Two: Sprite Rotation and Collision detection

Before you start this tutorial, make sure you have the source code from part one. This tutorial uses that
code and builds on it. The full source for this tutorial is at the end of the lesson.

Now, if you'll remember from the first lesson, we loaded sprites and moved one around with the arrow
keys. Now, the sprite we moved around was a space ship, and the way it moved looked rather strange,
always facing upward, yet moving every direction. The first thing we'll do to improve our program is to
make that ship rotate around and move in the direction that it is facing. Since we'll be using decimal
values, we'll need to modify our sp1x and sp1y values from integers to real values. This allows us to
use decimals, rather than just whole numbers. We'll also need new variables, Ang#, which is the angle
that the sprite is facing, sp2width and sp2height, which we'll use to make collision detection easier, and
collided, which we'll use to check collisions.

Dim backgroundImage, spriteTex1, spriteTex2, sprite1, sprite2, bgSprite, sp1x#,


sp1y#
Dim sp2x, sp2y, sp2width, sp2height
Dim ang#, collided

Make sure you fix all your sp1x and sp1y handles by adding a "#" at the end of them.

OK, within the main loop, after we bind sprite1 and set its X,Y coordinates with SprSetPos, we'll be
adding a new line.
While true
BindSprite(sprite1)
SprSetPos(sp1x#, sp1y#)
SprSetAngle(ang#)

This SprSetAngle(ang#) rotates the sprite to the specified angle. Right now, that will be zero, but we
can adjust this angle within the program to make the ship sprite appear to turn.

We'll also be adding all new code to our user input area
if ScanKeyDown(VK_UP) then
sp1y# = sp1y#- SinD(ang#+90)*3
sp1x# = sp1x#- CosD(ang#+90)*3
end if
if ScanKeyDown(VK_DOWN) then
sp1y# = sp1y#+SinD(ang#+90)*3
sp1x# = sp1x#+CosD(ang#+90)*3
end if
if ScanKeyDown(VK_LEFT) then
ang# = ang#-10
end if
if ScanKeyDown(VK_RIGHT) then
ang# = ang#+10
end if

For now, ignore UP and DOWN. Let's start with LEFT and RIGHT. What we are doing with these is
modifying the value of ang# so that when the loop runs through and does SprSetAngle, the sprite will
be rotated to a different angle. This causes the turning effect of the sprite.
Now, let's look at UP and DOWN. This might look a little confusing if you've never used sine and
cosine Trigonometric functions before. I'm not going to explain how sine and cosine work, because that
can become a lengthy subject to explain, trust me. I'll just tell you that it has to do with measuring
distances based on the specified angle (in this case, ang#), and that sine corresponds with Y coorinates,
and cosine corresponds with X coordinates. Here, sinD returns the value of sine in degrees. CosD
returns the value of cosine in degrees. So, why are we adding 90 to ang#? Normally in a coordinate
plane, when we start at 0 degrees, our sprite should be facing to the right. Our ship, however, is facing
up, at what would be 90 degrees. We are compensating for this by adjusting our angle by 90 degrees
when we take our sine and cosine values. Why are we multiplying it by 3? To make the ship move
faster. You may adjust this value however you like, but I thought that 3 fit our needs best.

If you run this code right now, you should have a ship that turns and moves in the direction that it is
facing. There are still problems, though. You can fly right off the screen, and right through the asteroid.
I'll show you next how to correct these issues. Put this within your main loop, along with all the code
after it.
if sp1X# < -16 then 'if sprite is off the left side
sp1x# = 640 'make it appear on the right
elseif sp1x# > 656 then 'if it is off the right side
sp1x# = 0 'make it appear on the left
end if
if sp1y# < -16 then 'if it's off the top
sp1y# = 480 'put it at the bottom
elseif sp1y# > 496 then 'if off the bottom
sp1y# = 0 'put it at the top
end if

What we've achieved with this code is a ship that will reappear on the opposite side of the screen when
it leaves the visible area. We are checking it against -16, because that is half the length and height of the
sprite. This makes sure it totally leaves the screen, whereas checking it at 0 would make it appear at the
other end when only half of the sprite has left the screen. We also add 16 to 640 and 480 when we
check X and Y respectively. So now, our ship can never disappear off the screen completely. Let's
finally deal with sprite-to-sprite collision detection.
if sp1x# < sp2x+(sp2width/2) and sp1x# > sp2x-(sp2width/2) then
if sp1y# < sp2y+(sp2height/2) and sp1y# > sp2y-(sp2height/2) then
collided = 15
end if
end if

Let's take this line-by-line. The first line checks if sp1x is between sp2x minus half its width, and sp2x
plus half its width. Why minus and plus half its width? Sp2x only deals with one single point, same
with sp2y, and we want to check that our sprite is colliding with the whole asteroid, not just its center
point, so we take the half the sprite's width in each direction, making up the whole sprite, see? With Y,
we do mostly the same thing, except using half the asteroid sprite's height. If all of these conditions
return true, then our ship is within the area of the asteroid, and we need to handle a collision event. I set
collided to equal 15. You'll see why with the next block of code.
if collided > 0 then
sp1y# = sp1y#+SinD(ang#+90)*9
sp1x# = sp1x#+CosD(ang#+90)*9
collided = collided-1
end if
Basically, when collided is greater than 0, we move our ship backwards at a fast rate, making it look
like it bounces off. Sure, it's not the best-looking bounce, but it works. (Maybe I'll do a better one in a
later tutorial). To make sure that this doesn't happen infinitely, we decrease the value of collided each
time. So there you have it, easy collision detection. That's it for Part two, more still to come on sprites!
~Stu

Full source code:


Dim backgroundImage, spriteTex1, spriteTex2, sprite1, sprite2, bgSprite, sp1x#,
sp1y#
Dim sp2x, sp2y, sp2width, sp2height
Dim ang#, collided

backgroundImage = LoadTexture("Textures\Background.bmp")
bgSprite = NewSprite(backgroundImage)
SprSetPos(320,240)
SprSetSize(640, 480)
SprSetZOrder(3)

spriteTex1 = LoadTexture("Data\F117.png")
sprite1 = NewSprite(spriteTex1)
SprSetPos(320,240)
SprSetSize(32,32)
SprSetZOrder(1)

spriteTex2 = LoadTexture("data\asteroid.png")
sprite2 = NewSprite(spriteTex2)
SprSetPos(520,240)
SprSetSize(64,64)
SprSetZOrder(2)
sp2width = 64
sp2height = 64

sp1x# = 320
sp1y# = 240
sp2x = 520
sp2y = 240

While true
BindSprite(sprite1)
SprSetPos(sp1x#, sp1y#)
SprSetAngle(ang#)
BindSprite(sprite2)
SprSetPos(sp2x, sp2y)
if ScanKeyDown(VK_UP) then
sp1y# = sp1y#- SinD(ang#+90)*3
sp1x# = sp1x#- CosD(ang#+90)*3
end if
if ScanKeyDown(VK_DOWN) then
sp1y# = sp1y#+SinD(ang#+90)*3
sp1x# = sp1x#+CosD(ang#+90)*3
end if
if ScanKeyDown(VK_LEFT) then
ang# = ang#-10
end if
if ScanKeyDown(VK_RIGHT) then
ang# = ang#+10
end if
if sp1X# < -16 then
sp1x# = 640
elseif sp1x# > 656 then
sp1x# = 0
end if
if sp1y# < -16 then
sp1y# = 480
elseif sp1y# > 496 then
sp1y# = 0
end if
if sp1x# < sp2x+(sp2width/2) and sp1x# > sp2x-(sp2width/2) then
if sp1y# < sp2y+(sp2height/2) and sp1y# > sp2y-(sp2height/2) then
collided = 15
end if
end if
if collided > 0 then
sp1y# = sp1y#+SinD(ang#+90)*9
sp1x# = sp1x#+CosD(ang#+90)*9
collided = collided-1
end if
WaitTimer(20)
wend

Vous aimerez peut-être aussi