Types in action

To give you an idea how of types can be used a program has been made that creates a space ship, that flies left and right, firing lasers at set intervals.

image-1

This program relies on some external media. The easiest way of running this program is to click here and download the project. Once the file has been downloaded, extract the files and open MyFirstAGKProject.agk within AppGameKit.

There's a lot to take in with this program, as it's using types and a number of functions. Try running the program first and watch it for several seconds to see what happens.

The program moves the space ship left and right whilst continually firing lasers. The kind of data we need to store includes the speed of the ship, which direction the ship is moving in, how often the ship should fire, the speed at which the lasers move etc. All of this data could be declared as individual variables. For example, the ship's data might look like this.

sprite as integer
speed as integer
direction as integer
fireTimer as float

laserSprite as integer [ 10 ] laserSpeed as float [ 10 ] laserState as integer [ 10 ]

This approach does work, but it's not necessarily the best way of storing the data. Think about what might happen if you needed more data for the laser - you would need to declare another array to store it. The problem is that all this data is connected to each other, but stored in lots of different arrays. It's not an ideal method to deal with your data.

Given the relationship between the data it would make sense to utilise types. The laser that gets fired could be considered as one type, while the ship could be considered as another type that contains an array of lasers. The above code could be rewritten as.

type laserType
	sprite as integer
	speed as float
	state as integer
endtype

type shipType sprite as integer speed as integer direction as integer fireTimer as float lasers as laserType [ 10 ] endtype

This results in more effective way of dealing with our data. To declare one ship we simply do this.

spaceShip as shipType

If we needed multiple ships it's just a case of changing the declaration to an array.

spaceShip as shipType [ 5 ]

By taking this approach everything we need is now contained within the variable spaceShip. This makes our code much easier to read and manage.

Now let's take a look at the whole program.


// create a space ship on screen that flies left and right // and also fires lasers
// declare a type to store data for our lasers type laserType sprite as integer speed as float state as integer endtype
// declare a type to store data for our ship type shipType sprite as integer speed as integer direction as integer fireTimer as float lasers as laserType [ 10 ] endtype
// variable for our ship, make it global so it can be // easily accessed by all parts of the program global spaceShip as shipType
// set a virtual resolution of 1024 x 768 SetVirtualResolution ( 1024, 768 )
// call functions to set up the ship and its lasers SetupShip ( ) SetupLasers ( )
// our main loop do // call functions to update the ship and its lasers UpdateShip ( ) UpdateLasers ( )
// update the screen sync ( ) loop
function SetupLasers ( )
// this function will set up the lasers
// load an image for the laser image = LoadImage ( "laser.png" )
// create sprites for each laser for i = 1 to spaceShip.lasers.length spaceShip.lasers [ i ].sprite = CreateSprite ( image ) ResetLaser ( i, 0 ) next i
endfunction
function ResetLaser ( index as integer, visible as integer )
// this function will reset the lasers, giving them default values
// state, speed, position to match the ship and visibility spaceShip.lasers [ index ].state = 0 spaceShip.lasers [ index ].speed = Random ( 80, 100 ) / 10.0 SetSpritePosition ( spaceShip.lasers [ index ].sprite, GetSpriteX ( spaceShip.sprite ) + GetSpriteWidth ( spaceShip.sprite ) / 2 - 8 , GetSpriteY ( spaceShip.sprite ) - 12 ) SetSpriteVisible ( spaceShip.lasers [ index ].sprite, visible )
endfunction
function UpdateLasers ( )
// this function updates the lasers
// increment the timer to control when the lasers should fire spaceShip.fireTimer = spaceShip.fireTimer + 0.01
// run through all the lasers for i = 1 to spaceShip.lasers.length
// if the state is 0 then this laser is available if spaceShip.lasers [ i ].state = 0
// only fire the laser if the fire timer is over 0.25 if spaceShip.fireTimer >= 0.25
// reset the laser, set the state to 1 and reset the timer ResetLaser ( i, 1 ) spaceShip.lasers [ i ].state = 1 spaceShip.fireTimer = 0.0
endif
endif
// when the state is 1 the laser has been fired if spaceShip.lasers [ i ].state = 1
// move the laser up the screen SetSpritePosition ( spaceShip.lasers [ i ].sprite, GetSpriteX ( spaceShip.lasers [ i ].sprite ), GetSpriteY ( spaceShip.lasers [ i ].sprite ) - spaceShip.lasers [ i ].speed )
// check for the laser leaving the screen if GetSpriteY ( spaceShip.lasers [ i ].sprite ) < 0
// reset the laser and allow it to be used again ResetLaser ( i, 0 )
endif endif next i
endfunction
function SetupShip ( )
// set up for our ship
// create a sprite, control how fast it moves and set its initial direction spaceShip.sprite = CreateSprite ( LoadImage ( "TopFighter1.png" ) ) spaceShip.speed = 2 spaceShip.direction = 0
// position the sprite towards the centre and near the bottom of the screen SetSpritePosition ( spaceShip.sprite, 1024 / 2, 626 )
endfunction
function UpdateShip ( )
// control the movement of the ship
// get the X coordinate of the ship x = GetSpriteX ( spaceShip.sprite )
// find out whether it has moved to the left or right side if ( spaceShip.direction = 0 and x > 976 ) or ( spaceShip.direction = 1 and x < 0 )
// reverse the speed and direction spaceShip.speed = -spaceShip.speed spaceShip.direction = not spaceShip.direction
endif
// add the current speed to the X position x = x + spaceShip.speed
// update the position of our ship SetSpritePosition ( spaceShip.sprite, x, GetSpriteY ( spaceShip.sprite ) )
endfunction

