Developing Asteroids: a series.

The bad part of using a joystick type control is if you swipe thru the middle, the ship changes direction instantly instead of rotating at a given value. For instance, being at the 12 O’clock, sliding down into Go, then to the 6 O’clock position.

yes, dave … and it can also happen by accident. it’s close to good tho.

@RonJeffries @dave1707 - a little improvement, still not ideal but closer to our need. Probably needs a little tickling on dimensions and could look better with sprites at the expense of screen real estate.

displayMode(FULLSCREEN)
function setup()
    --
    assert("Please ensure your sound is enabled")
    cW,cH = WIDTH/2, HEIGHT/2
    angle = -180
    padLoc = vec2(100,140)
    padSize = 180
    goSize = 80
    go = false
    checkBX, checkBY = 0,0
    bpX,bpY,bpS = 172,141,64
    butPos = vec3(bpX,bpY,bpS)
--    padCheck = padSize/2
--    goCheck = goSize/2
    butCheck = bpS/2
    fire = vec4(WIDTH-270,90,240,240)
    ship = readImage(asset.builtin.Space_Art.Red_Ship)
    trail = readImage(asset.builtin.Tyrian_Remastered.Flame_1)
end

function draw()
    -- 
    background(40, 40, 50)
    pad()
    pushMatrix()
        translate(cW,cH)
        rotate(angle+90)
        if go == true then
            sprite(trail,-0,-60,-20)
        end
        sprite(ship,0,0)
        rotate(90)
    popMatrix()
    rectMode(CORNER)
    noFill()
    stroke(254, 63)
    rect(fire.x,fire.y,fire.z,fire.a)
end

function touched(touch)
    --
    checkBX = math.abs(butPos.x - touch.pos.x)
    checkBY = math.abs(butPos.y - touch.pos.y)
    if touch.state == CHANGED then
        if math.abs(touch.pos.x - padLoc.x) < butCheck and 
           math.abs(touch.pos.y - padLoc.y) < butCheck then
            print(touch.pos.x - padLoc.x)
            go = true
        else
            go = false
        end
        if checkBX > 0 and checkBX < 160 then
            if  checkBY > 0 and checkBY < 160 then
                angle=math.deg(math.atan2(padLoc.y-touch.pos.y,padLoc.x-touch.pos.x))
                
            end
        end
    end
    if touch.state == ENDED then
        if isInside(touch.pos) == true then
            sound(SOUND_SHOOT, 0.5)
        end
        go = false
    end
end

function pad()
    --
    strokeWidth(2)
    stroke(255, 109)
    noFill()
    ellipseMode(CENTER)
  --  ellipse(padLoc.x,padLoc.y,padSize)
    ellipse(padLoc.x,padLoc.y,goSize)
    pushMatrix()
        translate(padLoc.x,padLoc.y)
        rotate(angle)
        ellipseMode(CENTER)
      --  sprite(asset.builtin.Space_Art.UFO ,padLoc.x-170,0,32)
        ellipse(padLoc.x-170,0,butPos.z)
    popMatrix()
        font("AmericanTypewriter-Bold")
    fontSize(48)
    fill(253, 66)
    text("Go",padLoc.x,padLoc.y)
end

function isInside(t)
--
  if t.x > fire.x and t.y > fire.y then
       if t.x < fire.x+240 and t.y < fire.y+240 then
            return true
        else
            return false
       end
  end
end

@Bri_G That’s a little better, but it still can rotate too fast. What you need to do is limit the rotation speed of the outer circle around the Go circle. That way it can’t rotate too fast but you still have better control over it. I would try to limit it, but it’s your code and I don’t want to step on your toes. I think you’re close to a good solution.

seems like the same idea to me, what am i missing? i share dave’s concern about the abrupt change in direction but i think if you make the link indirect the winding won’t make sense any more. i could be wrong …

@dave1707 @RonJeffries - thanks for the feedback, I take your point but I think trying to modulate the response would mess it up. The obvious way would be to broaden the inner circle/button thus increasing the circumference. After all, the rotation is dependent upon the user’s response speed - if you want fast it can do it, slow - you can do it.

Just thought of another way - make the turn button go through a half, third of the outer circle based at the top. Then apply a variable rate for ship rotation dependent upon extent of movement away from the vertical. Moving the button in the opposite direction would slow down rotation and eventually stop it then reverse it. May take me some time to put that together at the moment - feedback later.

slider can do that …

@RonJeffries @Bri_G Here’s a version that eliminates the snap (180 degree) rotation if you slide your finger to the opposite side of the circle.

displayMode(FULLSCREEN)

function setup()
    x=150
    y=200
    x1=x+65
    y1=y
    ang=0   
    noFill()
    stroke(255)
    strokeWidth(2) 
end

function draw()
    background(0)
    ellipse(x,y,200)
    ellipse(x1,y1,70)
    pushMatrix()
    translate(WIDTH/2,HEIGHT/2)
    rotate(math.deg(ang)+90)
    sprite(asset.builtin.Tyrian_Remastered.Plane_Boss,0,0)
    translate() 
    popMatrix()
end

