Lockdown

Hi All
If you are anything like me, and probably are - wherever you are, you are either very busy fighting CVD19, ill with it or subject to Lockdown. So I am posting some incomplete code which I started a few months ago and shelved. It’s based on a 1K challenge to make a Space Invaders game up. I didn’t intend limiting it to 1K but I tried to use the principle by using emojis as an alternative to sprites.

Got the base system up and running, not cleaned up or optimised, and haven’t yet added the touch control interactions and scores - so I am hoping that you can fill those in. This is intended to give users a target, entertain/distract/frustrate them in a hope what is happening in the World for most of us can be put on hold for a while. If you do get anywhere with this please post with your ideas/problems so other users can learn from it. Also if anyone else has similar half finished projects - Now’s the time to share the work. Code below:


-- 1KSpaceInvaders

displayMode(FULLSCREEN)
function setup()
    W,H = WIDTH,HEIGHT
    N={5,5,5,5,5,5,5,5,5,5,5}
    S,B,V,D,I,O,P = W/24,350,0,300,1,0,0,0
    buttons = {""}
    vaders = {{""},
    {""},
    {""},
    {""}
    }
    bpos = vec2(350,160)
    x,y,bw,vh,mv = 350,W/24,S+44,980,12
    blimL,blimR = 128,638
    bmv = 8
    blts = {x={},y={}}
    dark = fill(76, 37, 129, 255)
    ground = fill(118, 78, 37, 255)
    myMesh = mesh()
    myMesh.vertices = {vec2(0,1024),vec2(0,0),vec2(768,0),vec2(0,1024),vec2(768,0),vec2(768,1024)}
    myMesh.colors = {color(94, 22, 241, 255),color(60, 120, 38, 255),color(50,120,38,255),
    color(94,22,241,255),color(50,120,38,255),
    color(94,22,241,255)}
end

function draw()
    background(1, 132, 254, 255)
    -- S is image size, H is screen Height, W is screen Width
    -- P is 
    -- V is
    -- I is
    -- O is 
    myMesh:draw()
    y = H-S
    if I < 1 then 
        O = O +.5
    else
        O = O -.5
    end
    if O > S then 
        I = 1
        P = P+S
    end
    if O < -S then
        I = 0
        P = P+S
    end
        V = V-1
    fontSize(84)
    fill(254, 254, 254, 255)
    pushMatrix()
    -- 160
        text(buttons[1],40,100) 
        text(buttons[3],726,100)
        text(buttons[2],bpos.x,bpos.y)
        noFill()
        strokeWidth(5)
        fill(240, 42, 65, 255)
        ellipse(720,240,80,80)
        fill(220, 228, 201, 31)
    strokeWidth(1)
        rect(84,72,600,40)
    popMatrix() 

    -- D is
    -- i is column number
    -- j is row number
    -- B is
    -- N{} is
    
    if V < 0 then
        D = 1
    end
    for i = 1,10 do
        for j = 1,4 do
            tmp = 2*i*S
            if B > tmp+O and B < tmp+S and V > tmp+P and V < tmp+P+S then
                if N[i] > j and D < 1 then
                    D = 1
                    N[i] = N[i]-1
                end
            end
            fontSize(54)
            fill(255, 255, 255, 255)
            
          for si =1,4 do
                for sv = 1,10 do
                    if vaders[si][sv] > "-" then
                        text(vaders[si][sv],sv*66+20+O,vh-si*64-P+S)
                    end
                end
            
           end
            if N[i] > j then
            end
        end
    end
    strokeWidth(5)
    for f = 1, #blts do
        line(blts[f].x,blts[f].y+bmv,bmv,5,bmv)
    end
end

function touched(t)
    if t.state ~ ENDED then
        if t.y >= 60 and t.y <= 190 then
         --   print(t.x,t.y)
            bpos.x = t.x
            if bpos.x <= blimL then
                bpos.x = blimL
            elseif bpos.x >= blimR then
                bpos.x = blimR
            end
        elseif t.x >= 680 and t.y >= 200 and t.y <= 280 then
          --  print("fire")
         --   table.insert(blts,x=bpos.x,y=bpos.y+8)
        end
    else
    end
end

p.s. the buttons and invaders have been removed as they can not be printed in the format. I have posted an image below and will post a little code later with the character codes for the aliens and buttons. I may try another approach with another image to achieve this.

Hi there,

Space Invaders, nice! Thanks for the inspiration.

I used this as a starting point to try to make a simple game and try out codea and lua.
The structure is about the same.
You can play with touch control but also with an external keyboard.

