In the forth part we breathe life into our hero and teach him how to shoot.
In the attached samplecode there is a new graphicfile for playersprites and shots isdo/gfx/player.png.
In isdo.gbas first we define again some new types, constants and variables:
TYPE TPlayer
PosX = 64
PosY = 64
Timer% = 0
Dir% = 0
Speed = 1.0
ENDTYPE
PosX und PosY is the position of our playersprite. Timer is a counter we increase every screenrefresh by 1. Dir is the move-direction and Speed defines the move-speed.
TYPE TShot
State%[8]
PosX[8]
PosY[8]
Dir%[8]
Count% = 8
ENDTYPE
Here we define a type for 8 shots. This means we will bable to show max. 8 shots at the same time.
State describes the current shot-state, PosX and PosY the shot-position and Dir the shot-direction. Count is the maximum of shots we can display at the same time.
// sprites
GLOBAL SPR_PLAYER% = 3
GLOBAL SPR_SHOT% = 18
In order that we don't have to memorize the appropriate spritenumber, we describe them with a clear constant.
// directions
GLOBAL DIR_UP% = 16
GLOBAL DIR_RIGHTUP% = 18
GLOBAL DIR_RIGTH% = 2
GLOBAL DIR_RIGHTDOWN% = 6
GLOBAL DIR_DOWN% = 4
GLOBAL DIR_LEFTDOWN% = 12
GLOBAL DIR_LEFT% = 8
GLOBAL DIR_LEFTUP% = 24
GLOBAL DIR_NONE% = 0
These are direction values wich we use for playersprite and shots.
Then we must define the variables:
GLOBAL Player AS TPlayer
GLOBAL Shot AS TShot
and then
GLOBAL ButtonB = TRUE
this provide us the state of button B or "x"-key.
In level00.gbas we initialise some of the new variables.
Player.PosX=8
Player.PosY=64
SPR_SHOT=18
// make player sprites
LOADSPRITE "./isdo/gfx/player.png",0
id=1
FOR x=0 TO 3
DRAWRECT 0,0,16,32,COL_TRANSPARENT
DRAWSPRITE 0,-x*16,0
GRABSPRITE id,0,0,16,32
INC id,1
NEXT
here we load graphicdatas for our hero. Nr.1+2 are animation-steps if the player flies straightforward. Nr.3+4 if he moves upright. You can expand this for the rest of directions, if you like.
// make shots
DRAWRECT 0,0,128,32,COL_TRANSPARENT
DRAWSPRITE 0,0,-64
GRABSPRITE 16,0,0,8,8
GRABSPRITE 17,8,0,8,8
GRABSPRITE 18,16,0,8,8
GRABSPRITE 19,24,0,8,8
GRABSPRITE 20,32,0,8,8
GRABSPRITE 24,16,16,16,16
With these lines we build sprites for the shots.
In the levelloop we must first set the state of button-B to TRUE.
ButtonB=TRUE
This is important, otherwise the following happens.
First we are in the startmenu. With button-B we confirm our choice. If the level starts and our button-B is still pressed, we shoot instantly.
Through setting on TRUE the program will wait until the release of button.
We increase the counter for spriteanimation.
INC Player.Timer,1
GOSUB ShotHANDLER
GOSUB PlayerHANDLER
With these two subprograms we manage the shots and the display of hero.
Now let's change to our library in library.gbas.
First we look in the code of PlayerHANDLER.
//=============================================================================
SUB PlayerHANDLER:
//=============================================================================
DRAWSPRITE SPR_PLAYER+(INTEGER((bAND(Player.Timer,3)/2))),Player.PosX,Player.PosY
ENDSUB // PlayerHANDLER
This is responsible for display the playersprite at the current position.
INTEGER((bAND(Player.Timer,3)/2))
gives back according to Player.Timer 0 or 1, wich corresponds to each animation-step. In our program we have only 2.
In the KeyHANDLER there are also a few changes.
First we must define some local variables
LOCAL kr%,kl%,kd%,ku%
They store if the corresponding direction is pressed or not. For this, first initialize.
kr=0;kl=0;kd=0;ku=0
Now we check if directions are pressed or not. If yes, we write the value in the local variable. Simultaneously we change the position of player-sprite.
IF KEY(BUTTON_RIGHT)
kr=2
INC Player.PosX,Player.Speed
ENDIF
IF KEY(BUTTON_LEFT)
kl=8
DEC Player.PosX,Player.Speed
ENDIF
IF KEY(BUTTON_DOWN)
kd=4
INC Player.PosY,Player.Speed
ENDIF
IF KEY(BUTTON_UP)
ku=16
DEC Player.PosY,Player.Speed
ENDIF
Afterwards we add the single variables to a bitmask. This means we have a binary string of "00000". If we press right-button the bitmask looks like "00010", if we press right-button+up-button "10010". That way it's possible to request multiple buttonstates. This mask we save in Player.Dir.
Player.Dir=kr+kl+kd+ku
Now to something unusual. SPR_PLAYER is per definition a constant spriteID. But here we use it as a variable, so by a change of direction we can change the basissprite for animation with just one command. As an example i've done it here for upright.
SPR_PLAYER=1
SELECT Player.Dir
CASE DIR_RIGHTUP
SPR_PLAYER=3
ENDSELECT
Now we teach our hero to shoot.
// player shoot
IF KEY(BUTTON_B)
IF ButtonB=FALSE
ButtonB=TRUE
GOSUB ShotADD
ENDIF
ELSE
ButtonB=FALSE
ENDIF
By pressing button-B we jump to routine ShootADD which adds a shot to our scene.
In this routine we first define a local counte variable and init with 0.
LOCAL ix%
ix=0
Then we run 8 times through a loop wich checks for every possible shot.
Loop1:
....
....
GOTO Loop1
ENDIF
We chek if the counter reaches the las shot.
IF ix=Shot.Count THEN RETURN
If yes, we add no other shot.
Thereafter we check if the current shot-entry is still in using.
IF Shot.State[ix]=0
Then we pass dhe direction-mask and startposition of the new shot.
Shot.Dir[ix]=Player.Dir
Shot.PosX[ix]=Player.PosX+8
Shot.PosY[ix]=Player.PosY+10
Shot.State[ix]=1
Shot.State is a state variable wich gives us the current step of the shot.
In ShootHANDLER we define some local variables and running in a loop all 8 shots again.
//=============================================================================
SUB ShotHANDLER:
//=============================================================================
LOCAL ix%,ev%,x%,y%
FOR ix=0 TO Shot.Count-1
IF Shot.State[ix]
....
....
ENDIF
NEXT
Now we calculate dthe actual shot-position in our eventmap and read out this value.
x=INTEGER(ScrollX+Shot.PosX[ix]) / 16
y=INTEGER(ScrollY+Shot.PosY[ix]-32) / 16
ev=Event.Map[x*16+y]
As we alredy know, the eventmap contain special attributes. Such an attribute can be a wall or a block at the same position in the LayerFG.Map. Practicaly this means, we end the shot as soon as there is a wall and don't let it fly through.
If the shot hit the wall we free the current shotentry.
IF ev>0 THEN Shot.State[ix]=0
.
According to the flightdirection we adjust the shotposition, draw the corresponding sprite and check if the shot reach screenborders.
CASE DIR_RIGHTUP
INC Shot.PosX[ix],2
DEC Shot.PosY[ix],2
DRAWSPRITE SPR_SHOT-1,Shot.PosX[ix],Shot.PosY[ix]
IF Shot.PosX[ix]>320
Shot.State[ix]=0
ENDIF
In the next part we will fight against enemies.
[attachment deleted by admin]