Cool. Like it. 2 competitors in the game section.
ENEMY_SPAWN_EASY = 0
ENEMY_SPAWN_HARD = 1
EnemyHorde = class()
function EnemyHorde:init()
-- you can accept and set parameters here
self.frame = 0
self.units = {} -- enemy units
self.heroBullets = {} -- hero's bullets
self.explosions = {}
self.enemySize = 50
self.killCount = 0
self.spawnPattern = ENEMY_SPAWN_EASY
end
function EnemyHorde:draw()
self.frame = (self.frame+1)%128
pushStyle()
if self.spawnPattern == ENEMY_SPAWN_EASY then
fill(123, 25, 100, 255)
else
fill(16, 221, 4, 255)
end
stroke(62, 33, 37, 255)
strokeWidth(4)
-- Spawn random enemy every 100 frames
if self.frame%50 == 0 then
spawn = vec2( math.random(WIDTH), HEIGHT + self.enemySize )
table.insert( self.units, spawn )
end
for i,v in ipairs(self.units) do
-- Move unit down
v.y = v.y - 5
-- If hard, move in sine wave
if self.spawnPattern == ENEMY_SPAWN_HARD then
-- Compute movement vector
sideMove = vec2( math.sin(v.y * 0.02) * 60, 0 )
v = v + sideMove
end
-- Cull unit
culled = false
if (v.y + self.enemySize) < 0 then
table.remove(self.units, i)
culled = true -- no continue statement
end
-- Check if hit by a bullet
if culled == false then
for j,b in ipairs(self.heroBullets) do
if v:dist(b) < self.enemySize/2 then
table.remove(self.units, i)
table.remove(self.heroBullets, j)
-- Explode!
table.insert(self.explosions, Explosion(v))
-- Update killCount
self.killCount = self.killCount + 1
end
end
end
-- Draw unit
sprite("Tyrian Remastered:Blimp Boss", v.x, v.y, self.enemySize, self.enemySize)
end
-- Draw explosions
for i,e in ipairs(self.explosions) do
e:draw()
if e:isDone() then
table.remove(self.explosions,i)
end
end
popStyle()
end
Explosion = class()
function Explosion:init(pos)
self.position = pos
self.opacity = 255
self.time = 0
self.lines = {}
sound("explode",1285)
for i = 1,10 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 + 1.939
pushStyle()
lineCapMode(ROUND)
strokeWidth(6)
smooth()
stroke(255, 146, 0, 255)
p = self.position
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/30));
popStyle()
end
Invader = class()
function Invader:init()
self.position = vec2(0,0)
self.bullets = {}
self.frame = 0
end
function Invader:spawnBullet()
sound("shoot",77)
table.insert( self.bullets, vec2( self.position.x, self.position.y + 30 ) )
end
function Invader:drawBullets()
-- Spawn bullets
if self.frame%30 == 0 then
self:spawnBullet()
end
-- Move, draw, cull bullets
for i,v in ipairs(self.bullets) do
v.y = v.y + 3
rect(v.x, v.y, 2.5, 45)
if v.y > (HEIGHT + 10) then
table.remove(self.bullets,i)
end
end
end
function Invader:draw()
self.frame = (self.frame + 1)%128
pushMatrix()
pushStyle()
-- Set up basic graphical style
lineCapMode(ROUND)
strokeWidth(8)
stroke(222, 12, 12, 255)
smooth()
noFill()
-- Transform to pos
translate(self.position.x, self.position.y)
-- Draw our triangle invader
-- 60 pixels high, 40 pixels wide
fill(47, 34, 34, 255)
line( 0, 30, 20, -30 )
line( 0, 30,-20, -30 )
line( -20, -30, 20, -30 )
sprite("Tyrian Remastered:Boss D")
popMatrix()
self:drawBullets()
popStyle()
end
function Invader:touched(touch)
-- Codea currently does not automatically call this method
end
hero = nil
enemies = nil
bgLines = nil
explosion = nil
GAME_PLAYING = 0
GAME_DEAD = 1
state = GAME_PLAYING
-- Use this function to perform your initial setup
function setup()
state = GAME_PLAYING
iparameter("BackgroundSpawnRate",0,3,2)
hero = Invader()
hero.position = vec2(WIDTH/2, 150)
enemies = EnemyHorde()
enemies.heroBullets = hero.bullets
bgLines = StreamingLines()
end
function touchingAtPos()
if CurrentTouch.state == BEGAN or
CurrentTouch.state == MOVING then
return vec2( CurrentTouch.x, CurrentTouch.y )
end
return nil
end
-- This function gets called once every frame
function draw()
background(12, 0, 255, 255)
bgLines.spawnRate = BackgroundSpawnRate
bgLines:update()
bgLines:draw()
if state == GAME_PLAYING then
-- Process touch
touch = touchingAtPos()
if touch then
if touch.x < (hero.position.x - 10) then
hero.position.x = hero.position.x - 3
elseif touch.x > (hero.position.x + 10) then
hero.position.x = hero.position.x + 3
end
end
if enemies.killCount == 5 then
enemies.spawnPattern = ENEMY_SPAWN_HARD
end
enemies:draw()
hero:draw()
-- Check if hero is hit
for i,v in ipairs(enemies.units) do
if v:dist(hero.position) < 60 then
state = GAME_DEAD
explosion = Explosion(hero.position)
end
end
elseif state == GAME_DEAD then
if explosion then
explosion:draw()
if explosion:isDone() then
explosion = nil
end
end
end
end
-- This class draws the lines streaming past in the background
-- of the game. We spawn and delete them in the self.lines table
----------------------------------------------
-- Single line
----------------------------------------------
StreamLine = class()
function StreamLine:init(pos, vel)
self.position = pos
self.velocity = vel
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)
end
function StreamLine:shouldCull()
-- Check if off the bottom of the screen
if (self.position.y + self.velocity) < 0 then
return true
end
return false
end
----------------------------------------------
-- All lines
----------------------------------------------
StreamingLines = class()
function StreamingLines:init()
self.minSpeed = 5
self.speed = 30
self.spawnRate = 2
self.lines = {}
end
function StreamingLines:updateAndCull()
toCull = {}
for i,v in ipairs(self.lines) do
if v:shouldCull() then
-- table.insert( toCull, i )
table.remove( self.lines, i )
else
v:update()
end
end
-- print("Removing ", #toCull)
--for i = #toCull,1,-1 do
-- table.remove( self.lines, i )
--end
end
function StreamingLines:update()
-- Create spawnRate lines per update
for i = 1,self.spawnRate do
-- Generate random spawn location
vel = math.random(self.minSpeed, self.speed)
spawn = vec2( math.random(WIDTH), HEIGHT + vel )
table.insert(self.lines, StreamLine(spawn, vel))
end
-- Update and cull offscreen lines
self:updateAndCull()
end
function StreamingLines:draw()
--print("Num lines = ", #self.lines)
pushStyle()
noSmooth()
stroke(252, 205, 6, 173)
strokeWidth(2)
lineCapMode(SQUARE)
for i,v in ipairs(self.lines) do
v:draw()
end
popStyle()
end
@MICHAEL please remember to put three ~ characters on the lines above and below your code blocks. Otherwise the code will be unreadable and messy in your posts. I’ve fixed it for you this time.
Also, I wouldn’t recommend sharing your code directly in a competition thread when you have multiple tabs, as it makes it difficult to follow the content of the thread.
Thank you @John sorry for forgetting about the ~~~ do you have any recommendations as to how I should go about posting my code for this competition I was unsure of the best way
A lot of people use posterous.com which lets you post stuff via email, by setting up an account and emailing to send@posterous.com (i think). You can then provide the links on the forum.
I strongly recommend gist.github.com. Has versioning, easy copy and paste. Posterous worked better for binary files like .codea and screenshots.
Next time I do this, I’ll try to do a better way on my website. Thanks for the participation!
Thanks. If it’s any consolation, I still die on that stage about 1/2 the time, and it probably took me me a dozen tries to get past the third screen. I only bothered to actually put in four “hand crafted” puzzles, after which the levels are generated randomly, and usually end up being easier than the first four.
The level transition sequence is pretty fantastic. I really like the way everything blasts out and the new level comes in.
@mark I am sitting in class and just tried your game it is awesome I was having trouble with stage 2 so I gave myself a little fuel boost
@Simeon, you can think of this whole game as my leaning the joys of translate() and playing with scale. I tried actively varying the scale so that the ship is actually always the same physical distance from the “sun,” but I found it kind of disorientating.
Oh, and I cheated by using a global variable for scale, but then these classes are’t exactly the kind of thing you’d extract for another program in any case.
It’s stretching the term “space” to its limits, but I’d like to submit my program for exploring “Complex Euclidean Space”: http://www.math.ntnu.no/~stacey/HowDidIDoThat/iPad/Codea.html (scroll down to the projects, the one named “Complex Plane”).
@MICHAEL - If you could give a link to the code, that would be great. (Mabey put it on a hidden page on WordPress) Thanks!