function touched(t)
    if t.state==CHANGED then
        if t.x>x1-35 and t.x<x1+35 and t.y>y1-35 and t.y<y1+35 then
            ang=math.atan(t.y-y,t.x-x)
            x1=math.cos(ang)*65+x
            y1=math.sin(ang)*65+y
        end        
    end    
end

@dave1707 - cool, you need to format your post in the form thread, I think the ~~~ need a space in there. Could be because you copied my post as I tend to remove free space but there may be some invisible control characters missing if I deleted them.

Also had to add a multiplication sign in the last x1 and y1 lines for it to work.

The response is slower and doesn’t flip but it seems to lose contact occasionally. Thanks for the option I’ll play around with it.

By the way, where does the factor 65 fit in?

Edit: Just noticed the 65 is the x1 offset, but why is it used in the y1 offset later ?

Edit 2: Could you just check copying and pasting your original post (minus the ~~~ ) as I had trouble formatting the posted code in Codea. I tend to indent everything and it didn’t initially indent properly. Again, I think it’s control characters in the forum post that I may have deleted.

@Bri_G Sorry, I had a space before the last ~~~ . I was in a hurry when I posted it and didn’t check it again. Not sure about you’re adding the multiplication signs. The code runs OK as is when I copy and paste it. Losing contact of the small circle was the purpose. That prevents the 180 degree snap and makes you take your time rotating. As for the 65, that’s half the distance between the sizes of the 2 circles (200-70). That keeps the smaller circle touching the larger circle.

@dave1707 - when posted the code originally the multiply sign was omitted on both those lines. Could be a feature of the code formatting in the initial post.

Figured out your disconnect of the turn button from the rotate command. Thanks again.

@RonJeffries @Bri_G Here’s another version. Rotate your finger inside the circle in the direction you want the ship to rotate. When you lift your finger, the ship rotation will decrease to a stop. You can change the rotation speed (shipRot) to the speed you want.

PS. The ship rotates at a fixed speed no matter how fast you rotate your finger.

displayMode(FULLSCREEN)

function setup()
    xc,yc,radius=150,200,75
    screenAng,holdAng=0,0
    shipAng=0 
    shipRot=3
    noFill()
    stroke(255)
    strokeWidth(2) 
    shipInc=0
end

function draw()
    background(0)
    ellipse(xc,yc,radius*2)
    convert()
    pushMatrix()
    translate(WIDTH/2,HEIGHT/2)
    rotate(shipAng+90)
    sprite(asset.builtin.Tyrian_Remastered.Plane_Boss,0,0)
    translate() 
    popMatrix()
end

function touched(t)
    if t.state==CHANGED then
        turn=inCircle(t.x,t.y,xc,yc,radius)
        screenAng=math.deg(math.atan(t.y-yc,t.x-xc))//1
        x1=math.cos(math.rad(screenAng))*65+xc
        y1=math.sin(math.rad(screenAng))*65+yc
    end   
    if t.state==ENDED then
        turn=false
    end
end

function convert()
    shipInc=shipInc*.95
    shipAng=shipAng+shipInc
    if turn then
        if shipAng>180 then
            shipAng=shipAng-360
        end
        if screenAng>holdAng then
            shipInc=shipRot
        elseif screenAng<holdAng then
            shipInc=-shipRot
        end
        holdAng=screenAng
    end
end

function inCircle(x,y,xc,yc,a)
    if (x-xc)^2/a^2+(y-yc)^2/a^2 <= 1 then 
        return true
    end
    return false
end    

@dave1707 - very neat, I like that.

@RonJeffries - Asteroids31 - wow, the control was great and response very good. But, it will give me nightmares, progressed through several levels and it progressively gets very hard, tense!!! Fortunately you have infinite lives.

Suddenly remembered how crap I am when playing games!!

Thank you.

@dave1707 interesting, but jittery. i’m nearly convinced that your sliding idea was as good as any. also i was pleased not to need x1 and y1, as i couldn’t figure what they were about. :smiley:

@RonJeffries The x1,y1 variables were left over from code I removed when I was reworking the code. I was trying a lot of different combinations and didn’t realize I left those in once I got it working the way I wanted. So far with all the different things I tried, I find the up/down sliding for the rotation the easiest to use. I find It has the best control for ship rotation.

@RonJeffries - version 38 crashes on blammo - but not always. Image below showing error report.

yes sorry 39 should be ok

@RonJeffries Was looking at your code and noticed the two if dt > 0 statements. Not sure which one shouldn’t be there.

function Targeter:fireDirection()
    local dt = self:timeToTarget()
    if dt < 0 then return vec2(0,1) end
    if dt < 0 then return vec2(1,0):rotate(2*math.pi*math.random()) end
    local trueAimPoint = self.target.pos + self.target.step*dt
    local relativeAimPoint = trueAimPoint - self.saucer.pos
    local offsetAimPoint = relativeAimPoint - dt*self.saucer.step
    local dir = offsetAimPoint:normalize()
    return dir
end

first one just shoots straight up, put it in for debug, remove it for random shot. thanks!

@RonJeffries - very neat project you finished up with. Notice you moved on to Space Invaders, will watch this one closely as I recently tried to promote a minimal SI game as a communal project. Like the way you return to basics with the machine code versions.