Drone Simulator Misbehaving

@Scotty - in short I used your code, listing attached - change the names to avoid clash with other project. The compass I drew myself, needs a little adjustment.


— Landing

function setup()
    --
    X,Y = WIDTH/2, HEIGHT/2
    commonColors()
    createImageDrone()
    landingZone()
    drawDroneLights()
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)
    sprite(land,WIDTH//2,HEIGHT//2)
    sprite(drone,WIDTH//2,HEIGHT//4)
end

function landingZone()
    local size = 50
    land = image(size,size)
    setContext(land)
        pushMatrix()
            translate(size//2,size//2)
            pushStyle()
                rectMode(CENTER)
                strokeWidth(0)
                fill(orange)
                rect(0,0, size)
                fill(white)
                rect(0,0, size*.8)
                fill(black)
                fontSize(size*.6)
                font("Arial-BoldMT")
                text("H", 0,0)
                text("_", 0,0)
            popStyle()
        popMatrix()
    setContext()
    saveImage(asset.documents.."landing",land)
end

function createImageDrone()
    -- Creates an image that represents the drone w/o lights
    myImageDrone = image(X,Y)
    setContext(myImageDrone)
        drawDroneBody()
    setContext()
    saveImage(asset.documents.."drone2",drone)
end

function drawDroneBody(x,y)
    -- Image of drone w/o lights.
    local x,y = x,y
    local mSize = 50
    local size = 110
    local droneColor = gray
    drone = image(size,size)
    setContext(drone)
        pushMatrix()
            translate(size//2,size//2)
            pushStyle()
                -- arms
                lineCapMode(ROUND)            
                stroke(droneColor)  
                fill(droneColor)
                for i=1,4 do
        --  background(255)
                    rotate(90)
                    strokeWidth(mSize*.2)
                    stroke(black)
                    line(0,0, mSize*.625,mSize*.625)
                    strokeWidth(mSize*.15)
                    stroke(droneColor)
                    line(0,0, mSize*.625,mSize*.625)
                    strokeWidth(mSize*.01)
                    fill(170, 170, 170, 74)
                    ellipse(mSize*.625,mSize*.625, 50)
                    fill(black)
                    ellipse(mSize*.625,mSize*.625, 6)
                end
                -- body outline
                stroke(black)
                strokeWidth(mSize*.275)
                line(-mSize*.13, -mSize/2, -mSize*.09, mSize/2) -- l
                line( mSize*.13, -mSize/2,  mSize*.09, mSize/2) -- r
                line(-mSize*.13, -mSize/2,  mSize*.09,-mSize/2) -- b
                line(-mSize*.09,  mSize/2,  mSize*.09, mSize/2) -- t
                -- body
                stroke(droneColor)
                strokeWidth(mSize*.2)
                line(-mSize*.13, -mSize/2, -mSize*.09, mSize/2) -- l
                line( mSize*.13, -mSize/2,  mSize*.09, mSize/2) -- r
                line(-mSize*.13, -mSize/2,  mSize*.09,-mSize/2) -- b
                line(-mSize*.09,  mSize/2,  mSize*.09, mSize/2) -- t
                strokeWidth(mSize*.1)
                line(0,-mSize/2, 0,mSize/2) -- fill in what got missed         
                popStyle()
                -- forward arrow
                pushStyle()
                stroke(black)
                strokeWidth(3)
                lineCapMode(ROUND)
                line(0,30, 0,-20)
                line(0,30, 5,0)
                line(0,30, -5,0)
            popStyle()    
        popMatrix()
    setContext()
end

function drawDroneLights()
    -- Drone's flashing lights.
    local x,y = x,y
    local mSize = 60
    local droneColor = gray
    setContext(drone)
    pushMatrix()
        translate(55,100)
        pushStyle()
            -- tail light outline
            strokeWidth(2)
            stroke(black)
         --   line(-6,-mSize/2-48, 6,-mSize/2-48)
            -- head light outline
            fill(white)
           ellipse(0,mSize/2-44, 12)
         --   myTimer(2)
            -- tail light
            strokeWidth(5)
        --    line(-8,-mSize/2-8, 8,-mSize/2-8)
            stroke(black)
            -- head light
          --  ellipse(-4,mSize/2-108, 4,16)
            line(-8,-76,8,-76)
            stroke(green)
            strokeWidth(4)
            line(-7,-76,7,-76)
        popStyle()
    popMatrix()
    setContext()
    saveImage(asset.documents.."droneLit",drone)
end

function commonColors()
    red    = color(209,0,0,255)
    orange = color(255,102,34,255)
    yellow = color(255,218,33,255)
    green  = color(51, 221, 0, 255)
    blue   = color(16, 51, 204, 255)
    white  = color(255, 255, 255, 255)   
    gray   = color(127, 127, 127, 255)
    black  = color(0, 0, 0, 255)    
    brown  = color(165, 40, 41, 255)
end

@Scotty Here’s my original example that might be closer to what you’re after. The drone can move forward or backward (up or down), but not side to side yet. You can rotate the ground under the drone and the drone will still go forward or backward. To move the drone, move your finger up or down on the top half of the screen. To rotate the ground, move your finger side to side on the bottom half of the screen. The drone will continue to move if you lift your finger. To stop the drone, double tap on the top half of the screen.

PS. I think I know how to move the drone side to side too. I’ll work on that next.

viewer.mode=FULLSCREEN

function setup()
    rectMode(CENTER)
    ground=image(4000,4000)
    setContext(ground)
    background(236, 174, 67)
    stroke(255)
    strokeWidth(2)
    for x=1,4000,50 do
        for y=1,4000,50 do
            line(x,y,x,HEIGHT)
            line(x,y,WIDTH,y)
        end
    end    
    fill(255)
    noStroke()
    rect(2000,2000,60)
    fill(255,0,0)
    fontSize(50)
    text("H",2000,2000)
    text("N",2000,2200)
    text("S",2000,1800)
    setContext()
    
    sx,sy=0,0
    x,y=0,0
    dx,dy=0,0
    ang=0
end

function draw()
    background()    
    pushMatrix()
    translate(WIDTH/2,HEIGHT/2)
    rotate(ang)
    sprite(ground,x,y)
    popMatrix()
    sprite(asset.builtin.Tyrian_Remastered.Twisted,WIDTH/2,HEIGHT/2)  
    calc() 
end

function calc() 
    ang=ang%360
    if ang>=315 then
        ang1=360-ang
        x=x+math.tan(math.rad(ang1))*dy
        y=y-dy
    elseif ang>=225 and ang<315 then
        ang1=270-ang
        y=y+math.tan(math.rad(ang1))*dy
        x=x+dy
    elseif ang>=135 and ang<225 then
        ang1=180-ang
        x=x-math.tan(math.rad(ang1))*dy
        y=y+dy
    elseif ang>45 and ang<135 then
        ang1=90-ang
        y=y-math.tan(math.rad(ang1))*dy
        x=x-dy
    elseif ang<=45 then
        ang1=ang
        x=x-math.tan(math.rad(ang1))*dy
        y=y-dy
    end
end

function touched(t)
    if t.y<HEIGHT/2 then
        ang=ang-t.deltaX
    end
    if t.y>HEIGHT/2 then
        if t.state==BEGAN then
            sx=t.x
            sy=t.y
        elseif t.state==CHANGED then
            dx=(sx-t.x)/40
            dy=-(sy-t.y)/40
        elseif t.state==ENDED and t.tapCount==2 then
            dx,dy=0,0
        end          
    end      
end

@Scotty Here’s the latest example for the drone movement. You can now move in any direction and rotate the ground under the drone. Some changes for this example. Move up/down/left/right on right side of screen. Rotate ground by moving up/down on left side of screen. Drone continues to move when your finger is lifted. Double tap to stop drone.

All the calculations are done in calcUDLR, so you can move that to your code and work it with your joysticks.

viewer.mode=FULLSCREEN

function setup()
    rectMode(CENTER)
    ground=image(4000,4000)
    setContext(ground)
    background(236, 174, 67)
    stroke(255)
    strokeWidth(2)
    for x=1,4000,50 do
        for y=1,4000,50 do
            line(x,y,x,HEIGHT)
            line(x,y,WIDTH,y)
        end
    end    
    fill(255)
    rect(2000,2000,60)
    fill(255,0,0)
    fontSize(50)
    text("H",2000,2000)
    text("N",2000,2200)
    text("S",2000,1800)
    setContext()
    
    sx,sy,x,y,dx,dy,ang=0,0,0,0,0,0,0
end

function draw()
    background()   
     
    pushMatrix()
    translate(WIDTH/2,HEIGHT/2) -- center of screen
    rotate(ang)
    sprite(ground,x,y)
    popMatrix()
    
    sprite(asset.builtin.Tyrian_Remastered.Twisted,WIDTH/2,HEIGHT/2)  
    calcUDLR() 
end

function calcUDLR()   -- calculate x,y movement based on angle and direction
    ang=ang%360    
    if ang<=45 then
        ang1=ang
        x=x-math.tan(math.rad(ang1))*dy+dx
        y=y-math.tan(math.rad(ang1))*dx-dy
    elseif ang>=45 and ang<135 then
        ang1=90-ang
        y=y-math.tan(math.rad(ang1))*dy-dx
        x=x+math.tan(math.rad(ang1))*dx-dy
    elseif ang>=135 and ang<225 then
        ang1=180-ang
        x=x-math.tan(math.rad(ang1))*dy-dx
        y=y-math.tan(math.rad(ang1))*dx+dy
    elseif ang>=225 and ang<315 then
        ang1=270-ang
        y=y+math.tan(math.rad(ang1))*dy+dx
        x=x-math.tan(math.rad(ang1))*dx+dy
    elseif ang>=315 then
        ang1=360-ang
        x=x+math.tan(math.rad(ang1))*dy+dx
        y=y+math.tan(math.rad(ang1))*dx-dy
    end
end

function touched(t)
    if t.tapCount==2 then
        dx,dy=0,0
    end          
    if t.x<WIDTH/2 then -- change angle based on y changes
        ang=ang-t.deltaY/2
    end
    if t.x>WIDTH/2 then
        if t.state==BEGAN then  -- start x,y values
            sx=t.x
            sy=t.y
        elseif t.state==CHANGED then    -- calc change in touch
            dx=(sx-t.x)/40
            dy=-(sy-t.y)/40
        end

    end      
end

@dave1707 , @Bri_G

This is indeed getting close to the mark.

I’ve mashed Dave’s example, which includes calcUDLR(), with Bri’s. I’ve put in my touched() code so rotate and translate are controlled by left and right fingers respectively. When fingers are released motion stops.

I made some minor tweeks noted by lowercase “spg” that dose not change the overall by much. Has to do more with trading screen numbers for WIDTH or HEIGHT. I changed some sprite calls due to my ancient iPad. That sort of thing.

A more CONSEQUENTIAL change is noted by uppercase “SPG”. This has all to do with moving the ground is under the driver.

The one sticky thing still remaining is diagonal motion seems to be off by about 90°.

I hope my explanation makes sense.

Thanks again for all the help and have a HAPPY THANKSGIVING.

--viewer.mode = FULLSCREEN
displayMode(FULLSCREEN)

function setup()
    X,Y = WIDTH//2,HEIGHT//2
    
    --ground=image(1536,2048)
    ground=image(WIDTH*2,HEIGHT*2)
    setContext(ground)
    background(145, 164, 185, 255)
        spriteMode(CENTER)
        --sprite(asset.builtin.Blocks.Leaves,768,1024,1536,2048)
        stroke(255)
        strokeWidth(2)
        for x=1,WIDTH*2,64 do -- spg
            for y=1,HEIGHT*2,64 do -- spg
                line(x,y,x,HEIGHT)
                line(x,y,WIDTH,y)
            end
        end
        fill(255,0,0)
        spriteMode(CENTER)
        --sprite(asset.landing,768,1024) --bg
        sprite("Project:landing",WIDTH,HEIGHT) --spg
    setContext()
    
    x,y=0,0
    dx,dy=0,0
    da,ang=0,0
end

function draw()
    --
    background()
    pushMatrix()
        spriteMode(CENTER)
        --translate(WIDTH/2+x,HEIGHT/2+y) --bg
        translate(WIDTH/2,HEIGHT/2) --SPG
        ang=ang+da
        rotate(ang)
        --sprite(ground, 0,0) --bg
        sprite(ground, -x,-y)  --SPG
    popMatrix()
    
    pushMatrix()
        --translate(704,964) --bg
        translate(WIDTH/2,HEIGHT/2+200) --spg
        rotate(ang)
        --sprite(asset.Compas3,0,0,108,100) --bg
        sprite("Project:Compas3",0,0, 108,100) --spg
    popMatrix()
    
    fill(255)
    textMode(CENTER)
    --text("Angle : "..ang,664,884) --bg
    text(string.format("Angle: %.f",ang),WIDTH/2,HEIGHT/2+125) --spg
    myTimer(2)
    
    calcUDLR()
end

function touched(t)
    --Left (rotation)
    local max = 2
    if t.x<WIDTH/2 then
        da=da-t.deltaX/10
        if da> max then da= max end
        if da<-max then da=-max end
        if t.state==ENDED then da=0 end          
    end
    --Right (translation)   
    if t.x>WIDTH/2 then
        dx=dx-t.deltaX/10
        dy=dy-t.deltaY/10
        if dx> max then dx= max end
        if dy> max then dy= max end
        if dx<-max then dx=-max end
        if dy<-max then dy=-max end
        if t.state==ENDED then dx,dy=0,0 end          
    end
end

function myTimer(dT)
    -- The work of others.    
    local dT = dT -- How often we want to see change happen.
    local eT = math.floor(ElapsedTime) 
    if math.fmod(eT,dT) == 0 then
        --sprite(asset.drone2,X,Y) --bg
        sprite("Project:drone2",X,Y) --spg
    else
        --sprite(asset.droneLit,X,Y) --bg
        sprite("Project:droneLit",X,Y) --spg
    end
end

function calcUDLR()   -- calculate x,y movement based on angle and direction
    ang=ang%360 
    if ang<=45 then
        ang1=ang
        x=x-math.tan(math.rad(ang1))*dy+dx
        y=y-math.tan(math.rad(ang1))*dx-dy
    elseif ang>=45 and ang<135 then
        ang1=90-ang
        y=y-math.tan(math.rad(ang1))*dy-dx
        x=x+math.tan(math.rad(ang1))*dx-dy
    elseif ang>=135 and ang<225 then
        ang1=180-ang
        x=x-math.tan(math.rad(ang1))*dy-dx
        y=y-math.tan(math.rad(ang1))*dx+dy
    elseif ang>=225 and ang<315 then
        ang1=270-ang
        y=y+math.tan(math.rad(ang1))*dy+dx
        x=x-math.tan(math.rad(ang1))*dx+dy
    elseif ang>=315 then
        ang1=360-ang
        x=x+math.tan(math.rad(ang1))*dy+dx
        y=y+math.tan(math.rad(ang1))*dx-dy
    end
end

@Scotty To fix the movement being off, make this change in your touched function.
Make it a + instead of a - .

        dx=dx+t.deltaX/10

@dave1707, @Bri_G and if you change

        sprite(ground, x,y)  --SPG

to

        sprite(ground, -x,-y)  --SPG

in draw() I believe it will then work perfectly.

I’ll see if I can apply these concepts to my original drone project and see what happens.

Thank you very much for all the help.

And change

        da=da-t.deltaX/10

to an addition operation in touched()

        da=da+t.deltaX/10

That should do it.