Unusual gravity settings

Hello there,

Your help was very valuable yesterday, and I’m moving right along in my first little project. I’m having a lot of fun with codea, I must say.

I’m now trying to change gravity setting so it fits my (special) needs. I’m trying to get my bodies not to be attracted out at the bottom of the screen, but rather outward from the centre of the screen.

I’ve been looking, with no success, at a way to set the general attraction point to the middle of the screen, to then, I hoped, multiply the force by -1 to have objects be repelled from the centre.

Is there a straight forward way to achieve this?

Also, I’d like my bodies to repel each other. Again, I haven’t got a good idea on how to achieve this, any help would be very welcome!

Cheers!

Ps. Next move, camera!

Gravity is always towards the bottom of the screen, no option to change it to the middle.

Just do a simple test. If pos.x > width/2 then pos.x + 1 else pos.x - 1 end and the same for y coord of an object, If pos.y > height/2 then pos.y + 1 else pos.y - 1 end

No need to use gravity necessarily.

Oh ok, thanks. I kind of wanted a force field effect, but I’ll try to work around it. Cheers!

@Rodolphe Maybe something like this might be of interest. I’m not sure what you’re really after, but I thought I’d post this anyways.


displayMode(FULLSCREEN)
supportedOrientations(PORTRAIT_ANY)

function setup()
    force=physics.body(CIRCLE,75)
    force.x=WIDTH/2
    force.y=HEIGHT/2
    force.type=STATIC    
    force.sleepingAllowed=false  
    object1 = {}
    for z=1,40 do
        a=physics.body(CIRCLE,30)
        a.x=math.random(WIDTH)
        a.y=math.random(HEIGHT)
        a.gravityScale=0
        a.sleepingAllowed=false  
        table.insert(object1,a)
    end    
end

function draw()
    background(255, 167, 0, 38)
    if not moveToCenter then
        fill(255)
        text("tap screen",WIDTH/2,HEIGHT/2)
    else
        fill(255)
        text("force field up",WIDTH/2,HEIGHT/2)
        noFill()
        stroke(255)
        strokeWidth(3)
        ellipse(force.x,force.y,150)
    end
    for i,v in ipairs(object1) do
        if moveToCenter then
            move=center - vec2(v.x, v.y)   
            if move:len() > 10 then
                move = move:normalize()
            end
            v.x = v.x + move.x
            v.y = v.y + move.y
        end
        sprite("Planet Cute:Character Boy", v.x, v.y, 30)
    end
end

function touched(touch)
    if touch.state==BEGAN then
        moveToCenter=true
        center=vec2(WIDTH/2,HEIGHT/2)
    end
end

Hello @rodolphe.
I have tweeked Dave’s code above to add a gravity source to the center (and walls around).
The gravity is correct (within the limits of physics engine: too much propulsion when the planet commes too close to the center).


displayMode(FULLSCREEN)

function setup()
    edges = {}
    edges[1] = physics.body(EDGE,vec2(WIDTH,HEIGHT),vec2(0,HEIGHT))
    edges[2] = physics.body(EDGE,vec2(WIDTH,HEIGHT),vec2(WIDTH,0))
    edges[3] = physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
    edges[4] = physics.body(EDGE,vec2(0,0),vec2(WIDTH,0))
    for i,v in pairs(edges) do v.restitution = 0.9 end
    object1 = {}
    for z=1,40 do
        a=physics.body(CIRCLE,30)
        a.x=math.random(WIDTH)
        a.y=math.random(HEIGHT)
        a.gravityScale=0
        a.sleepingAllowed=false  
        table.insert(object1,a)
    end    
end