-- Rocky Invaders
-- very simple game for Codea

function setup()
    --  showKeyboard() -- enable for keyboard to work
    displayMode(FULLSCREEN)
    spriteMode(RADIUS)
    block = (WIDTH - 100) / 12
    size_img = block/2 -- size_imgze images
    x_rock, y_rock, rocksDirection = 0, HEIGHT - 4 * block, 0
    x_ship, shipDirection = WIDTH/2, 0
    x_bullet, y_bullet = WIDTH/2, 0
    x_cloud, y_cloud = 0,0
    fired = 0
    as, clouds = {}, {}
    rocks = math.random(22,44)
    for i=1,rocks do as[i]={s=math.random(0,2),y=-100} end
    for i=1,100 do clouds[i]={s=math.random(0,1),y=-100} end

    --configure
    bulletSpeed = 15
    rocksSpeed = 0.35
    shipSpeed = 4
end

function draw()
    background(80, 50, 100)

    -- draw cloud bg
    for i = 1,#clouds do
        col = 1+(i % 13); row = 1+(i % 9)
        x = x_cloud + (col * block)
        y = y_cloud + (row * block)
        z = size_img/(y/1000)
        if (clouds[i].s == 1) then
            sprite(asset.builtin.Space_Art.Cloudy_Nebula,x,y,z,z)
        end
    end
    --calculate rocks movement
    if rocksDirection == 1 then
        x_rock = x_rock - rocksSpeed
        y_rock = y_rock - rocksSpeed/2
    else
        x_rock = x_rock + rocksSpeed
        y_rock = y_rock - rocksSpeed/2
    end
    -- change rocks direction and SFX
    if x_rock > size_img then
        rocksDirection = 1; y_rock = y_rock - block/10
        sound(SOUND_EXPLODE, 24800)
    end
    if x_rock < -size_img then
        rocksDirection = 0; y_rock = y_rock - block/10
        sound(SOUND_EXPLODE, 24800)
    end
    if math.ceil(x_rock)==0 then 
        sound(SOUND_PICKUP, 24845)
    end

    -- draw rocks
    for i = 1,rocks do
        col = 1.3+(i % 11); row = 1+(i % 4); even = i % 2
        x = x_rock + (col * block)
        y = y_rock + (row * block)
        if (even==0) then x = x + size_img/2 end
        -- hit something?
        if (x_bullet>x-size_img and x_bullet<x+size_img and
            y_bullet>y-size_img and y_bullet<y+size_img) and as[i].s < 2 then
            fired=0; y_bullet=0; as[i].s=as[i].s+1; as[i].y=y
            sprite(asset.builtin.Space_Art.Red_Explosion,x,as[i].y,size_img,size_img)
            sound(SOUND_EXPLODE, 36059)
            -- have we won
            if winner() then
                sound(SOUND_POWERUP, 47448); restart()
            end
        end
        --change sprite when hit
        if (as[i].s==0) then
            sprite(asset.builtin.Space_Art.Asteroid_Large,x,y,size_img,size_img)
        elseif (as[i].s==1) then
            sprite(asset.builtin.Space_Art.Asteroid_Small,x,y,size_img/2,size_img/2)
            if (y < 150) then -- below this you die
                sound(SOUND_EXPLODE, 36028);background(255);restart()
            end
        elseif (as[i].s > 1) then
            as[i].s = as[i].s+.1
            sprite(asset.builtin.Space_Art.Star,x-x_rock,as[i].y,size_img/as[i].s,size_img/as[i].s)
        end
    end

    --draw ship
    x_ship = x_ship + shipSpeed * shipDirection
    if (x_ship < size_img) then
        x_ship = size_img
    elseif (x_ship > WIDTH - size_img) then
        x_ship = WIDTH - size_img
    end
    sprite(asset.builtin.Space_Art.Red_Ship,x_ship,100,size_img,size_img)
    
    -- draw bullet
    if fired == 1 then
        y_bullet = y_bullet + bulletSpeed
        sprite(asset.builtin.Space_Art.Beam,x_bullet,y_bullet,10,size_img)
    end
    if (y_bullet > HEIGHT) then fired = 0 end
    
    function winner()
        for i=1,#as do
            if as[i].s < 2 then return false end
        end
        return true
    end

    function fire()
        if fired == 0 then
            sound(SOUND_HIT, 36708)
            x_bullet = x_ship; shipDirection = 0; y_bullet = 200; fired = 1
        end
    end

    --control
    function touched(touch)
        if touch.x < 140 then shipDirection = -1 end
        if touch.x > 140 and touch.x < 220 then shipDirection = 1 end
        if touch.state == BEGAN then
            if touch.x > WIDTH-140 then fire() end
        end
    end

    --control by keys (enable keyboard first in setup)
    function keyboard(key)
        if (key=="," or key=="<") then shipDirection = -1 end
        if (key=="." or key==">") then shipDirection = 1 end
        if (key==" ") then fire() end
    end
    
    fontSize(60);fill(255, 50)
    ellipse(100,300,80); ellipse(180,300,80); ellipse(WIDTH-100,300,80)
    text("‹", 100, 305); text("›", 180, 305); text("•", WIDTH-100, 300)
    
