How to make a circle orbit a touch point

How do I make a circle/ellipse orbit in a circle around a touch point?

Here’s a simple way

function setup()
    spritedist = 120
    spritesize = 30
    ellsize = 30
    ellipseloc = vec2(WIDTH/2,HEIGHT/2)
    spriteloc = ellipseloc+vec2(0,spritedist)
    tid = nil
    col = color(0,0,255)
end
function draw() 
    background(40, 40, 50)
    fill(255,0,0)
    ellipse(ellipseloc.x,ellipseloc.y,ellsize)
    fill(col)
    ellipse(spriteloc.x,spriteloc.y,spritesize)    
end
function touched(t)
    if spriteloc:dist(vec2(t.x,t.y)) < spritesize/2+5 and t.state == BEGAN then
        tid = t.id
        col = color(0,255,0)
    elseif t.state == MOVING and t.id == tid then
        local ang = math.atan2(t.y-ellipseloc.y,t.x-ellipseloc.x)
        spriteloc = vec2(0,spritedist):rotate(ang-(math.pi/2))+ellipseloc
    elseif t.state == ENDED and t.id == tid then
        tid = nil
        col = color(0,0,255)
    end
end

EDIT: I reread your question and think that my original post is not what you want. Please hold while I slap myself and write another

Here, I THINK this is what you actually meant. Correct me if I’m wrong and I’ll go try again :stuck_out_tongue:

function setup()
    print("Hello World!")
    anglerad =0
    angleaddrad = 0
    lasso = nil
    oid = nil
    lassolength = nil
    shiploc = vec2(WIDTH/2,HEIGHT/2)
    simpveloc = 3
    shipVelocity = vec2(simpveloc,0)
    ctype = 1 --(change to 0 for orbit to change with finger moving)
end
function draw()
    background(255)
    clacloc()
    fill(0,0,255)
    ellipse(shiploc.x,shiploc.y,30)
    if lasso then
    ellipse(lasso.x,lasso.y,10)
    end
end
function touched(t)
    if t.state == BEGAN and not oid then
        oid = t.id
        initlasso(t)
    end
    if t.state == MOVING and oid == t.id then
        if ctype == 0 then
        initlasso(t)
        end
    end
    if t.state == ENDED and oid == t.id then
        lasso,angleaddrad,lassolength,oid = nil,0,nil,nil
    end
end
function initlasso(t)
    lassolength = vec2(t.x,t.y):dist(shiploc)
    lasso = vec2(t.x,t.y)
    local circumf = 2*math.pi*lassolength
    angleaddrad = 2*math.pi*simpveloc/circumf
    local offset = lasso - shiploc
    local anglebet = math.atan2(offset.y,offset.x)
    local tangent = anglebet - (math.pi/2)
    if (anglerad - anglebet)%(2*math.pi) > math.pi then
        anglerad = tangent
        else
        anglerad = tangent + math.pi
        angleaddrad = -angleaddrad
    end
end
function clacloc()
    if lasso ~= nil then
        anglerad = anglerad+ angleaddrad
    end
    if lasso ~= nil then
        shiploc = lasso + (shiploc - lasso):rotate(angleaddrad)
    else
        shiploc = shipVelocity:rotate(anglerad) + shiploc
    end
end

@Monkeyman32123, no need for such complex code. All you need is a little trigonometry :slight_smile:

@Acithium, here is a much shorter / easier way of doing it:

-- Orbit

function setup()
    orbitCenter = vec2(WIDTH / 2, HEIGHT / 2)
    orbitRad = WIDTH / 8
    orbitAngle = 0
    angleIncrement = .1
end

function draw()
    background(40, 40, 50)

    fill(255, 251, 0, 255) noStroke()
    ellipse(orbitCenter.x, orbitCenter.y, 10)
    
    fill(255, 0, 0, 255) 
    local outX = orbitCenter.x + orbitRad * math.cos(orbitAngle)
    local outY = orbitCenter.y + orbitRad * math.sin(orbitAngle)
    ellipse(outX, outY, 35)
    
    orbitAngle = orbitAngle + angleIncrement
end

function touched(t)
    orbitCenter = vec2(t.x, t.y)