function draw()
    background(255, 167, 0, 38)
    if not moveToCenter then
        fill(255)
        text("tap screen",WIDTH/2,HEIGHT/2)
    else
        fill(255)
        text("force field up",WIDTH/2,HEIGHT/2)
        noFill()
        stroke(255)
        strokeWidth(3)
    end
    local grav,dist
    for i,v in ipairs(object1) do
        if moveToCenter then
            grav=center - vec2(v.x, v.y)   
            dist = grav:len()
            if dist < 1 then dist = 1 end
            grav = grav / (dist*dist*dist) * 100000
            v:applyForce(grav)
        end
        sprite("Planet Cute:Character Boy", v.x, v.y, 30)
    end
end

function touched(touch)
    if touch.state==BEGAN and not(moveToCenter) then
        moveToCenter=true
        center=vec2(WIDTH/2,HEIGHT/2)
        for i,v in ipairs(object1) do
            v.linearVelocity = vec2(math.random(100)-50, math.random(100)-50)   
        end
    end
end

And here is another progam i found on the forum (cant remember who posted it, sorry).
There are more explanations.


--# Main


displayMode(FULLSCREEN)
--supportedOrientations(PORTRAIT)

function setup()
    leaveTrails = false
    if leaveTrails then
        backingMode(RETAINED)
    end
    bodies = {}

    setup = 1

    if setup == 1 then
        --solar system
        --gravitation constant for scaling
        G = .005
        --initial planets
        --sun
        bodies[1] = { m= 40000, x = WIDTH/2, y= HEIGHT/2, dx=0, dy=0 }
        --planets
        bodies[2] = { m= 15, x = WIDTH/2, y= HEIGHT/2 - 65, dx= 1.8, dy = 0 }
        bodies[3] = { m= 20, x = WIDTH/2, y= HEIGHT/2 - 100, dx=1.5, dy=0 }
        bodies[4] = { m= 30, x = WIDTH/2, y= HEIGHT/2 - 150, dx=1.3, dy=0 }
        bodies[5] = { m= 40, x = WIDTH/2, y= HEIGHT/2 - 180, dx=1.2, dy= 0}
        bodies[6] = { m= 60, x = WIDTH/2, y= HEIGHT/2 - 300, dx=0.85, dy= 0 }
        --moons
        bodies[7] = { m= 0.1, x = WIDTH/2, y= HEIGHT/2 - 155, dx= 1.47, dy= 0 }
    end

    if setup == 2 then
        --2 planets and a moon
        G = 1
        --initial planets
        bodies[1] = { m = 400, x= 300, y= 500, dx = 1.4, dy = .4 }
        bodies[2] = { m = 400, x= 300, y= 600, dx = -1.4, dy = -.4 }
        bodies[3] = { m = 4, x = 300, y= 480, dx = -3.1, dy = .4 }
    end

    selectedBody = 1
end

function touched(touch)
    if touch.state == BEGAN then
        if touch.x > WIDTH - 100 and touch.y < HEIGHT - 85 and touch.y > HEIGHT - 125 then
            --touched slower
            bodies[selectedBody].dx = bodies[selectedBody].dx * .9
            bodies[selectedBody].dy = bodies[selectedBody].dy * .9 
        elseif touch.x > WIDTH - 100 and touch.y < HEIGHT - 140 and touch.y > HEIGHT - 180 then
            --touched faster
            bodies[selectedBody].dx = bodies[selectedBody].dx * 1.1
            bodies[selectedBody].dy = bodies[selectedBody].dy * 1.1
        else
            --change slected planet if touch is with 100 of it
            closest = nil
            dist = 100
            for k,v in pairs(bodies) do
                calcDist = math.sqrt((touch.x - v.x)^2+(touch.y - v.y)^2)
                if  calcDist < dist then
                    dist = calcDist
                    closest = k
                end
            end
            if closest ~= nil then
                selectedBody = closest
            end
        end    
    end
end

function draw()
    if leaveTrails == false then
        background(40,40,50)
    end
    strokeWidth(0)
    fill(255)

    applyGravity()

    moveBodies()

    -- plot bodies
    for k,v in pairs(bodies) do
        if selectedBody == k then
            fill(255, 9, 0, 255)
        else
            fill(255,255,255,255)
        end
        ellipse(v.x, v.y, math.pow(v.m, .2)*2 + 2)
    end

    drawControl()