end 

@Atopia - excellent, very neat game. I was begining to think no-one would contribute to this but your program is a good example. Tnnk I’ll start to add a few exxtras on the one I started. Tanks.

Great stuff guys, I’ve zero game writing experience and just starting to dabble with Codea and using invaders type things to experiment with so this will be invaluable.

Probably started too hard as going with voxels too and that is bending my head.

@RaggedTooth - your welcome. Don’t hesitate to post queries, this is a great forum to help. I’d stick to non Craft until you have built up a basic understanding of Lua and Codea. It’s a good package and easy to absorb.

@Bri_G Ha, I’m sure you’re right, but I’m a glutton for punishment and will go a little way down the path, probably before seeing sense and coming back with my tail between my legs…

I think it’s fun trying!

Here’s a space invaders version that I had. Tilt the iPad left or right to move the ship. Tap the screen to shoot. Play in portrait orientation for more room up/down. Each time you shoot all the enemy players, the game will restart at a faster pace. If the enemy reaches near the bottom, the game restarts starting with the slow speed. There isn’t much to this, so don’t expect much.

displayMode(FULLSCREEN)

function setup()
    v=10
    limit=30
    setup1()
end

function setup1()
    v=10
    mis={}
    h=HEIGHT-50
    w=0
    tab={}
    for z=1,60 do
        tab[z]=0
    end
    delay=0
    limit=limit-3
    gx=WIDTH/2
end

function draw()
    background(40, 40, 50)    
    drawEnemy()
    checkDelay()
    moveShip()
    checkHit()
    checkEnemy()
    removeMis()
end

function touched(t)
    if t.state==BEGAN then
        gy=200
        table.insert(mis,vec2(gx,gy))
    end
end

function drawEnemy()
    cnt=0
    for x=1,12 do
        for y=1,5 do
            cnt=cnt+1
            if tab[cnt]==0 then
                sprite(asset.builtin.Space_Art.Part_Gray_Hull_4,x*60-30+w,h-y*40,20)
                if h-y*40<250 then
                    setup()
                end
            end
        end
    end
end

function checkDelay()
    delay=delay+1
    if delay>limit then
        if w>105 or w<0 then
            v=-v
            h=h-30
        end
        w=w+v
        delay=0
        sound(SOUND_SHOOT, 30208)
    end
end
    
function moveShip()
    sprite(asset.builtin.Space_Art.Red_Ship,gx,200)
    gx=gx+Gravity.x*20
end
       
function checkHit()
    for a,b in pairs(mis) do
        b.y=b.y+10
        sprite(asset.builtin.Space_Art.Red_Explosion,b.x,b.y,20)
        cnt=0
        for x=1,12 do
            for y=1,5 do
                cnt=cnt+1
                xp=x*60-30+w
                yp=h-y*40
                if b.x>xp-10 and b.x<xp+10 and b.y>yp-10 and b.y<yp+10 then
                    if tab[cnt]==0 then
                        tab[cnt]=1
                        table.remove(mis,a)
                        sound(SOUND_HIT, 30217)
                    end
                end
            end
        end
    end
end
    
function checkEnemy()
    cnt=0
    for z=1,#tab do
        if tab[z]==1 then
            cnt=cnt+1
        end
        if cnt==60 then
            setup1()
            return            
        end
    end
end
    
function removeMis()
    for z=#mis,1,-1 do
        if mis[z].y>HEIGHT+100 then
            table.remove(mis,z)
        end
    end
end

@dave1707 - sorry I’ve been slow to reply to this, family matters!! This is a very neat and concise code, keeps all the features needed despite it’s size. Must admit I tend not to think of the gyroscope for controlling movement but it works well here. Now in my useful demos list. Thanks for that.

Hi All,

