Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion

Planet physics (Gravity)

edited August 2013 in Examples Posts: 437

Hey all, this is a very simple example of my suggestion to use a set of planets with gravity , movers and attractors:

--# Main
-- PlanetGravity

-- Use this function to perform your initial setup
function setup()
    physics.gravity(0,0)
    mainPlanet = Planet({
     x       = WIDTH/2,
     y       = HEIGHT/2,
     radius  = 60,
     mass    = 10,
     type    = ATTRACTOR,
     img     = "SpaceCute:Planet"
    })

    redPlanet = Planet({
     x       = WIDTH - 100,
     y       = HEIGHT/3,
     radius  = 30,
     mass    = 8,
     type    = ATTRACTOR,
     img     = "Space Art:UFO"
    })

    asteroid = Planet({
     x       = WIDTH/4,
     y       = 100,
     sizex   = 66,
     sizey   = 55,
     radius  = 30,
     mass    = 2,
     type    = MOVER,
     img     = "Space Art:Asteroid Large"
    })

    small_asteroid = Planet({
     x       = WIDTH/1.2,
     y       = HEIGHT - 100,
     sizex   = 50,
     sizey   = 50,
     radius  = 25,
     mass    = 1,
     type    = MOVER,
     img     = "Space Art:Asteroid Small"
    })

    rockPlanet = Planet({
     x       = 100,
     y       = HEIGHT - 100,
     radius  = 40,
     mass    = 18,
     type    = ATTRACTOR,
     img     = "Tyrian Remastered:Rock 3"
    })

    -- set the attractors
    mainPlanet:addAttractor(asteroid)
    redPlanet:addAttractor(asteroid)
    mainPlanet:addAttractor(small_asteroid)
    rockPlanet:addAttractor(small_asteroid)
    rockPlanet:addAttractor(asteroid)

    -- controls of the masses :D
    parameter.number("Red Planet Mass", 8, 150, 8, function(newMass)
        redPlanet.mass = newMass
    end
    )
    parameter.number("Green Planet Mass",10,200,10,function(newMass)
        mainPlanet.mass= newMass
    end
    )
    parameter.number("Rock Planet Mass",8,200,18,function(newMass)
        rockPlanet.mass= newMass
    end
    )
    createUniverseLimit()
end

function createUniverseLimit()
    top   = physics.body(EDGE, vec2(0,HEIGHT), vec2(WIDTH,HEIGHT))
    left  = physics.body(EDGE, vec2(0,HEIGHT), vec2(0,0))
    right = physics.body(EDGE, vec2(WIDTH,HEIGHT), vec2(WIDTH,0))
    bottom= physics.body(EDGE, vec2(0,0) , vec2(WIDTH,0))
end

function draw()
    background(0)
    strokeWidth(2)

    mainPlanet:draw()
    rockPlanet:draw()
    redPlanet:draw()
    asteroid:draw()
    small_asteroid:draw()
end



function touched(touch)
    if asteroid:touched(touch) then return end
    if small_asteroid:touched(touch) then return end
end

--# Planet
Planet = class()
ATTRACTOR = 1
MOVER     = 2
GRAVITY   = 1000
function Planet:init(args)
    -- create the planet body
    self.body      = physics.body(CIRCLE, args.radius)
    self.body.x    = args.x
    self.body.y    = args.y
    self.type      = args.type
    self.body.mass = args.mass
    self.mass      = args.mass -- when static, body.mass is 0
    self.sizex     = args.sizex or args.radius*2.5
    self.sizey     = args.sizey or args.radius*2.5
    self.dragOffset= vec2(0,0)
    self.img       = readImage(args.img)
    self.body.restitution = .05
    self.body.friction = .6
    self.touchId   = 0
    if args.type == ATTRACTOR then
        self.attracted = {}
        self.body.type = STATIC
    elseif args.type == MOVER then
        self.attractors= {}
    end


end

function Planet:addAttractor(attractor)
    if self.type == ATTRACTOR then
        table.insert(self.attracted, attractor)
        table.insert(attractor.attractors, self)
    elseif self.type == MOVER then
        table.insert(self.attractors, attractor)
        table.insert(attractor.attracted, self)
    end
end

function Planet:attract(m)
    -- Direction of the force
    local force = self.body.position - m.body.position
    local d     = force:len() -- = m.body.position:dist(self.body.position)
    force = force:normalize()
    local dir   = vec2(self.mass/m.body.mass, self.mass/m.body.mass)

    -- Magnitude of the force
    local strength = (GRAVITY * self.mass * m.body.mass)/(d*d)    
    force = force * strength
    m.body:applyForce(force)

    stroke((1+math.floor(force.y))*110, (1+math.floor(force.x))*110, 10, 255)

    -- draw line between attractor/mover
    line(m.body.x+force.x, m.body.y+force.y, (self.body.x), (self.body.y))
end

function Planet:updateForces()
    if self.type == ATTRACTOR then
        self.body.angle = self.body.angle - 0.1
        for i,a in ipairs(self.attracted) do
            self:attract(a)
        end
    elseif self.type == MOVER then
        -- check for planets?
        -- TODO
    end
end

function Planet:draw()
    self:updateForces()
    pushMatrix()
     translate(self.body.x, self.body.y)
     rotate(self.body.angle)
     sprite(self.img, 0, 0, self.sizex, self.sizey)
    popMatrix()
end

function Planet:touched(touch)
    if touch.state == BEGAN then
        if self.touchId == 0 then
            if self.body:testPoint(vec2(touch.x,touch.y)) then
                self.touchId = touch.id
            else
                -- not touching this body
                return false
            end
        else
            -- this body has another touch
            return false
        end
    else
        if self.touchId ~= touch.id then
            return false
        end
    end

    self.body.x = touch.x
    self.body.y = touch.y
    if touch.state == ENDED then
        self.touchId = 0
    end
    return true
end


Comments

Sign In or Register to comment.