end

function drawControl()
    fill(255,255,255,255)
    text(string.format("Body: %d", selectedBody), WIDTH - 50, HEIGHT - 50)    
    fill(150,150,150,255)
    rect(WIDTH - 100, HEIGHT - 125, 100, 40)
    rect(WIDTH - 100, HEIGHT - 180, 100, 40)
    fill(255,255,255,255)
    text("slower", WIDTH - 50, HEIGHT - 105)
    text("faster", WIDTH - 50, HEIGHT - 160)
    v = math.sqrt(bodies[selectedBody].dx^2+bodies[selectedBody].dy^2)
    text(string.format("Velocity: %f", v), WIDTH - 100, HEIGHT - 200)
end

function applyGravity()
    for k,v in pairs(bodies) do
        for k2,v2 in pairs(bodies) do
            if k2 > k then
                --gravity factor - this is distance facotring for gravity and trigonometry
                d = 1 / math.pow(( (v.x - v2.x)^2 + (v.y - v2.y)^2), 1.5)

                --adjust v velocity
                v.dx = v.dx - (v.x - v2.x) * d * v2.m * G
                v.dy = v.dy - (v.y - v2.y) * d * v2.m * G

                --adjust v2 velocity
                v2.dx = v2.dx - (v2.x - v.x) * d * v.m * G
                v2.dy = v2.dy - (v2.y - v.y) * d * v.m * G
            end
        end
    end
end

function moveBodies() 
    for k,v in pairs(bodies) do
        v.x = v.x + v.dx
        v.y = v.y + v.dy
    end
end

I was one of the posters, here’s a link to the post. There were other links I had also on orbit simulations. http://www.twolivesleft.com/Codea/Talk/discussion/2018/using-physics-to-simulate-moon-in-orbit-around-planet/p1

This is all excellent, thanks a lot! From all this great code, I’m pretty sure I can manage to invert the force field in order to gently repel objects from the centre of the screen. Cheers !

Oops, codea crashes consistantly when I try to set the gravity to zero (see main in physics lab examples, I just force 0 gravity), as such :

defaultGravity = physics.gravity(0,0) (or even defaultGravity = physics.gravity(0,0,0))

What am I doing wrong?

Just write gravity(0,0)

This consistently crashes my system, does codea behave like this for anyone else? should I post an entry in the bug section?

Post more of your code, most likely there is a coding error

Actually, even easier for you guys : in the “main” file of the physics lab, in codea’s latest version, simply changing “physics.gravity()” by “physics.gravity(0,0)” crashes on my ipad retina. There’s most likely something I am missing…

Maybe physics.gravity(vec2(0, 0))?

Oops, i can’t remember if I tried this!

(Trying)

No, still crashing :frowning:

Looking at the code in the physics lab example and at the documentation, this is basically all the code that’s needed to show it doesnt work. Variable a is (0,-313.600006), variable b is nil. Variable b should be the same as a.

EDIT: physics.gravity doesn’t return a value if there are values in the (). The second function setup of my example works. So in the above example defaultGravity=physics.gravity(0,0) will set defaultGravity to nil.

    
function setup()
    a=physics.gravity()
    print(a)
    b=physics.gravity(a)
    print(b)   
end

function setup()
    a=physics.gravity()
    print(a)
    physics.gravity(a)
    b=physics.gravity()
    print(b)   
end

Sorry, I feel really slow, does that mean this is actually a bug?

No, it’s not a bug. It’s working the way it was written. At first I thought it was a bug also until I looked at the documentation and realized that it only returned a value when no parameters were passed in the function. I guess it could have been written to return a value even if there were parameters passed, but it doesn’t.

Alright, that’s clearer now. I still find it a little counter intuitive, but it now works for me thanks to you!