end

@JakAttak You could also use vec2.rotate, which might be a bit less confusing than trigonometry.

-- Orbit

-- Use this function to perform your initial setup
function setup()
    print("Hello World!")
    center = vec2(0, 0)
    offset = vec2(100, 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
    ellipse(center.x + offset.x, center.y + offset.y, 50)
    offset = offset:rotate(DeltaTime * 5)
end

function touched(touch)
    center.x, center.y = touch.x, touch.y
end

@SkyTheCoder, nice, I didn’t know about that.

@JakAttak
I realize there are easier ways to do rotation around a point (and I often use them myself), but the reason I made mine so complex is because he said an orbit, which, to me at least, makes me think of a gravitational pull. Therefore, I made mine so that the circle would orbit clockwise or counter-clockwise around the touch depending on the origin of the touch point (hence the seemingly needless complexity). Of course, it’d be much simpler to make it rotate in one direction only, but I wasn’t sure what he wanted so I gave what I wanted when I asked this very same question so long ago :stuck_out_tongue:

@Monkeyman32123, Well even to be able to rotate clockwise / counter-clockwise depending in the touch, I would only need to add 2/3 lines.

Oh, my apologies then dear sir. Well, in that case go tell @Andrew_Stacey you’ve found a better way, as he is the one who helped me make it go clockwise and counter-clockwise :stuck_out_tongue: (and, knowing him, he’d love a way to increase his vast library of general knowledge). But I don’t want to go tell him, his dominating intelligence in the subject of Maths intimidates me. ._.

@Monkeyman32123, LOL. If you wanted to add rotation going both directions, you take my (or @SkyTheCoder’s code) and you add a variable for the direction to turn (1 or -1) which you multiply by the angleIncrement in my code, or the rotation amount in his code.

Then you just need the code in touched function to determine whether that variable should be 1 or -1

@JakAttak if you actually analyse @Monkeyman32123’s code then you’d see that the bit that draws the orbiting ellipse is essentially the same as yours and @SkyTheCoder’s so less of the “it’s pretty simple really” language, please! The extra length in Monkeyman32123’s code is in figuring out what happens if you a) move the touch and b) stop touching and retouch somewhere else. Yours and SkyTheCoder’s code is a bit simplistic there and will simply move the orbiter and maintain the same direction. Monkeyman32123’s ensures that the orbiter moves in a reasonably natural path.

It’s true that this probably is more complicated than @Acithium wants, but unless (s)he explains further then it’s hard to know.

@Andrew_Stacey, you are right I see he is using the rotate function as well :slight_smile:

Here’s a version that allows multiple orbits. The center is the beginning touch point and the radius is the ending touch point. Also, the orbit speed is determined by the radius size. Keep creating multiple orbits, at least 100.

EDIT: added color
EDIT: added orbit count


displayMode(FULLSCREEN)

function setup()
    tab={}
    mov=false
    dir=1
end

