I’ve hit a roadblock with my drone flight-simulator project and asking for a pointer or two to help get me back on track.
Description:
The drone is always located in the center of the screen. The point of view (POV) is always directly overhead. As you fly the drone the ground beneath translates and rotates giving the sensation of motion. All motion if controlled by two joysticks. Slight finger movement provides plenty of motion and motion stops when fingers are released.
At startup, fly the drone forward, backward, left and right by moving the RIGHT joystick up, down, left and right respectively. The ground appears to move opposite to the stick because in reality you are moving the ground and not the drone. The goal is that to fly the drone forward you push the RIGHT stick forward.
Next, yaw (rotate) the drone left and right by moving the LEFT stick left or right. Notice the ground rotating directly underneath the drone. Left stick provides altitude using scale so it’s a bit primitive.
The Problem:
If you try to translate the drone with the RIGHT stick AFTER yawing the drone with the LEFT stick the control is messed up by what appears to be an amount equal to the Yaw amount. As an example: If Yaw is -45 degrees the drone should be facing NorthWest. If you wish to move to the NorthWest you should only have to push the stick forward. But instead if I push the stick forward the drone moves North rather than NorthWest.
Creating an image of the ground then translating and rotating it ahead of the sprite call works great as long as the drone was headed North. Adding yaw into the mix throws everything off. The drone needs to fly in the direction the RIGHT stick is pushed.
I’ve struggled with this problem for about two weeks and would greatly appreciate any leads to solving this problem.
I’m running this on a 3rd gen (iOs = 9.3.5) iPad that’s getting close to ten years old. Too old for any Codea updates and unable to zip files.
I am looking forward to any advice offered.
Thank you very much.
Scotty
-- DroneSim V5
supportedOrientations(ANY)
displayMode(FULLSCREEN)
function setup()
X,Y = WIDTH/2, HEIGHT/2
LR,FB = 0,0
Alt,Yaw = 1,0
-- modes (stick sensitivity):
cine = .10
normal = .25
sport = .50
mode = normal
-- Set up common colors
commonColors()
-- JoyStick class setup:
JSYA = JoyStick(175, 200, green, "Yaw: < Left/Right >",
"Altitude: ^ Up/Down v")
JSFBLR = JoyStick(WIDTH-175,200,red, "Translate: < Left/Right >",
"Translate: ^ Forward/Backward v")
-- For ground definition
rows,cols,sizeGeo = 20,20,100
imgSize = vec2(cols*sizeGeo, rows*sizeGeo)
-- Create images using setContext()
createImageGround()
createImageDrone()
end
function draw()
background(40, 40, 50)
-- trig numbers (req'd?)
sinLR = math.sin(math.rad(Yaw)) -- x
cosFB = math.cos(math.rad(Yaw)) -- y
-- Left joystick:
Yaw=Yaw+JSYA.dX*mode/4
Alt=Alt-JSYA.dY*mode/1000
if Alt > 1 then Alt = 1 end
if Alt < .4 then Alt = .4 end
-- Right joystick:
LR=LR+JSFBLR.dX*mode -- left/right
FB=FB+JSFBLR.dY*mode -- foreward/backward
-- Manage ground image, landing zone and return-to-home line.
pushMatrix()
translate(X,Y)
rotate(Yaw)
pushMatrix()
scale(Alt) -- The illusion of altitude
sprite(myImageGround,-LR,-FB)
landingZone(-LR,-FB)
returnToHomeLine(-LR,-FB)
popMatrix()
popMatrix()
-- Drone is stationary while the ground moves underneath.
sprite(myImageDrone,X,Y) -- Drone w/o lights
drawDroneLights(X,Y) -- Lights w/o body
pushStyle()
fill(white)
fontSize(14)
text(string.format("%.f°",Yaw), X,Y+60)
popStyle()
-- Joysticks
JSYA:draw()
JSFBLR:draw()
-- Compass letters rotate around drone.
drawCompass()
end
function touched(t)
JSYA:touched(t)
JSFBLR:touched(t)
end
JoyStick = class()
--[[
JoyStick details:
-----------------
Left Stick:
U +altitude
D -altitude
L ccw yaw
R cw yaw
Right Stick:
U Foreward movement
D Backward movement
L Left movement
R Right movement
--]]
function JoyStick:init(x,y,clr,txt1,txt2)
self.x = x
self.y = y
self.clr = clr -- color
self.txt1 = txt1
self.txt2 = txt2
self.dia = 50
self.max = 25
self.dX = 0
self.dY = 0
self.id = {} -- touch id table
end
function JoyStick:draw()
pushStyle()
-- Escutcheon:
strokeWidth(4)
stroke(self.clr)
fill(black)
ellipse(self.x,self.y,self.dia)
-- Stick design:
fill(self.clr)
stroke(self.clr)
strokeWidth(10)
line(self.x, self.y, self.x+self.dX*.5, self.y+self.dY*.5)
fill(black)
strokeWidth(2)
ellipse(self.x+self.dX*.5, self.y+self.dY*.5, self.dia*.3)
ellipse(self.x+self.dX*.6, self.y+self.dY*.6, self.dia*.3)
-- Reference data and etc. that's not really important to the project:
fill(white)
text(string.format("(%.f, %.f)",self.dX,self.dY), self.x,self.y+self.dia)
text(self.txt1, self.x,self.y-self.dia)
text(self.txt2, self.x,self.y-self.dia*1.5)
popStyle()
end
function JoyStick:touched(t)
if vec2(t.x,t.y):dist(vec2(self.x,self.y)) <= self.dia*2 then
if t.state==BEGAN or t.state==MOVING then
table.insert(self.id,t.id)
-- Update deltas
self.dX=self.dX+t.deltaX
self.dY=self.dY+t.deltaY
-- Limit deltas to maximums
if self.dX> self.max then self.dX =self.max end
if self.dY> self.max then self.dY =self.max end
if self.dX<-self.max then self.dX=-self.max end
if self.dY<-self.max then self.dY=-self.max end
end
elseif vec2(t.x,t.y):dist(vec2(self.x,self.y)) > self.dia*2 or t.state==MOVING then
for z=#self.id,1,-1 do
if self.id[z]==t.id then
table.remove(self.id,z)
end
end
end
if t.state==ENDED then
-- Clear table
for z=#self.id,1,-1 do
if self.id[z]==t.id then
table.remove(self.id,z)
end
end
-- Kill motion of released joystick
if #self.id==0 then
self.dX=0
self.dY=0
end
end
end