-- title: asteroids -- author: Bob Grant -- desc: -- script: lua -- game state control STATE_START = 0 STATE_PLAY = 10 STATE_END = 20 gameState = STATE_START SCREEN_MAX_X = 240 SCREEN_MAX_Y = 136 playerShip = { position = { x = 100, y = 60 }, velocity = { speed = 0, direction = 0 }, acceleration = 0.05, deceleration = 0.01, rotation = 0, rotationSpeed = 0.07, points = { {x=8,y=0, colour = 6}, {x=-8,y=6, colour = 6}, {x=-4,y=0, colour = 6}, {x=-8,y=-6, colour = 6}, {x=8,y=0, colour = 6} } } asteroids = {} NUM_ASTEROIDS = 10 ASTEROID_NUM_POINTS = 10 ASTEROID_RAD = 15 ASTEROID_RAD_PLUS = 4 ASTEROID_RAD_MINUS = 6 ASTEROID_MAX_VEL = 0.5 ASTEROID_MIN_VEL = 0.1 ASTEROID_MAX_ROT = 0.03 function TIC() if gameState == STATE_START then doStartScreen() elseif gameState == STATE_PLAY then doPlayGame() elseif gameState == STATE_END then doEndScreen() end end function doStartScreen() cls() print ("ASTEROIDS", 80,40) print ("press Z to start", 60,60) if btnp(4) then initGame() end end -- doStartScreen() function doEndScreen() cls() print ("GAME OVER", 80,40) print ("press Z to start", 60,60) if btnp(4) then gameState = STATE_PLAY end end -- doEndScreen() function doPlayGame() cls() -- update checkPlayerButtons() movePlayerShip() moveAsteroids() -- draw drawVectorShape(playerShip) drawAsteroids() if btnp(4) then gameState = STATE_END end end -- doPlayGame() function initGame() gameState = STATE_PLAY generateAsteroids() end -- initGame function drawVectorShape(shape) local firstPoint = true local lastPoint = 0 local rotatedPoint = 0 for index, point in ipairs(shape.points) do rotatedPoint = rotatePoint(point,shape.rotation) if firstPoint then lastPoint = rotatedPoint firstPoint = false else line(lastPoint.x + shape.position.x, lastPoint.y + shape.position.y, rotatedPoint.x + shape.position.x, rotatedPoint.y + shape.position.y, point.colour) lastPoint = rotatedPoint end end -- for end -- drawVectorShape function rotatePoint(point, rotation) local rotatedX = (point.x * math.cos(rotation)) - (point.y * math.sin(rotation)) local rotatedY = (point.y * math.cos(rotation)) + (point.x * math.sin(rotation)) return {x=rotatedX, y=rotatedY} end -- rotatePoint function checkPlayerButtons() if btn(2) then -- left playerShip.rotation = playerShip.rotation - playerShip.rotationSpeed end if btn(3) then -- right playerShip.rotation = playerShip.rotation + playerShip.rotationSpeed end playerShip.rotation = keepAngleInRange(playerShip.rotation) end -- checkPlayerButtons function keepAngleInRange(angle) if angle < 0 then while angle < 0 do angle = angle + (2 * math.pi) end end if angle > (2 * math.pi) then while angle > (2 * math.pi) do angle = angle - (2 * math.pi) end end return angle end -- keepAngleInRange function movePointByVelocity(object) components = getVectorComponents(object.velocity) local newPosition = { x = object.position.x + components.xComp, y = object.position.y + components.yComp } return newPosition end -- movePointByVelocity function movePlayerShip() -- thrust if btn(0) then -- up key playerShipThrust() end -- if playerShip.velocity.speed = playerShip.velocity.speed - playerShip.deceleration if playerShip.velocity.speed < 0 then playerShip.velocity.speed = 0 end playerShip.position = movePointByVelocity(playerShip) playerShip.position = wrapPosition(playerShip.position) end -- movePlayerShip function playerShipThrust() local acceleration = { speed = playerShip.acceleration, direction = playerShip.rotation } playerShip.velocity = addVectors(playerShip.velocity, acceleration) end -- playerShipThrust function addVectors(vector1, vector2) v1Comp = getVectorComponents(vector1) v2Comp = getVectorComponents(vector2) resultantX = v1Comp.xComp + v2Comp.xComp resultantY = v1Comp.yComp + v2Comp.yComp local resVector = compToVector(resultantX, resultantY) return resVector end -- addVectors function getVectorComponents(vector) local xComp = vector.speed * math.cos(vector.direction) local yComp = vector.speed * math.sin(vector.direction) local components = { xComp = xComp, yComp = yComp } return components end -- getVectorComponents function compToVector(x, y) local magnitude = math.sqrt( (x * x) + (y * y)) local direction = math.atan2(y, x) direction = keepAngleInRange(direction) local vector = { speed = magnitude, direction = direction } return vector end -- compToVector function wrapPosition(position) if (position.x >= SCREEN_MAX_X) then position.x = 0 elseif (position.x < 0) then position.x = SCREEN_MAX_X - 1 end if (position.y >= SCREEN_MAX_Y) then position.y = 0 elseif (position.y < 0) then position.y = SCREEN_MAX_Y - 1 end return position end -- wrapPosition function spawnAsteroid() local asteroid = { position = { x = 0, y = 0 }, velocity = { speed = 0, direction = 0 }, acceleration = 0.05, deceleration = 0.01, rotation = 0, rotationSpeed = 0.07, points = {} } -- generate points -- first point at default radius table.insert(asteroid.points, { x = ASTEROID_RAD, y = 0, colour = 15 } ) local angle = 0 local radius = 0 local vector = {} for point=1, (ASTEROID_NUM_POINTS - 1) do -- create a random radius radius = math.random( ASTEROID_RAD - ASTEROID_RAD_MINUS, ASTEROID_RAD + ASTEROID_RAD_PLUS ) -- angles are evenly spaced angle = ((math.pi * 2) / ASTEROID_NUM_POINTS) * point vector = { speed = radius, direction = angle } components = getVectorComponents(vector) table.insert(asteroid.points, { x = components.xComp, y = components.yComp, colour = 15 } ) end -- for -- last point same as first table.insert(asteroid.points, { x = ASTEROID_RAD, y = 0, colour = 15 } ) return asteroid end -- spawnAsteroid function generateAsteroids() local asteroid for count = 1,NUM_ASTEROIDS do asteroid = spawnAsteroid() asteroid.velocity = { speed = (math.random() * (ASTEROID_MAX_VEL - ASTEROID_MIN_VEL)) + ASTEROID_MIN_VEL, direction = math.random() * math.pi * 2 } asteroid.rotationSpeed = (math.random() * (2 * ASTEROID_MAX_ROT)) - ASTEROID_MAX_ROT if math.random(1,2) == 1 then -- start at top of screen asteroid.position = { x = math.random(0,(SCREEN_MAX_X - 1)), y = 0 } else -- start at left of screen asteroid.position = { x = 0, y = math.random(0,(SCREEN_MAX_Y - 1)) } end -- if table.insert(asteroids, asteroid) end -- for end -- generateAsteroids function drawAsteroids() for index, asteroid in ipairs(asteroids) do drawVectorShape(asteroid) end -- for end -- drawAsteroids function moveAsteroids() for index, asteroid in ipairs(asteroids) do asteroid.rotation = asteroid.rotation + asteroid.rotationSpeed asteroid.position = movePointByVelocity(asteroid) asteroid.position = wrapPosition(asteroid.position) end -- for end -- moveAsteroids