Howdy, Stranger!

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

Please Help Me Make A Shattering Circle Physics Body

edited July 2016 in Questions Posts: 160

Hello!
I'm trying to make a circle shatter into a bunch of peices when you tap the screen, but I'm having trouble figuring out what points I need to use when creating the slices. I'm worried I might have to use some of the math functions I don't understand like math.acos, math.cosh, math.asin, math.sinh, math.atan, math.tanh, math.fmod, and math.log (I do understand however, that cosine is adjecent / hypotenuse, sine is oposite / hypotenuse and tangent is oposite / adjecent in a triangle). Don't blame me, I'm not in high school yet. I've tried learning these math functions through the internet, but that kind of math was very confusing. I'm hoping someone can help me here on the forums. I would love someone to help me write the code, but giving me some easy-to-understand tutorials on these math functions would also be great!
Here's what I have so far:

-- Use this function to perform your initial setup
function setup()
    borders = physics.body(CHAIN,true,vec2(0,0),vec2(WIDTH,0),vec2(WIDTH,HEIGHT),vec2(0,HEIGHT))

    bodies = {}
    newBody(physics.body(CIRCLE, 100), WIDTH/2, HEIGHT/2, vec2(0,0))
    --newBody(physics.body(POLYGON,vec2(-100,-100),vec2(0,100),vec2(100,-100)),200,HEIGHT-100)

    physics.gravity(0,-700)
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- Do your drawing here
    for k,t in pairs(bodies) do
        pushMatrix()
        translate(t.b.x,t.b.y)
        if t.b.shapeType == POLYGON then
            rotate(t.b.angle)
            t.m:draw()
            elseif t.b.shapeType == CIRCLE then
            pushStyle()
            fill(0,0,255)
            noStroke()
            ellipse(0,0,t.b.radius*2)
            popStyle()
        end
        popMatrix()
    end
end

function touched(t)
    if t.state == ENDED then
        -- First we create new bodies in the shapes of the circle sliced (how??)

        bodies[1].b:destroy()
        table.remove(bodies,1) -- Then we remove the original circle
    end
end

function newBody(b, x, y, vel, ang, rotSpeed)
    local velocity
    if vel then
        velocity = vec2(vel.x,vel.y)
        else
        velocity = vec2(0,0)
    end

    b.position = vec2(x,y)
    b.linearVelocity = velocity
    b.angle = ang or 0
    b.angularVelocity = rotSpeed or 0
    b.restitution = 0.4

    local m = mesh()
    if b.shapeType == POLYGON then
        m.vertices = triangulate(b.points)
    end
    m:setColors(0,0,255)

    table.insert(bodies, {b=b,m=m})
end

Thank-you so much in advance! :smile:

Tagged:

Comments

  • Posts: 2,020

    The easiest way would be to have it shatter into pie-slices (pi slices? :D )

    Is that what you want though?

    You say "shatter" which implies to me that you'd like the pieces to be more irregular and unevenly shaped.

  • Posts: 160

    Yes, that is what I was implying when I said shatter. But if that's too complicated, the pie slices would work too. (and thank-you for helping out! :) )

  • edited July 2016 Posts: 160

    I'm sorry to do so but, I've actually changed my mind. I think the pie slices method would be a lot better because if we use the other option we will end up with peices that are very small which is not so good for the game I'll be using this for. I think the pie slices can be made with a couple for loops, math.cos and math.sin, but I'm not sure exactly how to do it.

  • IgnatzIgnatz Mod
    Posts: 5,396

    @Kolosso - we are happy to help solve problems, but we do ask people to make an effort first, because we are a small group.

    Unless you are expecting us to write all the code for you, you will need to learn a bit about sin, cos, tan. They really aren't very difficult, even if you aren't in high school yet, and you need them all the time to do graphics programming.

    There are stacks of tutorials on them, much better than anything we could do. Why reinvent the wheel?

    Why don't you look at all the stuff out there, try to get a basic understanding of trig functions, then come back and have a go with Codea?

  • Posts: 2,020

    Sorry, couldn't resist. Codea's triangulate function creates nice, spiky looking segments.


    --# Main -- Circle Shatter function setup() --unique points describing circle local noPoints = 24 --must be a multiple of 3 local points = {} local radius = 100 local angleStep = (math.pi * 2) / noPoints for i = 1,noPoints do local angle = (i-1) * angleStep points[i] = vec2(radius * math.sin(angle), radius * math.cos(angle)) end local verts = triangulate(points) --triangulate points bodies = {} local col = color(0, 235, 255, 255) local pos = vec2(WIDTH/2, HEIGHT/2) --position of circle print("triangles:", #verts / 3) for i = 1, #verts, 3 do local a = verts[i] * 1 -- *1 to make a new copy of the vec local b = verts[i+1] * 1 local c = verts[i+2] * 1 local centre = (a+b+c)/3 a = a - centre b = b - centre c = c - centre table.insert(bodies, Triangle(centre, pos, col, a, b, c)) end end function draw() background(40, 40, 50) for i = 1, #bodies do bodies[i]:draw() end end function touched(t) for i = 1, #bodies do bodies[i]:touched() end end --# Triangle Triangle = class() local function randomRange(n) return (math.random() - 0.5) * n * 2 end function Triangle:init(segmentPos, circlePos, col, a,b,c) self.body = physics.body(POLYGON, a, b, c) self.body.position = segmentPos + circlePos self.body.gravityScale = 0 --not affected by gravity. yet... self.body.interpolate = true self.mesh = mesh() local mag = 1.01 --make mesh slightly bigger to cover cracks. Or, smaller, 0.99 if you want cracks self.mesh.vertices = {a * mag,b * mag,c * mag} self.mesh:setColors(col) --the vector that the segment will explode along is its normalized segment position, plus anti-gravity, plus noise self.escapeVelocity = (segmentPos:normalize() + vec2(randomRange(0.5),1 + math.random() * 0.4)) * 3 end function Triangle:draw() pushMatrix() translate(self.body.x, self.body.y) rotate(self.body.angle) self.mesh:draw() popMatrix() end function Triangle:touched() self.body.gravityScale = 1 self.body:applyLinearImpulse(self.escapeVelocity) self.body:applyAngularImpulse(randomRange(10)) end
  • Posts: 160

    @yojimbo2000, Thank-you so much! Like I said, I have changed my mind so I may not use the code you provided in my game (and I'm sorry about it) but I will still try to learn from it. I bet there are many techniques in your code.

    @Ignatz, Sorry for causing any problems. I have looked up cosine, sine and tangent tutorials on the internet and I'm currently trying my best to split the circle into even pie slices with them.

  • Posts: 2,020

    Well, look at the first for loop in my setup function for your pi slices.

  • Posts: 160

    I looked at this code in your setup function, and after quite a few experiments, I think I finally understand how it works!!:

        local noPoints = 24 --must be a multiple of 3
        local points = {}
        local radius = 100
        local angleStep = (math.pi * 2) / noPoints
        for i = 1,noPoints do
            local angle = (i-1) * angleStep
            points[i] = vec2(radius * math.sin(angle), radius * math.cos(angle))
        end
    

    Thanks, @yojimbo2000!

  • dave1707dave1707 Mod
    edited July 2016 Posts: 7,532

    @Kolosso Thought I'd give a try at the exploding circle. Tap the screen to explode it. Do a restart to see it again.

    displayMode(FULLSCREEN)
    
    function setup()
        e1=physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT))
        e2=physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,HEIGHT))
        e3=physics.body(EDGE,vec2(0,0),vec2(WIDTH,0))
        e4=physics.body(EDGE,vec2(0,HEIGHT),vec2(WIDTH,HEIGHT))
        ba={}
        for x=1,16 do
              table.insert(ba,ball(WIDTH/2,HEIGHT/2))    
        end
        physics.continuous=true
    end
    
    function draw()
        background(40, 40, 50)
        stroke(255)
        strokeWidth(2)
        noFill()
        if not hide then
            ellipse(WIDTH/2,HEIGHT/2,40)
        else
            for a,b in pairs(ba) do
                b:draw()
            end
        end
    end
    
    function touched(t)
        if t.state==BEGAN and not hide then
            hide=true
            for z=1,#ba do
                ba[z].a.type=DYNAMIC
                ba[z].a.linearVelocity=vec2(math.random(-300,300),math.random(-300,300))
            end        
        end
    end
    
    ball=class()
    
    function ball:init(x,y)
        self.a=physics.body(POLYGON,
            vec2(math.random(-10,0),math.random(10)),
            vec2(math.random(-10,0),math.random(-10,0)),
            vec2(math.random(10),math.random(-10,0)),
            vec2(math.random(10),math.random(10)))
        self.a.gravityScale=0
        self.a.x=x
        self.a.y=y
        self.a.restitution=.8
        self.a.type=STATIC
    end
    
    function ball:draw()
        stroke(255)
        strokeWidth(2)
        pushMatrix()
        translate(self.a.x,self.a.y)
        rotate(self.a.angle)
        p=self.a.points
        for z=2,#p do
            line(p[z-1].x,p[z-1].y,p[z].x,p[z].y)        
        end
        line(p[1].x,p[1].y,p[#p].x,p[#p].y)
        popMatrix()
    end
    
  • Posts: 160

    I did it! :smiley:
    It took a lot of time and effort and it probably isn't the most efficient way, but I finally figured out how to make a circle split into a bunch of peices!:

    -- Use this function to perform your initial setup
    displayMode(FULLSCREEN)
    function setup()
        borders = physics.body(CHAIN,true,vec2(0,0),vec2(WIDTH,0),vec2(WIDTH,HEIGHT),vec2(0,HEIGHT))
    
        bodies = {}
        newBody(physics.body(CIRCLE, 100), WIDTH/2, HEIGHT/6*5, vec2(0,0))
        --newBody(physics.body(POLYGON,vec2(-100,-100),vec2(0,100),vec2(100,-100)),200,HEIGHT-100)
    
        physics.gravity(0,-700)
    end
    
    -- This function gets called once every frame
    function draw()
        -- This sets a dark background color 
        background(40, 40, 50)
    
        -- Do your drawing here
        for k,t in pairs(bodies) do
            pushMatrix()
            translate(t.b.x,t.b.y)
            if t.b.shapeType == POLYGON then
                rotate(t.b.angle)
                t.m:draw()
                elseif t.b.shapeType == CIRCLE then
                pushStyle()
                fill(0,0,255)
                noStroke()
                ellipse(0,0,t.b.radius * 2)
                popStyle()
            end
            popMatrix()
        end
    end
    
    function touched(t)
        if t.state == ENDED then
            -- First we create new bodies in the shapes of a sliced circle
            slicedCircle(bodies[1].b.radius, bodies[1].b.x, bodies[1].b.y, bodies[1].b.linearVelocity * 1, 500)
    
            bodies[1].b:destroy()
            bodies[1] = nil -- Then we remove the original circle
        end
    end
    
    function newBody(b, x, y, vel, ang, rotSpeed)
        local velocity
        if vel then
            velocity = vec2(vel.x,vel.y)
            else
            velocity = vec2(0,0)
        end
    
        b.position = vec2(x,y)
        b.linearVelocity = velocity
        b.angle = ang or 0
        b.angularVelocity = rotSpeed or 0
        b.restitution = 0.4
    
        local m = mesh()
        if b.shapeType == POLYGON then
            m.vertices = triangulate(b.points)
        end
        m:setColors(0,0,255)
    
        table.insert(bodies, {b=b,m=m})
    end
    
    function slicedCircle(radius, x, y, velocity, explo, p, groups)
        local p = p or 24
        local groups = groups or 2
        local circle = circlePoints(radius, p)
    
        local next = 0
        for i=1, math.ceil(#circle / groups) do
            local points = {vec2(0,0)}
            for g=1, groups+1 do
                next = next + 1
                if circle[next+(i-1)] then
                    table.insert(points,circle[next+(i-1)]*1)
                    elseif points[#points] ~= circle[1] then
                    table.insert(points,circle[1]*1)
                end
            end
            next = next - 2
            local b = physics.body(POLYGON, table.unpack(points))
            local vel = vec2(math.sin(i) * explo + velocity.x, math.cos(i) * explo + velocity.y)
            newBody(b, x, y, vel)
        end
    end
    
    function circlePoints(radius,numPoints)
        local points = {}
        local fullCircle = math.pi * 2
        local angleStep = fullCircle / numPoints
        for i=1, numPoints do
            local angle = (i-1) * angleStep
            points[i] = vec2(math.sin(angle) * radius, math.cos(angle) * radius)
        end
        return points
    end
    

    I made a function called slicedCircle(radius, x, y, velocity, explo, p, groups) that makes a bunch of polygon physics bodies in shapes of a sliced circle. The parameter radius determines the radius of the circle, x and y is for location of the sliced circle, velocity and explo are used to determine the velocity of the peices, p is for the amount of points you want the circle to have and groups is used to determine how many points (the more points, the more round) each slice has. If groups is not a multiple of p, the slice just left of the top of the circle will be a different fraction of the whole circle and this is fine in my opinion. I'm just pointing it out incase someone might want to use these functions.

    Thank-you so much @dave and @yojimbo2000 for writing examples. They really helped. :smile:
    And thank-you, @ignatz for the advice. :smile:

Sign In or Register to comment.