Skip to content

Instantly share code, notes, and snippets.

@shawndumas
Created May 21, 2012 12:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shawndumas/2762088 to your computer and use it in GitHub Desktop.
Save shawndumas/2762088 to your computer and use it in GitHub Desktop.
Codea Game: StarFighter
--# HeroAttack
HeroAttack = class()
function HeroAttack:init(hero)
self.duration = 0.5
self.currentTime = 0
self.endTime = self.currentTime + self.duration
self.hero = hero
self.size = hero.size
self.blastSize = self.size * ((self.hero.energy / 25) + 1)
self.currentSize = self.size
end
function HeroAttack:draw()
self.currentTime = self.currentTime + 1 / 30
local attackTime = self.currentTime / self.duration
pushStyle()
noFill()
stroke(255, 0, 0, 255 * (1 - attackTime))
strokeWidth(10 * (1 - attackTime))
self.currentSize = self.blastSize * attackTime + (self.size * (1 - attackTime))
ellipse(self.hero.pos.x, self.hero.pos.y, self.currentSize)
popStyle()
end
function HeroAttack:isDone()
return self.currentTime > self.endTime * 2
end
--# PowerUp
PowerUp = class()
function PowerUp:init(type)
self.type = type or "shield"
self.size = 50
self.pos = vec2(math.random(35, WIDTH - 35), HEIGHT)
self.pos.y = self.pos.y + self.size
self.cull = false
end
function PowerUp:update(hero)
local y = nil
local x = nil
local size = nil
if self.type == "energy" then
y = math.random(0, 4)
x = math.random(-35, 35)
size = math.random(5, 50)
elseif self.type == "shield" then
y = math.random(-5, 10)
x = math.random(-4, 4)
size = math.random(10, 100)
elseif self.type == "fire" then
y = math.random(-15, 30)
x = math.random(-35, 35)
size = math.random(50, 150)
end
self:shouldCull()
self.pos.y = self.pos.y - y
self.pos.x = self.pos.x + x
self.size = size
if hero and self.pos:dist(hero.pos) < hero.size then
if self.type == "energy" then
hero.energy = hero.energy + 25
sound(SOUND_POWERUP, 23401)
elseif self.type == "shield" then
hero.shields = hero.shields + 25
sound(SOUND_POWERUP, 23414)
elseif self.type == "fire" then
hero.fire = hero.fire + 2
sound(SOUND_POWERUP, 23418)
end
self.cull = true
end
end
function PowerUp:draw()
pushMatrix()
pushStyle()
if self.type == "energy" then
tint(255, 0, 0, 255)
elseif self.type == "fire" then
tint(255, 110, 0, 255)
elseif self.type == "shield" then
noTint()
end
sprite("Tyrian Remastered:Energy Orb 1", self.pos.x, self.pos.y, self.size)
popStyle()
popMatrix()
end
function PowerUp:shouldCull()
if (self.pos.y + self.size) < 0 then self.cull = true end
self.cull = false
end
--# Rocks
Rock = class()
function Rock:init()
self.size = 60
self.pos = vec2(math.random(WIDTH), HEIGHT)
self.pos.y = self.pos.y + self.size
self.spriteName = "Tyrian Remastered:Rock " .. math.random(3, 5)
self.onFire = false
self.cull = false
self.hit = false
end
function Rock:update(spd)
self.pos.y = self.pos.y - spd
self:shouldCull()
end
function Rock:draw()
local spriteNames = {
"Tyrian Remastered:Fire Rock",
"Tyrian Remastered:Firestroid"
}
if self.onFire then self.spriteName = spriteNames[math.random(2)] end
pushMatrix()
sprite(self.spriteName, self.pos.x, self.pos.y, self.size)
popMatrix()
end
function Rock:shouldCull()
if (self.pos.y + self.size) < 0 then self.cull = true end
self.cull = false
end
Rocks = class()
function Rocks:init()
self.frame = 0
self.rocks = {}
self.explosions = {}
end
function Rocks:draw(speed, hero)
self.frame = (self.frame + 1) % 128
if self.frame % 40 == 0 then table.insert(self.rocks, Rock()) end
local function explodeRock (rk)
rk.cull = true
table.insert(self.explosions, Explosion(rk.pos))
end
if hero then
for i, v in ipairs(self.rocks) do
if v.pos:dist(hero.pos) < hero.size and not v.cull then
explodeRock(v)
end
end
for i, v in ipairs(self.rocks) do
for j, fbPos in ipairs(hero.fireballs) do
if v.pos:dist(fbPos) < 25 and not v.cull then
table.remove(hero.fireballs, j)
sound(SOUND_EXPLODE, 45815)
if v.onFire then
explodeRock(v)
else
v.onFire = true
end
end
end
end
end
for i, v in ipairs(self.rocks) do
if not v.cull then
v:update(speed)
v:draw()
end
end
for i, e in ipairs(self.explosions) do
e:draw()
if e:isDone() then table.remove(self.explosions, i) end
end
end
--# Explosion
Explosion = class()
function Explosion:init(pos)
self.pos = pos
self.opacity = 255
self.time = 0
self.lines = {}
sound(SOUND_EXPLODE, 969)
for i = 1, 20 do
dir = vec2(0,1)
dir = dir:rotate(math.rad(math.random(360)))
table.insert(self.lines, (dir * math.random(2, 7)))
end
end
function Explosion:isDone()
return (self.opacity <= 0)
end
function Explosion:draw()
self.time = (self.time + 3)
pushStyle()
lineCapMode(ROUND)
strokeWidth(6)
smooth()
stroke(255, 255, 255, math.max(self.opacity, 0))
p = self.pos
for i, v in ipairs(self.lines) do
vt = (p + v * self.time)
line(p.x, p.y, vt.x, vt.y)
end
self.opacity = (255 * (1 - (self.time / 50)))
popStyle()
end
--# Main
cfg = {
maxSpeed = 75,
delayMin = 10,
newShield = 500,
newEnergy = 1000,
newFire = 1500,
heroSize = 75
}
gbl = {}
function setup()
displayMode(FULLSCREEN)
supportedOrientations(LANDSCAPE_RIGHT)
gbl = {
stars = StarField(),
hero = Hero(180, cfg.heroSize),
rks = Rocks(),
frame = 0,
speed = 15,
playing = true,
score = 0,
level = 1
}
end
function levelUp()
gbl.level = gbl.level + 1
gbl.speed = gbl.speed + 5
if gbl.playing then gbl.score = gbl.score + 789 end
if gbl.speed > cfg.maxSpeed then gbl.speed = cfg.maxSpeed end
end
function draw()
background(0, 0, 0, 255)
gbl.frame = gbl.frame + 1
if (gbl.frame % cfg.newShield) == 0 then
if (not gbl.hero or gbl.hero.shields < 100) then
gbl.powerUp = PowerUp("shield")
end
end
if (gbl.frame % cfg.newEnergy) == 0 then
if gbl.playing then levelUp() end
if (not gbl.hero or gbl.hero.energy < 100) then
gbl.powerUp = PowerUp("energy")
end
end
if (gbl.frame % cfg.newFire) == 0 then
if (not gbl.hero or gbl.hero.fire == 0) then
gbl.powerUp = PowerUp("fire")
end
end
if gbl.powerUp then
gbl.powerUp:update(gbl.hero)
if not gbl.powerUp.cull then
gbl.powerUp:draw()
else
gbl.powerUp = nil
end
end
gbl.stars:update(gbl.speed)
gbl.stars:draw()
fontSize(30)
textMode(CORNER)
local shields = 0
local energy = 0
local fire = 0
if gbl.playing then
shields = gbl.hero.shields
energy = gbl.hero.energy
fire = gbl.hero.fire
gbl.rks:draw(gbl.speed, gbl.hero)
else
gbl.rks:draw(gbl.speed, false)
end
text("Level: " .. gbl.level, 10, HEIGHT - 50)
text("Score: " .. gbl.score, 10, HEIGHT - 100)
local at = "Shields: " .. shields .. "%"
local atWidth = textSize(at)
text(at, WIDTH - atWidth - 10, HEIGHT - 50)
local at = "Energy: " .. energy .. "%"
local atWidth = textSize(at)
text(at, WIDTH - atWidth - 10, HEIGHT - 100)
if energy > 0 then
pushStyle()
strokeWidth(1)
fill(255, 0, 0, 100)
ellipse(80, 100, 90, 90)
popStyle()
text(gbl.hero.energy / 25, 72, 82)
end
if fire > 0 then
pushStyle()
strokeWidth(1)
fill(255, 110, 0, 100)
ellipse(WIDTH - 80, 100, 90, 90)
popStyle()
text(gbl.hero.fire, WIDTH - 88, 82)
end
if gbl.playing then
gbl.score = gbl.score + math.floor(gbl.speed * .1)
gbl.hero:update()
gbl.hero:draw()
for i, v in ipairs(gbl.rks.rocks) do
if not v.hit and v.pos:dist(gbl.hero.pos) < gbl.hero.size then
if gbl.hero.attack and not gbl.hero.attack:isDone() then
else
local function boom ()
gbl.hero.boom = Explosion(gbl.hero.pos)
sound(SOUND_EXPLODE, 969)
gbl.playing = false
end
if gbl.hero.shields ~= 0 then
local dmg = 25
if v.onFire then dmg = 50 end
local shields = gbl.hero.shields - dmg
if shields > 0 then
gbl.hero.shields = shields
else
gbl.hero.shields = 0
boom()
end
v.hit = true
else
boom()
end
end
if v.cull then table.remove(gbl.rks.rocks, i) end
end
end
else
fontSize(60)
textMode(CENTER)
text("GAME OVER", WIDTH/2, HEIGHT/2)
fontSize(40)
text("Tap screen to restart.", WIDTH/2, (HEIGHT/2 - 80))
if gbl.speed > 5 then gbl.speed = gbl.speed - 1 end
gbl.hero = nil
end
end
function touched(touch)
if CurrentTouch.state == BEGAN then
if not gbl.playing then
setup()
else
gbl.hero:touched(touch)
end
end
end
--# Hero
Hero = class()
function Hero:init(rotDeg, size)
self.fromTop = 700
self.rotDeg = rotDeg
self.shields = 100
self.energy = 100
self.fire = 9
self.size = size
self.attack = nil
self.boom = nil
self.pos = nil
self.fireballs = {}
end
function Hero:spawnFireball()
if self.fire > 0 and #self.fireballs < 2 then
sound(SOUND_EXPLODE, 18)
table.insert(self.fireballs, vec2(self.pos.x, self.pos.y + 30))
self.fire = self.fire - 1
end
end
function Hero:drawFireballs()
pushStyle()
for i, v in ipairs(self.fireballs) do
v.y = v.y + 10
tint(255, 255, 255, 175)
sprite("Tyrian Remastered:Bullet Fire C", v.x, v.y, 25)
if v.y > (HEIGHT + 10) then
table.remove(self.fireballs, i)
end
end
popStyle()
end
function Hero:update()
local x = ((Gravity.x * self.fromTop) + (WIDTH / 2))
local y = ((Gravity.y * self.fromTop) + HEIGHT)
self.pos = vec2(x, y)
end
function Hero:draw()
self:drawFireballs()
pushMatrix()
pushStyle()
translate(self.pos.x, self.pos.y)
rotate(self.rotDeg)
if self.shields > 0 then
sprite("Tyrian Remastered:Plane Boss")
pushMatrix()
pushStyle()
fill(50, 50, 100, self.shields)
stroke(50, 50, 200, 150 + self.shields)
strokeWidth(0.1)
translate(-self.pos.x, -self.pos.y)
ellipse(self.pos.x, self.pos.y - 10, 111)
popStyle()
popMatrix()
else
tint(255, 150, 150, 255)
sprite("Tyrian Remastered:Plane Boss Destroyed")
end
popStyle()
popMatrix()
pushMatrix()
pushStyle()
translate(self.pos.x, self.pos.y - 117)
scale(.19, .59)
rotate(180)
tint(255, 150, 150, math.random(100, 255))
sprite("Small World:Beam")
popStyle()
popMatrix()
if self.attack then
self.attack:draw()
if self.attack:isDone() then self.attack = nil end
end
if self.boom then
self.boom:draw()
if self.boom:isDone() then self.boom = nil end
end
end
function Hero:energyAttack()
if self.attack == nil then
sound(SOUND_RANDOM, 156)
self.attack = HeroAttack(self)
self.energy = self.energy - 25
end
end
function Hero:touched(touch)
local isFire = touch.x > WIDTH / 2
if isFire then
self:spawnFireball()
else
if self.energy ~= 0 then self:energyAttack() end
end
end
--# StarField
StreamLine = class()
function StreamLine:init(pos, vel)
local function r () return math.random(255) end
local clrs = {
color(255, 0, 0, r()),
color(0, 0, 255, r())
}
for i = 3, 150 do
table.insert(clrs, i, color(179, 153, 180, r()))
end
self.position = pos
self.velocity = vel
self.color = clrs[math.random(1, #clrs)]
end
function StreamLine:update()
self.position.y = self.position.y - self.velocity
end
function StreamLine:draw()
p = self.position
line(p.x, p.y, p.x, p.y + self.velocity - 4)
end
function StreamLine:shouldCull()
if (self.position.y + self.velocity) < 0 then
return true
end
return false
end
StarField = class()
function StarField:init()
self.minSpeed = 5
self.spawnRate = 1
self.speed = 15
self.lines = {}
end
function StarField:updateAndCull()
toCull = {}
for i, v in ipairs(self.lines) do
if v:shouldCull() then
table.remove(self.lines, i)
else
v:update()
end
end
end
function StarField:update(speed)
self.speed = speed
for i = 1, self.spawnRate do
vel = math.random(self.minSpeed, self.speed)
spawn = vec2(math.random(WIDTH), HEIGHT + vel)
table.insert(self.lines, StreamLine(spawn, vel))
end
self:updateAndCull()
end
function StarField:draw()
pushStyle()
noSmooth()
strokeWidth(1)
lineCapMode(ROUND)
for i, v in ipairs(self.lines) do
stroke(v.color)
v:draw()
end
popStyle()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment