Wheel spinning with physics

Hi Everybody,

I’m a Beginner with Corona sdk and Lua, i’m tryng to create a sort of wheel of fortune game, but i’m having trouble with the rotation physics. My wheel rotate when i touch it but stops immediatly after. I would like to give to the wheel a spin effect that slowly decrease the speed just like in the wheel of fortune. Here is my code:


– main.lua


– 

local physics = require(“physics”)

physics.start()

physics.setGravity(0,8)

physics.setDrawMode(“hybrid”)

local background = display.newImage(“background.png”)

background.x = display.contentCenterX

background.y = display.contentCenterY

local arms = display.newImage(“arms1.png”, true)

arms.x = display.contentWidth - 134

arms.y = display.contentHeight - 290

local wheel = display.newImage(“wheel.png”, true)

wheel.x = display.contentWidth - 195

wheel.y = display.contentHeight - 268

physics.addBody(wheel,“static”,{bounce=0, friction=0.2, radius=98})

wheel:applyTorque(3.8)

local skull = display.newImage(“skull1.png”, true)

skull.x = display.contentWidth - 190

skull.y = display.contentHeight - 379

function getAngle(x1,y1,x2,y2)

    local PI = 3.14159265358

    local deltaY = y2 - y1

    local deltaX = x2 - x1

    local angleInDegrees = (math.atan2( deltaY, deltaX) * 180 / PI)*-1

    local mult = 10^0

    return math.floor(angleInDegrees * mult + 0.5) / mult

end

wheel.touch = function(self, event)

    print(event.phase)

    if event.phase == “moved” then

        --If your image is originally pointing to the north use +90

        --If your image is originally pointing to the east use +180

        --If your image is originally pointing to the south use +270

        --If your image is originally pointing to the west use +360 or +0

        --My wheel.png is point to the east so I use +180

        --You can use this formula

        wheel.rotation = (getAngle(wheel.x,wheel.y,event.x,event.y)+180)*-1

    end

end

Runtime:addEventListener(“touch”,wheel)


Thanks and i’m sorry for my bad english.

Hi @kkaaoss,
First and most importantly, make the wheel a “dynamic” physics body, not “static”.

Next, apply the torque just as you are now, however, to make the wheel slow down gradually, set an angular damping value on it:

https://docs.coronalabs.com/api/type/Body/angularDamping.html

Best regards,
Brent

Hi Brent!

Thanks for your reply, i just applied changes to my code as you suggested, but the wheel still stops immediatly and now the wheel falls down :frowning: here is my new code:

 -----------------------------------------------------------------------------------------

– main.lua


– 

local physics = require(“physics”)

physics.start()

physics.setGravity(0,1)

physics.setDrawMode(“hybrid”)

local background = display.newImage(“background.png”)

background.x = display.contentCenterX

background.y = display.contentCenterY

local arms = display.newImage(“arms1.png”, true)

arms.x = display.contentWidth - 134

arms.y = display.contentHeight - 290

local wheel = display.newImage(“wheel.png”, true)

wheel.x = display.contentWidth - 195

wheel.y = display.contentHeight - 268

physics.addBody(wheel,“dynamic”,{bounce=0, friction=0.2, radius=98})

wheel.angularDamping = 5

wheel:applyTorque(3.8)

local skull = display.newImage(“skull1.png”, true)

skull.x = display.contentWidth - 190

skull.y = display.contentHeight - 379

function getAngle(x1,y1,x2,y2)

    local PI = 3.14159265358

    local deltaY = y2 - y1

    local deltaX = x2 - x1

    local angleInDegrees = (math.atan2( deltaY, deltaX) * 180 / PI)*-1

    local mult = 10^0

    return math.floor(angleInDegrees * mult + 0.5) / mult

end

wheel.touch = function(self, event)

    print(event.phase)

    if event.phase == “moved” then

        --If your image is originally pointing to the north use +90

        --If your image is originally pointing to the east use +180

        --If your image is originally pointing to the south use +270

        --If your image is originally pointing to the west use +360 or +0

        --My wheel.png is point to the east so I use +180

        --You can use this formula

        wheel.rotation = (getAngle(wheel.x,wheel.y,event.x,event.y)+180)*-1

    end

end

Runtime:addEventListener(“touch”,wheel)


Please post your code using the <> button in the forum editor’s formatting bar (with Bold, Italic, etc.).

I built a triva game once that uses a wheel of fortune type spinning well to select categories. You can spin it and take where it lands, but you can also use it a dial to pick the category.  Here is the relevant code:

local function gameLoop() angle = wheel.rotation if wheel.angularVelocity == 0 and angle ~= startingAngle then --print(angle % 360) local wedge = math.floor(((angle + 45) % 360) /45) + 1 --print(wedge .. " " .. wedgeName[wedge]) startingAngle = angle mydata.gameCategory = wedge if movementEnded then timer.performWithDelay(1000,playRound); end end end local function spinWheel(event) local t = event.target local phase = event.phase --print("Phase: " .. phase) if (phase == "began") then display.getCurrentStage():setFocus( t ) t.isFocus = true -- Store initial position of finger t.x1 = event.x t.y1 = event.y startTime = event.time --print("start time " .. startTime) elseif t.isFocus then if (phase == "moved") then t.x2 = event.x t.y2 = event.y angle1 = 180/math.pi \* math.atan2(t.y1 - t.y , t.x1 - t.x) angle2 = 180/math.pi \* math.atan2(t.y2 - t.y , t.x2 - t.x) --print("angle1 = "..angle1) rotationAmt = angle1 - angle2 --rotate it t.rotation = t.rotation - rotationAmt --print ("t.rotation = "..t.rotation) t.x1 = t.x2 t.y1 = t.y2 elseif (phase == "ended") or (phase == "cancelled") then local deltaTime = event.time - startTime if deltaTime \< 500 then wheel:applyAngularImpulse( 100000 + rand(33000)) wheel:removeEventListener("touch", spinWheel) else --print("delta time " .. (event.time - startTime)) -- wheel:removeEventListener("touch", spinWheel) timer.performWithDelay(500,playRound); end movementEnded = true display.getCurrentStage():setFocus( nil ) t.isFocus = false end end -- Stop further propagation of touch event return true end function scene:createScene( event ) local group = self.view physics.start() physics.setGravity(0,0) -- app doesn't need gravity physics.pause() local background = display.newImageRect("images/menu\_background.jpg", 756, 504) background.x = display.contentWidth / 2 background.y = display.contentHeight / 2 group:insert(background) --\> This sets the background wheel = display.newImageRect("images/wheel.png", 250, 250) startingAngle = wheel.rotation print("Starting Angle: " .. startingAngle) wheel.x = 140 wheel.y = display.contentHeight / 2 + 20 group:insert(wheel) physics.addBody(wheel, {density=0.5, friction=0.8, bounce=0.0, radius=125 } ) wheel.angularDamping = 0.7 wheel:addEventListener("touch", spinWheel) local pointer = display.newImageRect("images/pointer.png", 32, 16) pointer.x = 15 pointer.y = display.contentHeight / 2 + 20 group:insert(pointer) -- more code end function scene:enterScene( event ) local group = self.view storyboard.removeScene("loading") Runtime:addEventListener("enterFrame", gameLoop) physics.start() end

As I said, this is an older app that was using storyboard, but this should adapt to Composer quite easily.

Rob

Hello Rob,

First of all thank you for the code! I resolved the “falling wheel” issue setting the gravity to zero, but i still have the touch event issue.

I need to spin the wheel with the finger, now it follows my finger on the screen but when i remove the finger it stops instead of continue spinning.

Thank you guys for the help.

My touch handler works. Take some time and study it. It also uses an Runtime “enterFrame” listener too. 

Rob

Hi Everybody,

