Archer

This is a small game I made this week that I thought I’d share.


--# Main
-- Archer

-- Use this function to perform your initial setup
function setup()
    archerElbowX = 100
    v1 = vec2(200,250)
    bow = vec2(130,250)
    tx = WIDTH/2
    ty = 0
    shotTarget = false
    arrow = vec2(90,0)
    arrowBack = vec2(20,0)
    dx = 0
    gravity = 0
    arrow1 = physics.body(POLYGON,vec2(0,0),vec2(0,8),vec2(70,8),vec2(70,0))
    rotation = 0
    hitTarget = false
    oppositeRotation = 0
    elbowX = WIDTH-800
    touchMoved = 0
    powerTrue = true
    shoot = false
    power = 0
    finalStage = false
    timer = 0
    result = 0
    windBoolean = false
    wind = math.random(-15,15)
    windResult = 0
    finalPick = 0
    bowTop = vec2(WIDTH/2,125)
    bowBottom = vec2(WIDTH/2,0)
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- This sets the line thickness
    strokeWidth(5)

    -- Do your drawing here
    if powerTrue == true then
        PowerStage:draw()
    elseif shoot == true then
        ShootingStage:draw()
    elseif finalStage == true then
        FinalTarget:draw()
    elseif windBoolean == true then
        WindStage:draw()
    end
    
end

function touched(t)
    if powerTrue == true then
        PowerStage:touched(t)
    elseif shoot == true then
        ShootingStage:touched(t)
    elseif windBoolean == true then
        WindStage:touched(t)
    end
end

--# PowerStage
PowerStage = class()

-- Archer
displayMode(FULLSCREEN)
-- Use this function to perform your initial setup
function PowerStage:draw()
    -- This sets a dark background color 
    background(116, 116, 217, 255)

    -- This sets the line thickness
fill(0, 0, 0, 255)

    -- Do your drawing here
    pushStyle()
    strokeWidth(0)
    fill(52, 239, 50, 255)
    rectMode(CENTER)
    rect(WIDTH/2,75,WIDTH,150)
    popStyle()
    strokeWidth(25)
    stroke(255, 255, 255, 255)
    fill(255)
    line(WIDTH-850,100,WIDTH-750,300) --leg left
    line(WIDTH-750,300,WIDTH-650,100) --leg right
    line(WIDTH-750,300,WIDTH-750,600) --body
    line(WIDTH-750,500,WIDTH-600,500) --arm left
    line(WIDTH-750,500,elbowX,475) --arm right top
    line(elbowX,475,elbowX+150,500) --arm right bottom
    ellipse(WIDTH-750,600,150) --head
    pushStyle()
    stroke(100, 70, 31, 255)
    line(WIDTH-600,400,WIDTH-600,600)
    popStyle()
    pushStyle()
    strokeWidth(4)
    fill(255, 255, 255, 255)
    stroke(255, 255, 255, 255)
    line(WIDTH-600,600,elbowX+150,500)
    line(WIDTH-600,400,elbowX+150,500)
    popStyle()
    pushStyle()
    lineCapMode(PROJECT)
    strokeWidth(15)
    stroke(255, 0, 0, 255)
    line(elbowX+150,500,elbowX+350,500)
    popStyle()
    fill(255, 0, 0, 255)
    fontSize(35)
    text("Drag to increase power...",WIDTH/2+200,HEIGHT-100)
    fontSize(25)
    text("Power:   "..math.ceil(power),WIDTH-100,50)
end

function PowerStage:touched(t)
    if t.state == MOVING then
        touchMoved = touchMoved - t.deltaX
        elbowX = elbowX - touchMoved/100
        if elbowX < WIDTH-925 then
            elbowX = WIDTH-925
        elseif elbowX > WIDTH-800 then
            elbowX = WIDTH-800
        end
    end
    power = (WIDTH-800-elbowX)/3.57
    if t.state == ENDED then
        touchMoved = 0
        windBoolean = true
        shoot = false
        powerTrue = false
    end
end

--# WindStage
WindStage = class()

    function WindStage:draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- This sets the line thickness
    strokeWidth(0)

    -- Do your drawing here
    fill(0, 255, 31, 255)
    rect(0,0,WIDTH,400)
    
    fill(255)
    ellipse(WIDTH/2,425,300)
    fill(255, 0, 0, 255)
    ellipse(WIDTH/2,425,300-125*0.390625)
    fill(255)
    ellipse(WIDTH/2,425,300-250*0.390625)
    fill(255, 0, 0, 255)
    ellipse(WIDTH/2,425,300-375*0.390625)
    fill(255)
    ellipse(WIDTH/2,425,300-500*0.390625)
    fill(255, 0, 0, 255)
    ellipse(WIDTH/2,425,300-625*0.390625)
    fontSize(25)
    text("Wind:   "..wind,100,HEIGHT-50)
    fill(125,200)
    ellipse(tx,425,35)
    windResult = tx+(wind*(WIDTH/2)/15)
    pushStyle()
    lineCapMode(PROJECT)
    strokeWidth(25)
    line(bowBottom.x,bowBottom.y,bowTop.x,bowTop.y)
    lineCapMode(ROUND)
    stroke(255)
    line(WIDTH/2,50,bowTop.x,bowTop.y-(bowTop.y-bowBottom.y)/2)
    strokeWidth(4)
    line(WIDTH/2,50,bowTop.x,bowTop.y)
    line(WIDTH/2,50,bowBottom.x,bowBottom.y)
    popStyle()
    fill(255)
    ellipse(WIDTH/2,50,150)
    stroke(111, 86, 37, 255)
end

function WindStage:touched(t)
    if t.state == MOVING then
        bowBottom.x = bowBottom.x + t.deltaX/4
        bowTop.x = bowTop.x + t.deltaX/4
        tx = tx + t.deltaX 
    end
    if t.state == ENDED then
        shoot = false
        powerTrue = false
        windBoolean = false
        shoot = true
        finalStage = false
    end
end

--# ShootingStage
ShootingStage = class()

-- Archer Shooting Stage
displayMode(FULLSCREEN)
supportedOrientations(LANDSCAPE_ANY)
-- Use this function to perform your initial setup

function ShootingStage:draw()
    -- This sets a dark background color
    background(68, 68, 224, 255)

    -- This sets the line thickness
    
strokeWidth(0)
    -- Do your drawing here
    arrow.x = arrow.x + dx
    arrowBack.x = arrowBack.x + dx
    rectMode(CENTER)
    fill(61, 239, 50, 255)
    rect(WIDTH/2,75,WIDTH,150)
    strokeWidth(0)
    rectMode(CORNER)
    fill(206, 198, 163, 255)
    ellipse(WIDTH-75,250,25,228)
    rect(WIDTH-100,136,25,228)
    fill(0, 0, 0, 255)
    ellipse(WIDTH-99,250,25,228)
    fill(255, 255, 255, 255)
    ellipse(WIDTH-100,250,25,228)
    fill(255, 0, 0, 255)
    
    
    
    pushStyle()
    rectMode(CENTER)
    popStyle()
    strokeWidth(15)
    fill(255, 255, 255, 255)
    stroke(255,255, 255, 255)
    line(150,100,125,200) --leg left
    line(125,200,100,100) --leg right
    line(125,200,125,300) --body
     --arm left
     --arm right top
     --arm right bottom
    ellipse(125,300,75) --head
    pushStyle()
    pushMatrix()
    stroke(120, 82, 30, 255)
    translate(bow.x,bow.y)
    bowRotate =vec2(tx/300,ty/300)
    down = vec2(1, 0)
    orient = down:angleBetween(bowRotate)
    pushMatrix()
    resetMatrix()
    translate(bow.x,bow.y)
    translate(bowRotate.x,bowRotate.y)
    rotate(math.deg(orient/2))
    line(75,50,75,-50)
    stroke(255)
    line(0,0,75,0)
    line(0,0,-30,-25)
    line(-30,-25,20,0)
    strokeWidth(4)
    line(75,50,20,0)
    line(75,-50,20,0)

    popMatrix()
    popMatrix()
    popStyle()
    pushStyle()
pushMatrix()
    stroke(120, 82, 30, 255)
    translate(bow.x,bow.y)
    bowRotate =vec2(tx/300,ty/300)
    down = vec2(1, 0)
    orient = down:angleBetween(bowRotate)
    pushMatrix()
    resetMatrix()
    translate(bow.x,bow.y)
    translate(bowRotate.x,bowRotate.y)
    rotate(math.deg(orient/2))
    if shotTarget == true then
        rotate(-rotation)
        rotation = rotation + 15/(WIDTH/15)
    end
    if hitTarget == false then
        oppositeRotation = rotation
        
    end
    if hitTarget == true then
        rotate(rotation - oppositeRotation)
        result = power*(math.deg(orient/2))*2.9
        timer = timer + 1
        if timer > 60 then
            finalStage = true
            shoot = false
            powerTrue = false
            timer = 0
            print("Y: "..result)
            print("X: "..windResult)
        end
    end
    strokeWidth(8)
    lineCapMode(PROJECT)
    stroke(255, 0, 0, 255)
    line(arrowBack.x,arrowBack.y,arrow.x,arrow.y)
    if arrow.x >789 then
        arrow.x = 789
        dx = 0
        hitTarget = true
    end
    popMatrix()
popMatrix()
    popStyle()
    --Target
    
    
end

function ShootingStage:touched(t)
    if shotTarget == false then
    tx = t.x
    ty = t.y
    if t.state == ENDED then
        shotTarget = true
        dx = dx + power
        gravity = gravity + 1
    end
        end
end


--# FinalTarget
FinalTarget = class()

function FinalTarget:draw()
    -- Codea does not automatically call this method
    background(116, 116, 217, 255)
    strokeWidth(0)
    fill(52, 239, 50, 255)
    rect(0,0,WIDTH,100)
    fill(255)
    ellipse(WIDTH/2,HEIGHT/2,HEIGHT)
    fill(255, 0, 0, 255)
    ellipse(WIDTH/2,HEIGHT/2,HEIGHT-125)
    fill(255)
    ellipse(WIDTH/2,HEIGHT/2,HEIGHT-250)
    fill(255, 0, 0, 255)
    ellipse(WIDTH/2,HEIGHT/2,HEIGHT-375)
    fill(255)
    ellipse(WIDTH/2,HEIGHT/2,HEIGHT-500)
    fill(255, 0, 0, 255)
    ellipse(WIDTH/2,HEIGHT/2,HEIGHT-625)
    pushStyle()
    rectMode(CENTER)
    fill(0)
    rect(windResult,result,50,50)
    popStyle()
end
function FinalTarget:touched(touch)
    -- Codea does not automatically call this method
end

The height of the final result is a bit off. I could really figure out a way to measure the “height” very accurately as it changes based on rotation so the y value is always 0. If anyone has any advice on how to make this more accurate or has any suggestions/advice on how to better the game please feel free to post a comment.

Thanks for share! I will test it now.

@Andresan I just noticed that the power stage does not change the speed of the arrow. I’ve changed the original code, but you can change yours by going into the shooting stage class and changing the touched function so that dx = dx + power instead of + 36.

@Staples - maybe this post will help you with the height of the arrow

http://coolcodea.wordpress.com/2013/10/21/128-physics-ballistics/

The user and all related content has been deleted.

Nice skeletal animation!

@NatTheCoder feel free to use whatever you want, just note that the height is a bit off as I stated above, but I feel like it is pretty close (I made up a formula to measure the “height”, it must be working). I will try to make it 100% accurate and update the code by looking @Ignatz’s blog post. If you are going to publish a game on the App Store with any of my code, please credit me though. :slight_smile:

The user and all related content has been deleted.