-- title: Space Invaders
-- author: Bob Grant
-- desc: Lesson 19
-- script: lua
playerShip = {
position = {
x = 120,
y = 128
},
spriteNum = 0,
minX = 0,
maxX = 232,
speed = 1,
bulletOffset = {
x = 4,
y = 4
}
}
playerBullets = {}
maxPlayerBullets = 5
aliens = {}
alienRows = 6
alienColumns = 8
alienHorzSpacing = 12
alienVertSpacing = 12
alienDirection = 1
alienSpeed = 4
alienVertSpeed = 4
alienMaxX = 232
alienMinX = 0
alienMoveDelay = 30
alienMoveCounter = alienMoveDelay
alienMoveNumFrames = 2
alienMoveFrameCounter = 0
alienRowTypes = {}
alienRowTypes[1] = {baseSprite = 16}
alienRowTypes[2] = {baseSprite = 16}
alienRowTypes[3] = {baseSprite = 32}
alienRowTypes[4] = {baseSprite = 32}
alienRowTypes[5] = {baseSprite = 48}
alienRowTypes[6] = {baseSprite = 48}
explosions = {}
gameNeedsToBeInitialised = true
function TIC()
-- game initialisation
-- check if game needs to be initialised
if (gameNeedsToBeInitialised) then
initialiseGame()
gameNeedsToBeInitialised = false
end
-- updating
movePlayerShip()
checkPlayerFire()
movePlayerBullet()
moveAliens()
checkBulletCollisions()
-- drawing / rendering
cls()
drawPlayerBullet()
drawPlayerShip()
drawAliens()
drawExplosions()
end -- end TIC
function movePlayerShip()
-- check move right button
if(btn(2)) then
playerShip.position.x =
playerShip.position.x - playerShip.speed
end
-- check move left button
if(btn(3)) then
playerShip.position.x =
playerShip.position.x + playerShip.speed
end
playerShip.position.x = checkLimits(
playerShip.position.x,
playerShip.minX,
playerShip.maxX )
end -- movePlayerShip
function checkLimits(value, min, max)
if (value > max) then
value = max
elseif (value < min) then
value = min
else
value = value
end
return value
end -- checkLimits
function checkPlayerFire()
local bulletFired = false
local bullet = 1
-- if fire button is pressed then
if (btnp(4)) then
-- find a bullet that's ready to fire
while (bullet <= maxPlayerBullets) and (not bulletFired) do
if (not playerBullets[bullet].active) then
-- initialise bullet
playerBullets[bullet].position = {
x = playerShip.position.x + playerShip.bulletOffset.x,
y = playerShip.position.y + playerShip.bulletOffset.y
}
-- mark bullet as active
playerBullets[bullet].active = true
-- stop other bullets from firing
bulletFired = true
end -- if not active
bullet = bullet + 1
end -- while
end -- if button pressed
end -- checkPlayerFire
function movePlayerBullet()
for bullet = 1, maxPlayerBullets do
if (playerBullets[bullet].active) then
-- move the bullet up the screen
playerBullets[bullet].position.y =
playerBullets[bullet].position.y - playerBullets[bullet].speed
if (playerBullets[bullet].position.y < 0) then
playerBullets[bullet].active = false
end
end
end
end -- movePlayerBullet
function drawPlayerBullet()
for bullet = 1, maxPlayerBullets do
if (playerBullets[bullet].active) then
-- draw player bullet
-- line(startX, StartY, endX, endY, colour)
line(
playerBullets[bullet].position.x,
playerBullets[bullet].position.y,
playerBullets[bullet].position.x,
playerBullets[bullet].position.y + playerBullets[bullet].length,
playerBullets[bullet].colour
)
end -- if
end -- for
end -- drawPlayerBullet
function drawPlayerShip()
spr(playerShip.spriteNum,
playerShip.position.x,
playerShip.position.y, 0)
end -- drawPlayerShip
function initialiseGame()
initPlayerBulletsArray()
initAliens()
end -- initialiseGame
function initPlayerBulletsArray()
for bullet = 1, maxPlayerBullets do
playerBullets[bullet] = {
position = {
x = 0,
y = 0
},
height = 5,
width = 1,
length = 5,
colour = 14,
speed = 2,
active = false
}
end -- for
end -- initPlayerBulletsArray
function initAliens()
-- create alien grid
for row = 1, alienRows do
-- create row of aliens
aliens[row] = {}
for column = 1,alienColumns do
-- create alien
aliens[row][column] = {
position = {
x = (column - 1) * alienHorzSpacing,
y = (row - 1) * alienVertSpacing
},
height = 8,
width = 8,
alive = true,
alienBaseSprite =
alienRowTypes[row].baseSprite
}
-- end row
end
-- end alien grid
end
end -- initAliens
function drawAliens()
for row = 1, alienRows do
for column = 1, alienColumns do
if (aliens[row][column].alive) then
spr(aliens[row][column].alienBaseSprite
+ alienMoveFrameCounter,
aliens[row][column].position.x,
aliens[row][column].position.y)
end -- if
end -- columns
end -- rows
end -- drawAliens
function moveAliens()
alienMoveCounter = alienMoveCounter - 1
if (alienMoveCounter <= 0) then
-- alienMoveNumFrames = 2
-- alienMoveFrameCounter = 0
alienMoveFrameCounter =
alienMoveFrameCounter + 1
alienMoveFrameCounter =
alienMoveFrameCounter % alienMoveNumFrames
if aliensAtEdge() then
-- move down
for row = 1, alienRows do
for column = 1, alienColumns do
if (aliens[row][column].alive) then
aliens[row][column].position.y =
aliens[row][column].position.y +
(alienVertSpeed)
end -- if
end -- columns
end -- rows
alienDirection = -alienDirection
else
for row = 1, alienRows do
for column = 1, alienColumns do
if (aliens[row][column].alive) then
aliens[row][column].position.x =
aliens[row][column].position.x +
(alienSpeed * alienDirection)
end -- if
end -- columns
end -- rows
end -- if
alienMoveCounter = alienMoveDelay
end -- if alienMoveCounter
end -- moveAliens
function aliensAtEdge()
-- for each alien
for row = 1, alienRows do
for column = 1, alienColumns do
-- if alien is alive then
if (aliens[row][column].alive) then
-- if alien going right +1
if (alienDirection == 1) then
-- if alien x + step > MaxX then
if (aliens[row][column].position.x + alienSpeed) >
alienMaxX then
-- return true
return true
-- end if
end
-- else going left -1
else
if (aliens[row][column].position.x - alienSpeed) <
alienMinX then
-- return true
return true
-- end if
end
-- end if - going left right
end
-- end if alive
end
end -- for columns
end -- for rows
-- end for
-- return false
return false
end -- aliensAtEdge
function checkCollision(object1, object2)
-- object.position position.x posiition.y
-- object.width
-- object.height
local object1Left = object1.position.x
local object1Right = object1.position.x
+ object1.width -1
local object1Top = object1.position.y
local object1Bottom = object1.position.y
+ object1.height - 1
local object2Left = object2.position.x
local object2Right = object2.position.x
+ object2.width -1
local object2Top = object2.position.y
local object2Bottom = object2.position.y
+ object2.height - 1
if (object1Left < object2Right) and
(object1Right > object2Left) and
(object1Top < object2Bottom) and
(object1Bottom > object2Top) then
return true
else
return false
end
end -- checkCollision
function checkBulletCollisions()
local bulletHasHitAlien = false
for bullet = 1, maxPlayerBullets do
if (playerBullets[bullet].active) then
for row = 1, alienRows do
for column = 1, alienColumns do
if (aliens[row][column].alive) then
bulletHasHitAlien = checkCollision(
playerBullets[bullet],
aliens[row][column]
)
if (bulletHasHitAlien) then
-- hit
aliens[row][column].alive = false
playerBullets[bullet].active = false
alienExplosion(aliens[row][column].position)
end -- if
end -- if alien alive
end -- for column
end -- for row
end -- if bullet active
end -- for bullet
end -- checkBulletCollisions
function alienExplosion(exPosition)
local explosion = {
position = exPosition,
ticCounter = 0,
totalTics = 30,
baseSprite = 64,
numFrames = 4
}
table.insert(explosions, explosion) -- add explosion into the array
end -- function alienExplosion
function drawExplosions()
local spriteNumber
for index, explosion in ipairs(explosions) do
spriteNumber = (explosion.ticCounter % explosion.numFrames)
+ explosion.baseSprite
spr(spriteNumber, explosion.position.x, explosion.position.y)
explosion.ticCounter = explosion.ticCounter + 1
if (explosion.ticCounter > explosion.totalTics) then
table.remove(explosions, index)
end --if
end -- for
end -- drawExplosions