The program begins by declaring our types. laserType contains data for the lasers and shipType contains data about the ship, including an array of 10 lasers.

type laserType
	sprite as integer
	speed as float
	state as integer
endtype

type shipType sprite as integer speed as integer direction as integer fireTimer as float lasers as laserType [ 10 ] endtype

A variable is declared named spaceShip using the type shipType. It has global prefixed to the declaration so that it will be accessible throughout the whole program, as later on some of the functions require access to it. It is possible to pass in types as parameters to functions, but for now declaring the variable as global will do.

global spaceShip as shipType

The next part contains two calls to functions.

SetupShip ( )
SetupLasers ( )

Let's take a look at what the function SetupShip does.

function SetupShip ( )
	spaceShip.sprite = CreateSprite ( LoadImage ( "TopFighter1.png" ) )
	spaceShip.speed = 2
	spaceShip.direction = 0
	
SetSpritePosition ( spaceShip.sprite, 1024 / 2, 626 ) endfunction

The function creates a sprite using the image "TopFighter1.png" and stores the sprite ID within the sprite variable, that is part of the spaceShip variable. It also assigns a value of 2 to the speed part of spaceShip. This is later used to determine how fast the ship moves across the screen. A lower value will make the ship move slower, whereas a higher value will make it move quickly. This is followed by the direction part of spaceShip getting assigned 0. This variable controls the direction in which the ship moves. If direction is 0 then the ship moves from left to right. If direction is 1 then the ship moves from right to left. The final call is used to position the newly created sprite towards the centre and bottom of the screen.

After SetupShip has finished its work a call is made to SetupLasers. This function is responsible for creating 10 lasers that the ship will fire. Let's see the code.

function SetupLasers ( )
	
image = LoadImage ( "laser.png" )
for i = 1 to spaceShip.lasers.length spaceShip.lasers [ i ].sprite = CreateSprite ( image ) ResetLaser ( i, 0 ) next i endfunction

It begins by loading an image named "laser.png" and storing its ID within the variable image. This is followed by a loop that will cycle from 1 to the size or length of the lasers array (10) contained within the spaceShip variable. For each iteration of the loop a sprite is created, with its identifier stored in the lasers array. This will give us 10 separate laser sprites that can be used by the ship. It's finished off with a call to ResetLaser.

function ResetLaser ( index as integer, visible as integer )
	spaceShip.lasers [ index ].state = 0
	spaceShip.lasers [ index ].speed = Random ( 80, 100 ) / 10.0
	SetSpritePosition ( spaceShip.lasers [ index ].sprite, GetSpriteX ( spaceShip.sprite ) + GetSpriteWidth ( spaceShip.sprite ) / 2 - 8 , GetSpriteY ( spaceShip.sprite ) - 12 )
	SetSpriteVisible ( spaceShip.lasers [ index ].sprite, visible )
endfunction

The ResetLaser function is used to apply default values to the lasers. It takes in two parameters letting us specify the laser to modify with the index, and the visibility of the sprite using visible. SetupLasers calls this function to modify all 10 lasers that get created and sets visible to 0. The actual function sets the state of each laser to 0 (the state determines whether it's available to be fired), gives it a random speed, sets its position to match that of the space ship and finally sets the sprite to be visible or invisible.

The next part of the program is the main loop.

do
	UpdateShip ( )
	UpdateLasers ( )
	
sync ( ) loop

It calls the functions UpdateShip and UpdateLasers.

Here's the UpdateShip function.

function UpdateShip ( )
	x = GetSpriteX ( spaceShip.sprite )
	
if ( spaceShip.direction = 0 and x > 976 ) or ( spaceShip.direction = 1 and x < 0 ) spaceShip.speed = -spaceShip.speed spaceShip.direction = not spaceShip.direction endif
x = x + spaceShip.speed
SetSpritePosition ( spaceShip.sprite, x, GetSpriteY ( spaceShip.sprite ) ) endfunction

The function performs a few simple operations. It gets the X position of the space ship sprite. It then checks whether the ship is moving left or right and if it has left the boundaries of the screen. If this condition is met the ship is set to move in the opposite direction. Finally the position of the ship is updated using the modified X value.

The UpdateLasers function cycles through all 10 lasers and will launch one every so often.

function UpdateLasers ( )
	spaceShip.fireTimer = spaceShip.fireTimer + 0.01
	
for i = 1 to spaceShip.lasers.length if spaceShip.lasers [ i ].state = 0 if spaceShip.fireTimer >= 0.25
ResetLaser ( i, 1 ) spaceShip.lasers [ i ].state = 1 spaceShip.fireTimer = 0.0 endif endif
if spaceShip.lasers [ i ].state = 1 SetSpritePosition ( spaceShip.lasers [ i ].sprite, GetSpriteX ( spaceShip.lasers [ i ].sprite ), GetSpriteY ( spaceShip.lasers [ i ].sprite ) - spaceShip.lasers [ i ].speed )
if GetSpriteY ( spaceShip.lasers [ i ].sprite ) < 0 ResetLaser ( i, 0 ) endif endif next i endfunction

The function performs the following tasks.

Overall it's quite a simple program but it does demonstrate how effective types can be when grouping data together.