function draw()
    background(40, 40, 50)
    fill(255)
    text("tap for center and drag for radius size",WIDTH/2,HEIGHT-50)
    text("number of orbits  "..#tab,WIDTH/2,HEIGHT-100)
    if mov then
        stroke(255)
        strokeWidth(2)
        line(cx,cy,mx,my)
    end
    for a,b in pairs(tab) do
        b:draw()
    end
end

function touched(t)
    if t.state==BEGAN then
        cx=t.x
        cy=t.y
    end
    if t.state==MOVING then
        mov=true
        mx=t.x
        my=t.y
    end
    if t.state==ENDED then
        dir=dir*-1
        mov=false
        v1=vec2(cx,cy)
        rad=v1:dist(vec2(t.x,t.y))
        ang=math.atan2(t.y-cy,t.x-cx)
        table.insert(tab,orb(cx,cy,rad,ang))
    end
end

orb=class()

function orb:init(cx,cy,rad,ang)
    self.cx=cx
    self.cy=cy
    self.rad=rad  
    self.ang=ang 
    self.inc=rad/3000*dir
    self.col=color(math.random(255),math.random(255),math.random(255))
end

function orb:draw()
    self.x=self.cx+self.rad*math.cos(self.ang)
    self.y=self.cy+self.rad*math.sin(self.ang)
    fill(self.col)
    stroke(self.col)
    strokeWidth(2)
    ellipse(self.cx,self.cy,5)
    ellipse(self.x,self.y,20) 
    line(self.cx,self.cy,self.x,self.y)
    self.ang=self.ang+self.inc
end

Here, here’s a version where I took the question far too literally

displayMode(OVERLAY)
displayMode(FULLSCREEN)
backingMode(RETAINED)
function setup()
    mpp = 2000000
    gravity = false
    g = 6.674*(1/(10^11))
    planets = {}
    planets[#planets+1]=Planet(vec2(WIDTH/2,HEIGHT/2),5.97219*(10^25))
    planets[#planets+1]=Planet(vec2(WIDTH/2,HEIGHT/2+(384400000/mpp)),7.34767309*(10^22),1737.4,vec2(.8*2,0))
    for i=1, 30 do
        --planets[i] = Planet(nil, math.random(0,1000)*(10^23))
    end
    alive = true
    oid = nil
end
function draw()
    if alive then
        background(255)
    end
    if alive then
        for i=1,#planets do
            planets[i]:gravcal()
        end
        for i=1,#planets do
            planets[i]:draw()
        end
    else
        restart()
    end
    if alive then
    local count = 0
    for i=1, #planets do
        if not planets[i].alive then
            count = count + 1
        end
    end
    if count == #planets then
        alive = false    
    end
    end
end
function touched(t)
    if alive then
        if t.state == BEGAN and planets[1].locv:dist(vec2(t.x,t.y)) < 22 and not oid then
            oid = t.id
            elseif oid == t.id then
            planets[1].locv = vec2(t.x,t.y)
            if t.state == ENDED then
                oid = nil
                if math.sqrt(t.deltaX^2+t.deltaY^2)>3 then
                    planets[1].vel = vec2(t.deltaX,t.deltaY)
                    else
                    planets[1].vel = vec2(0,0)
                end
            end
        end
    end
end
Planet = class()
function Planet:init(loc,kg,radkm,vel)
    self.locv = loc or vec2(math.random(0,WIDTH),math.random(0,HEIGHT))
    self.mass = kg or 5.97219*(10^24)
    self.rad = radkm or 6378.1
    self.radpix= (self.rad*1000)/mpp
    self.vel = vel or vec2(0,0)
    self.alive = true
end
function Planet:draw()
    if self.alive then
        self.locv = self.locv + self.vel
        fill(0)
        ellipse(self.locv.x,self.locv.y,self.radpix*2+11)
    end
end
function Planet:gravcal()
    for i=1, #planets do
        if planets[i].alive and self.alive then
            if self.locv ~= planets[i].locv then
                local f=(g*self.mass*planets[i].mass)/((self.locv:dist(planets[i].locv)*mpp)^2)
                local a=vec2(f/self.mass,0)
                local offsx = planets[i].locv.x-self.locv.x
                local offsy = planets[i].locv.y-self.locv.y
                local ang = math.atan2(offsy,offsx)
                self.vel = self.vel + a:rotate(ang)
                if planets[i].locv:dist(self.locv) < 11 then
                    self.alive = false
                    planets[i].alive = false
                    return
                end
            end
        end
    end
end

im seriously behind on math…

@Monkeyman32123 - Thanks for the code snippets. I was working on faux-planetary orbits, and your code really helped out. I’m with @Weisdendarm - seriously behind on math.

@athros thanks, glad I could help! :smiley:
I just learned about calculating planetary orbit radii, orbit velocities, orbit periods, and gravitational accelerations in my physics class and decided to make a little mini-solar-system out of it, and so the code was born.
And it’s ok, I’m seriously behind on math too. If it weren’t for Andrew_stacey I’d still be trying to figure out angles to this very day

@Monkeyman32123 Do a forum search for orbits. There are several programs that already do orbit calculations. Maybe those will help out.

@dave1707 but…what’s wrong with mine :c

@Monkeyman32123 - I have a friend who asked me for a game (something like Conquest: Frontier Wars with some realistic system movement, or Aurora) and I’ve been exploring it with Codea.