Thanks for the contributions here, didn’t get the progressive development I hoped for here but thanks for your posts. I’ve decided to post a project which is almost finished, just needs a little tidying - something I started years ago got to work then messed up and shelved. Largely fixed, grandkids love it. You have all probably seen this especially at Christmas. When I finished was going to offer to 2LL as a finished demo. Here it is in bits, I have posted some of the sprites to get it working.

Here is the main tab:


--# Main

function setup()
    -- load resources
    init()
end

function draw()
    -- set up the background and fixed sprites
    spriteMode(CENTER)
    sprite(back,cW,cH,sW,sH)
    sprite(absent,sW-200,200,96)
    sprite(present,200,200,chW,chH)
    sprite(absent,568,200,chW,chH)
    font("Georgia-bold")
    fontSize(84)
    fill(130, 39, 59)
    text("MAGIC NUMBER",cW-4,sH-124)
    fill(252, 91, 8)
    text("MAGIC NUMBER",cW,sH-120)
    -- display number cards stationary or in motion
    for lp =1,#card do
        if sorted < 5 then
            if card[lp].pos.y < 100 then 
                card[lp].pos.y = 100 
            end
            if card[lp].pos.y > 710 then 
                card[lp].pos.y = 710 
            end
            if card[lp].vis == true then
                adjust = 0
                sprite(card[lp].pic,card[lp].pos.x,card[lp].pos.y,card[lp].size)
            end
        end   
    end
    if sorted == 5 then
        -- show result and repeat or exit
        pushMatrix()
            strokeWidth(3)
            stroke(0,0,0,255)
            fill(255,255,255,255)
            rect(cW-90,116,180,136)
            fill(0,0,0,255)
            fontSize(18)
            text("your number is: ", cW, 220)
            fill(0,0,0,fade)
            fontSize(72)
            font("Georgia-bold")                
            text(total,cW,170)
            if fade > 254 then
                fade = 255
            else
                fade = fade + 1
            end
            if fade > 254 then
                sprite(reStart,cW,cH)
            end
        popMatrix()
    end
end

function touched(touch)
    -- touch routine where all the magic is done
    local x,y = touch.x,touch.y
    if touch.state == BEGAN then
        check = checkInside(touch.pos)
    elseif touch.state == MOVING and check > 0 then
        card[check].pos = vec2(x+touch.deltaX,y+touch.deltaY)
        card[check].size = card[check].size+touch.deltaY/10
    elseif touch.state == ENDED then 
        if check > 0 then
            card[check].pos = vec2(cLoc*check,cHeight)
            card[check].size = cSize
            for cp = 1,2 do
                test1 = math.abs(CurrentTouch.y - chest[cp].pos.y)
                if test1 < 60 then
                    test2 = math.abs(CurrentTouch.x - chest[cp].pos.x)
                    if  test2 < 60 and cp == 1 then
                        print("test1 : "..check,cp,test1,test2)
                        if card[check].vis == true then
                            total = total + card[check].value
                            sorted = sorted + 1
                        end
                        card[check].vis = false
                    elseif test2 < 60 and cp == 2 then
                        print("test2 : "..check,cp,test1,test2)
                        sorted = sorted + 1
                        card[check].vis = false
                    end
                    test1, test2 = 0,0
                end
            end
        else
            if sorted == 5 then
                sprite(reStart,cW,cH)
                if CurrentTouch.x > cW-resW/2 and CurrentTouch.x < cW+resW/2 and CurrentTouch.y > cH-resH/2 and CurrentTouch.y < cH+resH/2 then
                    check = 0
                    init()
                end
            end
        end
    end
end

Here is the utils/resources code:


--# Utils

function init()
    --
    sW,sH,cW,cH = WIDTH, HEIGHT, WIDTH/2, HEIGHT/2
    cLoc = WIDTH//6
    cHeight = 700
    cSize = 124
    card = {}
    chest = {}
    total = 0
    sorted = 0
    fade = 0
    check = 0
    more = false
    
    panel1 = readImage(asset.documents.Dropbox.magicno.panel1)
    panel2 = readImage(asset.documents.Dropbox.magicno.panel2)
    panel3 = readImage(asset.documents.Dropbox.magicno.panel4)
    panel4 = readImage(asset.documents.Dropbox.magicno.panel8)
    panel5 = readImage(asset.documents.Dropbox.magicno.panel16)
    
    reStart = readImage(asset.documents.Dropbox.magicno.restart)
    resW,resH = spriteSize(reStart)
    
    mystic = readImage(asset.documents.Dropbox.magicno.mystic)
    back = readImage(asset.builtin.Cargo_Bot.Game_Area)
    present = readImage(asset.documents.Dropbox.magicno.Present)
    absent = readImage(asset.documents.Dropbox.magicno.Absent)
    chW,chH = spriteSize(present)
    
    card[1] = cards(1,1,panel1,vec2(cLoc,cHeight),true,cSize)
    card[2] = cards(2,2,panel2,vec2(cLoc*2,cHeight),true,cSize)
    card[3] = cards(3,4,panel3,vec2(cLoc*3,cHeight),true,cSize)
    card[4] = cards(4,8,panel4,vec2(cLoc*4,cHeight),true,cSize)
    card[5] = cards(5,16,panel5,vec2(cLoc*5,cHeight),true,cSize)
    
    chest[1] = chests(1,present,vec2(200,200),96)
    chest[2] = chests(2,absent,vec2(560,200),96)