Rob I switched your code with mine but my wheel still stops :-((((( please help i’m losing my head.

here is my new code:

[lua]         --print(wedge … " " … wedgeName[wedge])

        startingAngle = angle

        if movementEnded then timer.performWithDelay(1000,playRound); end

    end

end

local function spinObject(event)

    local t = event.target

    local phase = event.phase

    --print("Phase: " … phase)

    if (phase == “began”) then

            display.getCurrentStage():setFocus( t )

            t.isFocus = true

            – Store initial position of finger

            t.x1 = event.x

            t.y1 = event.y

    elseif t.isFocus then

            if (phase == “moved”) then

                    t.x2 = event.x

                    t.y2 = event.y

                    local angle1 = 180/math.pi * math.atan2(t.y1 - t.y , t.x1 - t.x)

                    local angle2 = 180/math.pi * math.atan2(t.y2 - t.y , t.x2 - t.x)

                    local rotationAmt = angle1 - angle2

                    t.rotation = t.rotation - rotationAmt

                    t.x1 = t.x2

                    t.y1 = t.y2

                    

            elseif (phase == “ended”) or (phase == “cancelled”) then

                display.getCurrentStage():setFocus( nil )

                t.isFocus = false

            end

    end

    

    – Stop further propagation of touch event

    return true

end

wheel:addEventListener(“touch”, spinObject)

Runtime:addEventListener(“enterFrame”, gameLoop)

    physics.start() [/lua]

Ok we can close the topic as ‘Solved’ i found a solution to my issue using the “touch joint”.

Thanks everybody for the precious help.

Hi @kkaaoss,
First and most importantly, make the wheel a “dynamic” physics body, not “static”.

Next, apply the torque just as you are now, however, to make the wheel slow down gradually, set an angular damping value on it:

https://docs.coronalabs.com/api/type/Body/angularDamping.html

Best regards,
Brent

Hi Brent!

Thanks for your reply, i just applied changes to my code as you suggested, but the wheel still stops immediatly and now the wheel falls down :frowning: here is my new code:

 -----------------------------------------------------------------------------------------

– main.lua


– 

local physics = require(“physics”)

physics.start()

physics.setGravity(0,1)

physics.setDrawMode(“hybrid”)

local background = display.newImage(“background.png”)

background.x = display.contentCenterX

background.y = display.contentCenterY

local arms = display.newImage(“arms1.png”, true)

arms.x = display.contentWidth - 134

arms.y = display.contentHeight - 290

local wheel = display.newImage(“wheel.png”, true)

wheel.x = display.contentWidth - 195

wheel.y = display.contentHeight - 268

physics.addBody(wheel,“dynamic”,{bounce=0, friction=0.2, radius=98})

wheel.angularDamping = 5

wheel:applyTorque(3.8)

local skull = display.newImage(“skull1.png”, true)

skull.x = display.contentWidth - 190

skull.y = display.contentHeight - 379

function getAngle(x1,y1,x2,y2)

    local PI = 3.14159265358

    local deltaY = y2 - y1

    local deltaX = x2 - x1

    local angleInDegrees = (math.atan2( deltaY, deltaX) * 180 / PI)*-1

    local mult = 10^0

    return math.floor(angleInDegrees * mult + 0.5) / mult

end

wheel.touch = function(self, event)

    print(event.phase)

    if event.phase == “moved” then

        --If your image is originally pointing to the north use +90

        --If your image is originally pointing to the east use +180

        --If your image is originally pointing to the south use +270

        --If your image is originally pointing to the west use +360 or +0

        --My wheel.png is point to the east so I use +180

        --You can use this formula

        wheel.rotation = (getAngle(wheel.x,wheel.y,event.x,event.y)+180)*-1

    end

end

Runtime:addEventListener(“touch”,wheel)


Please post your code using the <> button in the forum editor’s formatting bar (with Bold, Italic, etc.).

I built a triva game once that uses a wheel of fortune type spinning well to select categories. You can spin it and take where it lands, but you can also use it a dial to pick the category.  Here is the relevant code:

local function gameLoop() angle = wheel.rotation if wheel.angularVelocity == 0 and angle ~= startingAngle then --print(angle % 360) local wedge = math.floor(((angle + 45) % 360) /45) + 1 --print(wedge .. " " .. wedgeName[wedge]) startingAngle = angle mydata.gameCategory = wedge if movementEnded then timer.performWithDelay(1000,playRound); end end end local function spinWheel(event) local t = event.target local phase = event.phase --print("Phase: " .. phase) if (phase == "began") then display.getCurrentStage():setFocus( t ) t.isFocus = true -- Store initial position of finger t.x1 = event.x t.y1 = event.y startTime = event.time --print("start time " .. startTime) elseif t.isFocus then if (phase == "moved") then t.x2 = event.x t.y2 = event.y angle1 = 180/math.pi \* math.atan2(t.y1 - t.y , t.x1 - t.x) angle2 = 180/math.pi \* math.atan2(t.y2 - t.y , t.x2 - t.x) --print("angle1 = "..angle1) rotationAmt = angle1 - angle2 --rotate it t.rotation = t.rotation - rotationAmt --print ("t.rotation = "..t.rotation) t.x1 = t.x2 t.y1 = t.y2 elseif (phase == "ended") or (phase == "cancelled") then local deltaTime = event.time - startTime if deltaTime \< 500 then wheel:applyAngularImpulse( 100000 + rand(33000)) wheel:removeEventListener("touch", spinWheel) else --print("delta time " .. (event.time - startTime)) -- wheel:removeEventListener("touch", spinWheel) timer.performWithDelay(500,playRound); end movementEnded = true display.getCurrentStage():setFocus( nil ) t.isFocus = false end end -- Stop further propagation of touch event return true end function scene:createScene( event ) local group = self.view physics.start() physics.setGravity(0,0) -- app doesn't need gravity physics.pause() local background = display.newImageRect("images/menu\_background.jpg", 756, 504) background.x = display.contentWidth / 2 background.y = display.contentHeight / 2 group:insert(background) --\> This sets the background wheel = display.newImageRect("images/wheel.png", 250, 250) startingAngle = wheel.rotation print("Starting Angle: " .. startingAngle) wheel.x = 140 wheel.y = display.contentHeight / 2 + 20 group:insert(wheel) physics.addBody(wheel, {density=0.5, friction=0.8, bounce=0.0, radius=125 } ) wheel.angularDamping = 0.7 wheel:addEventListener("touch", spinWheel) local pointer = display.newImageRect("images/pointer.png", 32, 16) pointer.x = 15 pointer.y = display.contentHeight / 2 + 20 group:insert(pointer) -- more code end function scene:enterScene( event ) local group = self.view storyboard.removeScene("loading") Runtime:addEventListener("enterFrame", gameLoop) physics.start() end

As I said, this is an older app that was using storyboard, but this should adapt to Composer quite easily.

Rob

Hello Rob,

First of all thank you for the code! I resolved the “falling wheel” issue setting the gravity to zero, but i still have the touch event issue.

I need to spin the wheel with the finger, now it follows my finger on the screen but when i remove the finger it stops instead of continue spinning.

Thank you guys for the help.

My touch handler works. Take some time and study it. It also uses an Runtime “enterFrame” listener too. 

Rob

Hi Everybody,

Rob I switched your code with mine but my wheel still stops :-((((( please help i’m losing my head.

here is my new code:

[lua]         --print(wedge … " " … wedgeName[wedge])

        startingAngle = angle

        if movementEnded then timer.performWithDelay(1000,playRound); end

    end

end

local function spinObject(event)

    local t = event.target

    local phase = event.phase

    --print("Phase: " … phase)

    if (phase == “began”) then

            display.getCurrentStage():setFocus( t )

            t.isFocus = true

            – Store initial position of finger

            t.x1 = event.x

            t.y1 = event.y

    elseif t.isFocus then

            if (phase == “moved”) then

                    t.x2 = event.x

                    t.y2 = event.y

                    local angle1 = 180/math.pi * math.atan2(t.y1 - t.y , t.x1 - t.x)

                    local angle2 = 180/math.pi * math.atan2(t.y2 - t.y , t.x2 - t.x)

                    local rotationAmt = angle1 - angle2

                    t.rotation = t.rotation - rotationAmt

                    t.x1 = t.x2

                    t.y1 = t.y2

                    

            elseif (phase == “ended”) or (phase == “cancelled”) then

                display.getCurrentStage():setFocus( nil )

                t.isFocus = false

            end

    end

    

    – Stop further propagation of touch event

    return true

end

wheel:addEventListener(“touch”, spinObject)

Runtime:addEventListener(“enterFrame”, gameLoop)

    physics.start() [/lua]

Ok we can close the topic as ‘Solved’ i found a solution to my issue using the “touch joint”.

Thanks everybody for the precious help.