end

function checkInside(ct)
--
    for lp = 1,#card do
        if ct.x > card[lp].bl.x and ct.x < card[lp].tr.x then
            if ct.y > card[lp].bl.y and ct.y < card[lp].tr.y then
                return math.floor((ct.x+60)/cLoc)
            else
                return 0
            end
        end
    end
end

Finally here are the classes involved:


--# CardClass

cards = class()

function cards:init(id,val,px,pos,vis,size)
    -- 
    self.cardID = id
    self.value = val
    self.pic = px
    self.pos = pos
    self.vis = vis or true
    self.size = size
    half = size/2
    self.bl = vec2(self.pos.x-half,self.pos.y-half)
    self.tr = vec2(self.pos.x+half,self.pos.y+half)
end

function cards:draw()
    --
    local lp
    for lp = 1,5 do
         sprite(self.pic,self.pos.x,self.pos.y,self.size)
    end
end


--# ChestClass

chests = class()

function chests:init(id,pic,pos,size)
    --
    self.id = id
    self.pos = pos
    self.pic = pic
    self.size = size
    local half = math.floor(size/2)
    self.cbl = vec2(self.pos.x-half,self.pos.y-half)
    self.ctr = vec2(self.pos.x+half,self.pos.y+half)
end


I am sure many of you will be able to suggest refinements, simplifications, bug fixes!!! All would be welcome.

Hi All,

Finally images of how it should look, and my own setup for it.

Oh, for all who have not seen this you have to select a number between 1 and 32 then drag the cards which contain that number to the present chest, and the other to the absent chest. Then your iPad will tell you which number you chose.

I’m looking at increasing the cards to six and selecting number for 1 to 64.

Any issues - just post em.

Edit: A little bit of colour helps, see attached pics. Your main edits will be to set up the path links to the graphic sprites either in the text form “Dropbox:…panel1” or with the asset.path list method asset.documents.Dropbox. … panel1 or similar.

All - just been fiddling with @Jarc ’s loader and thinking about text size/colour display to make formatting in it easier? Came up with this - needs a little more polishing to make it generally applicable but - here it is:


function setup()
    --
    sW,sH,cW,cH = WIDTH,HEIGHT,WIDTH/2,HEIGHT/2
    -- a few thought provoking ideas 
    story = {}
    table.insert(story,"Red is my favourite colour")
    table.insert(story,"My knee hurts")
    table.insert(story,"Always look on the bright side of life")
    table.insert(story,"A Song of Ice and Fire")
    table.insert(story,"Books can be dangerous")
    table.insert(story,"Stars can't shine without darkness")
    table.insert(story,"I can, I will, end of story")
    table.insert(story,"A smooth sea never made a skillful sailor")
    table.insert(story,"Take the risk or lose the chance")
    table.insert(story,"Don't stop until your proud")
    table.insert(story,"Never make permanent decisions on temporary feelings")
    table.insert(story,"The eyes are useless when the mind is blind")
    -- cycling the font colour
    fs = 40
    colours = {
                color(234, 22, 10),
                color(234, 138, 10),
                color(234, 232, 10),
                color(135, 255, 0),
                color(0, 255, 156),
                color(10, 228, 234),
                color(0, 122, 255),
                color(10, 24, 234),
                color(125, 10, 234),
                color(210, 10, 234),
                color(234, 10, 133),
                color(211, 162, 209),
                color(234, 22, 10),
                color(183, 62, 72),
                color(112, 206, 145)
            }
end

function draw()
    --
    background(0)
    textMode(CENTER)
    font("Georgia")
    for lp = 1,#story do
        fontSize(sW*2/string.len(story[lp]))
        fill(colours[lp])
        text(story[lp],cW,sH-lp*80)
    end
end


Anyone any ideas on pushing this further?