Play Click sound for every degree rotated

I’ve got a handle on my game, and this concept is driving me crazy.

Lets say I have a stereo with a volume dial. It rotates left and right. I want to play a single clicking sound for every degree (or every couple degrees, if it’s too noisy considering there are 360 degrees I may settle on every 5 or 10)
I dove into the Lua 5.1 reference guide and pulled up the “relational operators” since I am still kind of new to programming (all programming never touched code before June 2011).

<
>
<=
>=

~=

I was trying to do something in a function like this (full code below, but here is the snippet):

 local function clicker ()  
 print ("clickity click")  
 if testobject.rotation ~= 0 then print ("1 more degree")  
-- So I read ~= equals "negation of equality" OK what the hell does that mean? lol @ me.  
  
 --audio.play(click)  
 print (testobject.rotation)  
 end  
 end  

So I’m printing out the rotation and it’s not in round numbers as expected but I want to take action based on whole rounded numbers such as 1,2,3 for the number of whole degrees and not decimal places. In my head and paper I know what I want, I just can’t seem to code it worth a damn haha.

So if the volume dial rotates left or right by say 5 degrees, every 5 degrees it would click. The problem I see is the knob turns from 0 starting position gets to 5 clicks and then stops clicking. So I have to figure out a way to…uhh I don’t know something like add 5 to the degrees or take away 5 to the degrees or something that way it plays every 5 degrees.

That was probably completely off, but I don’t know what I’m talking about most of the time :slight_smile:

My mind says “table, or array” or something. What do you think? Any help is greatly appreciated, spent a few hours on this so far and I think this beat me haha.
Here is the sample code, simply drag the circle left or right and it spins around using a simple joint.

-Nick

[code]
local physics = require “physics”
physics.start(true)
physics.setDrawMode(“debug”)

–DECLARE WIDTH AND HEIGHT SHORTCUT VARIABLES
local _W = display.contentWidth
local _H = display.contentHeight

local refpoint
local testobject
–local click = audio.loadSound (“click.wav”)

print (“wtfbbq kyle this code is pissing me off and I want to die”)

local refpoint = display.newCircle (_W/2, _H/2, 5)
physics.addBody(refpoint, “static”, {isSensor = true, radius = 5})
refpoint:setFillColor (255,0,0)
refpoint.alpha = 1

–======================================================================================
–testobject - ATTACHES TO REFERENCE POINT VIA “PIVOT”
local testobject = display.newCircle (refpoint.x, refpoint.y, 150)
physics.addBody( testobject, {radius = 150})
testobject.isSleepingAllowed = false
testobject.alpha = 1
testobject.x = refpoint.x
testobject.y = refpoint.y

–Some stuff I was messing around with, trying to capture numbers
–and to get degrees or something…grr
local av = testobject.angularVelocity
local ad = testobject.angularDamping
local lv = testobject.LinearVelocity
local r = testobject.rotation

–======================================================================================
–PIVOT JOINT THAT CONNECTS THE REFERENCE POINT TO testobject
local testobjectJoint = physics.newJoint ( “pivot”, refpoint, testobject, refpoint.x, refpoint.y)

–X and Y touch accurate – no “snapping”
local function dragBody( event )
–print (“testobject drag started”)
local body = event.target
local phase = event.phase
local stage = display.getCurrentStage()

if “began” == phase then

stage:setFocus( body, event.id )
body.isFocus = true
–Change body to dynamic while we are moving the testobject around
event.target.bodyType = “dynamic”

– Create a temporary touch joint and store it in the object for later reference
body.tempJoint = physics.newJoint( “touch”, body, event.x, event.y )

elseif body.isFocus then
if “moved” == phase then

– Update the joint to track the touch
body.tempJoint:setTarget( event.x, event.y )

elseif “ended” == phase or “cancelled” == phase then
stage:setFocus( body, nil )
body.isFocus = false
event.target:setLinearVelocity( 0, 0 )
event.target.angularVelocity = 0

–After the event ends, change body back to static.
event.target.bodyType = “dynamic”

– Remove the joint when the touch ends
body.tempJoint:removeSelf()
–print (“testobject drag ended”)
end
end

– Stop further propagation of touch event
return true
end

local function clicker ()
print (“clickity click”)
if testobject.rotation ~= 0 then print (“1 more degree”)
–audio.play(click)

end
end

testobject:addEventListener( “touch”, clicker )
testobject:addEventListener( “touch”, dragBody )

[/code] [import]uid: 61600 topic_id: 27557 reply_id: 327557[/import]

Hey Nick

‘Negation of equality’ (~=) means that the check is for inequality - basically, it’s the opposite check to the double equals (==) check for equality. It returns true if the two values that you are comparing are not equal.

Anyway, to quickly achieve something like what you’re after, I’ve removed the seperate touch listener for the test object, and added the call to the clicker function as part of the ‘moved’ phase of the dragBody function.

What it does is uses math.floor to truncate the rotation value to get a whole number - basically just chops off the decimal part.

Next, there’s an if statement that uses the modulo operator to calculate whether the rotation value is exactly divisible by 5. If it is, then it will run the code inside the statement - it’s just printing out to the console at the moment, but obviously your click audio would go here, etc.

In my opinion, I think you’re right about playing the click on every increment of one - it’d be too much. As it is set up in the code below, with it playing every 5 intervals, it will be cleaner.

[lua]local physics = require “physics”
physics.start(true)
physics.setDrawMode(“debug”)

–DECLARE WIDTH AND HEIGHT SHORTCUT VARIABLES
local _W = display.contentWidth
local _H = display.contentHeight
local refpoint
local testobject
–local click = audio.loadSound (“click.wav”)

print (“wtfbbq kyle this code is pissing me off and I want to die”)

local refpoint = display.newCircle (_W/2, _H/2, 5)
physics.addBody(refpoint, “static”, {isSensor = true, radius = 5})
refpoint:setFillColor (255,0,0)
refpoint.alpha = 1

–======================================================================================
–testobject - ATTACHES TO REFERENCE POINT VIA “PIVOT”
local testobject = display.newCircle (refpoint.x, refpoint.y, 150)
physics.addBody( testobject, {radius = 150})
testobject.isSleepingAllowed = false
testobject.alpha = 1
testobject.x = refpoint.x
testobject.y = refpoint.y

–Some stuff I was messing around with, trying to capture numbers
–and to get degrees or something…grr
local av = testobject.angularVelocity
local ad = testobject.angularDamping
local lv = testobject.LinearVelocity
local r = testobject.rotation

–======================================================================================
–PIVOT JOINT THAT CONNECTS THE REFERENCE POINT TO testobject
local testobjectJoint = physics.newJoint ( “pivot”, refpoint, testobject, refpoint.x, refpoint.y)

–X and Y touch accurate – no “snapping”
local function dragBody( event )
–print (“testobject drag started”)
local body = event.target
local phase = event.phase
local stage = display.getCurrentStage()

if “began” == phase then

stage:setFocus( body, event.id )
body.isFocus = true
–Change body to dynamic while we are moving the testobject around
event.target.bodyType = “dynamic”

– Create a temporary touch joint and store it in the object for later reference
body.tempJoint = physics.newJoint( “touch”, body, event.x, event.y )

elseif body.isFocus then
if “moved” == phase then

– Calculate the integer value of rotation
local calculatedRotation = math.floor(body.rotation)

– Check if exactly divisible by 5
if (calculatedRotation % 5) == 0 then

print (“Rotation: “…math.floor(body.rotation)…” clickity click”)
–audio.play(click)

end

– Update the joint to track the touch
body.tempJoint:setTarget( event.x, event.y )

elseif “ended” == phase or “cancelled” == phase then
stage:setFocus( body, nil )
body.isFocus = false
event.target:setLinearVelocity( 0, 0 )
event.target.angularVelocity = 0

–After the event ends, change body back to static.
event.target.bodyType = “dynamic”

– Remove the joint when the touch ends
body.tempJoint:removeSelf()
–print (“testobject drag ended”)
end
end

– Stop further propagation of touch event
return true
end

testobject:addEventListener( “touch”, dragBody ) [/lua]

You’ll notice in the print output in the console that it sometimes prints a few times as it’s catching the same value occassionally - this would play your click audio multiple times. It needs cleaning up a bit with some flags/checks but I’ll let you handle that. Obviously, let me know if you need any more help with that. Hopefully, this will get you up and running again though.

One more thing, if the above code isn’t suitable, you could always use an enterFrame Runtime event that calls the clicker function every frame and checks if the rotation is divisible by 5. If it is, play the audio. Again, you’ll need some kind of flag so that it doesn’t play the audio more than once for each pass of an interval, or it might potentially try to play the audio on every frame - not good.
.

Regards

Adam
.
.

EDIT: Apologies for the weird formatting in the code - tried to sort it out but not sure what’s going on with it. It doesn’t look like that in my editor. [import]uid: 74503 topic_id: 27557 reply_id: 111959[/import]

ahhh HAH!

I went about it the wrong way I guess, I see you just embedded it inside the drag code where I was doing a function outside of that.

I never used the math floor before, as math is my mortal enemy lol, but i’m getting better. This works decently, however I can see what you are saying. It does fire off rapidly in succession, and if I rotate to fast it seems to skip a click.

Ok so I was trying to think how would I prevent the double firing? Would it be something like creating a local click sound = clickisactive (some kind of flag) or click is playing and if click is playing wait or how would I flag that?

This is great though, I can see the usefulness of the math floor for other purposes too. The whole truncating thing was confusing me as I didn’t know how to approach it. I was reading lua 5.1 ref programming guide, lua gems and the ref guide and couldn’t figure it out.

Thanks again this is on the right track, if you have a suggestion for the flag thing let me know. I’ll bang away on it (i’ve made several attempts so far, nothing worked yet haha).

all part of the learning experience I guess.

thanks again!

ng [import]uid: 61600 topic_id: 27557 reply_id: 111991[/import]

I’ve just quickly tried implementing a flag in the code but it lacks any real accuracy. It’s not updating during the moved phase of the touch event quickly enough and it’s causing it to either repeat the ‘click’, or to skip some completely if moved quickly.

To make it update quicker, I’ve removed the code that we implemented earlier and reinstated it into it’s own function that acts as a listener for a Runtime event that’s called every frame (as I suggested earlier).

A new variable (lastClick) now keeps track of the last interval that made the ‘click’. We check if the rotation is divisible by 5 AND that it’s not the same value of lastClick to ensure that it’s not repeating the click multiple times. This works well.

However, if you move it quickly, even the enterFrame doesn’t quite keep up with it. This can be made a little more accurate though by setting the FPS to 60 in a config.lua , but it’s still not perfect and can miss some clicks. I’ll post this revised code below so that you can have a play with it. Maybe try limiting the maximum rotation speed to increase the accuracy.

Another way that may be more accurate (not sure though) is to use a ‘property callback’. Jonathan Beebe wrote a tutorial on it a while ago here:

http://www.coronalabs.com/blog/2012/05/01/tutorial-property-callbacks/

Basically, you create a proxy using Jonathan’s proxy.lua module and it listens for changes in any of the objects properties that you set (in this case .rotation). Whenever the property is altered, it calls the listener function. Using the same methods we’ve already been using, maybe you can get better results that way? It’s something else to explore at least if you’re still having problems later on.

Anyway, here’s the revised code:

[lua]local physics = require “physics”
physics.start(true)
physics.setDrawMode(“debug”)

–DECLARE WIDTH AND HEIGHT SHORTCUT VARIABLES
local _W = display.contentWidth
local _H = display.contentHeight
local refpoint
local testobject
–local click = audio.loadSound (“click.wav”)

print (“wtfbbq kyle this code is pissing me off and I want to die”)

local refpoint = display.newCircle (_W/2, _H/2, 5)
physics.addBody(refpoint, “static”, {isSensor = true, radius = 5})
refpoint:setFillColor (255,0,0)
refpoint.alpha = 1

–======================================================================================
–testobject - ATTACHES TO REFERENCE POINT VIA “PIVOT”
local testobject = display.newCircle (refpoint.x, refpoint.y, 150)
physics.addBody( testobject, {radius = 150})
testobject.isSleepingAllowed = false
testobject.alpha = 1
testobject.x = refpoint.x
testobject.y = refpoint.y

–Some stuff I was messing around with, trying to capture numbers
–and to get degrees or something…grr
local av = testobject.angularVelocity
local ad = testobject.angularDamping
local lv = testobject.LinearVelocity
local r = testobject.rotation

–======================================================================================
–PIVOT JOINT THAT CONNECTS THE REFERENCE POINT TO testobject
local testobjectJoint = physics.newJoint ( “pivot”, refpoint, testobject, refpoint.x, refpoint.y)

–X and Y touch accurate – no “snapping”
local function dragBody( event )
–print (“testobject drag started”)

local body = event.target
local phase = event.phase
local stage = display.getCurrentStage()

if “began” == phase then

stage:setFocus( body, event.id )
body.isFocus = true
–Change body to dynamic while we are moving the testobject around
event.target.bodyType = “dynamic”

– Create a temporary touch joint and store it in the object for later reference
body.tempJoint = physics.newJoint( “touch”, body, event.x, event.y )

elseif body.isFocus then
if “moved” == phase then

– Update the joint to track the touch
body.tempJoint:setTarget( event.x, event.y )

elseif “ended” == phase or “cancelled” == phase then
stage:setFocus( body, nil )
body.isFocus = false
event.target:setLinearVelocity( 0, 0 )
event.target.angularVelocity = 0

–After the event ends, change body back to static.
event.target.bodyType = “dynamic”

– Remove the joint when the touch ends
body.tempJoint:removeSelf()
–print (“testobject drag ended”)
end
end

– Stop further propagation of touch event
return true
end

– Variable to keep track of the last value causing a ‘click’ to prevent it repeating
local lastClick = 0

local function clicker ()

local calculatedRotation = math.floor(testobject.rotation)

– Check if exactly divisible by 5
if (calculatedRotation % 5) == 0 and (calculatedRotation ~= lastClick) then

print (“Rotation: “…calculatedRotation…” clickity click”)
–audio.play(click)

– Set the lastClick to the current rotation value causing the ‘click’
lastClick = calculatedRotation

end

end

Runtime:addEventListener(“enterFrame”, clicker)
testobject:addEventListener( “touch”, dragBody )[/lua]

Hope this helps and let me know how you get on with it. [import]uid: 74503 topic_id: 27557 reply_id: 112011[/import]

I set the config.lua to 60 and put

testobject.angularDamping = 40 which helped some. If I really slow it down then its fairly accurate.

I’ll read more about the property callbacks. I didn’t think this would be THAT complicated hehe. This was more of a “polish” feature on my game, but once I got it partially working, now I am on the EPIC QUEST to conquer it haha. I’ll hunt down the property callbacks and see if it’s something I can try out and i’ll post back here because I am sure that I will get stuck (again, what else is new).

Thanks for posting some new code, that helped a bunch, maybe might help others if they are so interested in something specific like this.
While I am thinking about it (this is a phase 2 thing) is perhaps giving 12 degrees and “stays” on the volume knob and putting a light at each indicator. So you would rotate the knob and even if your finger kept going just a little bit it wouldn’t turn again until it moved a bit more beyond a threshold… I know at techority.com (Peach’s site) they made some fancy volume knob which is what got me thinking about this clicking thing (which that doesn’t do). Anyway, that was just like extra credit.

ng [import]uid: 61600 topic_id: 27557 reply_id: 112012[/import]

I set the config.lua to 60 and put

testobject.angularDamping = 40 which helped some. If I really slow it down then its fairly accurate.

I’ll read more about the property callbacks. I didn’t think this would be THAT complicated hehe. This was more of a “polish” feature on my game, but once I got it partially working, now I am on the EPIC QUEST to conquer it haha. I’ll hunt down the property callbacks and see if it’s something I can try out and i’ll post back here because I am sure that I will get stuck (again, what else is new).

Thanks for posting some new code, that helped a bunch, maybe might help others if they are so interested in something specific like this.
While I am thinking about it (this is a phase 2 thing) is perhaps giving 12 degrees and “stays” on the volume knob and putting a light at each indicator. So you would rotate the knob and even if your finger kept going just a little bit it wouldn’t turn again until it moved a bit more beyond a threshold… I know at techority.com (Peach’s site) they made some fancy volume knob which is what got me thinking about this clicking thing (which that doesn’t do). Anyway, that was just like extra credit.

ng [import]uid: 61600 topic_id: 27557 reply_id: 112013[/import]

I set the config.lua to 60 and put

testobject.angularDamping = 40 which helped some. If I really slow it down then its fairly accurate.

I’ll read more about the property callbacks. I didn’t think this would be THAT complicated hehe. This was more of a “polish” feature on my game, but once I got it partially working, now I am on the EPIC QUEST to conquer it haha. I’ll hunt down the property callbacks and see if it’s something I can try out and i’ll post back here because I am sure that I will get stuck (again, what else is new).

Thanks for posting some new code, that helped a bunch, maybe might help others if they are so interested in something specific like this.
While I am thinking about it (this is a phase 2 thing) is perhaps giving 12 degrees and “stays” on the volume knob and putting a light at each indicator. So you would rotate the knob and even if your finger kept going just a little bit it wouldn’t turn again until it moved a bit more beyond a threshold… I know at techority.com (Peach’s site) they made some fancy volume knob which is what got me thinking about this clicking thing (which that doesn’t do). Anyway, that was just like extra credit.

ng [import]uid: 61600 topic_id: 27557 reply_id: 112014[/import]

**I double posted by accident, so disregard this text**

why are you still reading me nothing to see here :slight_smile: [import]uid: 61600 topic_id: 27557 reply_id: 112015[/import]

HaHa. Looks like you got a bit trigger happy on the ‘Submit’ button whilst posting above…

It was actually me who made the artwork tutorial for the control knob for Techority :slight_smile:

I also wrote a (quickly put together) accompanying coding tutorial that demonstrates how to use the artwork created in that tutorial to control the volume in the way in what you’re trying to achieve here.

Although I didn’t implement a ‘click’ on intervals, it does do a good job of controlling the app volume accurately, and also controlling some visual indicator LEDs that turn on/off at the correct intervals.

Here’s a screeny of how the project looks/works:

All that code that handles that can be downloaded from my web site here:

Stylish Volume Control In Corona SDK [import]uid: 74503 topic_id: 27557 reply_id: 112021[/import]

Wow I am TRULY retarded haha. Thats right (looks at code OH YEA!) lol. I remember now (well you just told me but now I put the pieces together).

That volume knob is stylish. The BIGGEST problem I have with rotating anything is the “light source” applied to a knob. I wish there was a way to always have section of a object lit from another direction.

I know I know, that’s why we have engines like unity and other 3d environments. I just always wondered why 2d stuff doesn’t have light source built in.

*oh I just noticed my 4 posts above, I caught one of them, lol I guess my internet was lagging and I just kept clickity clicking.
ng
[import]uid: 61600 topic_id: 27557 reply_id: 112027[/import]

Ha, no problem. As the control knob will be static on the screen (in the X/Y - not the rotation) there is a way that you can fake the light source.

1.) Create the art for the control knob but don’t apply the lighting effect to it directly

2.) Create a separate ‘light’ layer on top of the control knob layer in Photoshop (or whatever) and save them independently from each other - two separate PNGs as opposed to a single one

3.) The control knob will be the image that rotates and the light layer will just sit over the top of it to create the light effect that won’t move. You can use alpha and blends to enhance the effect

I should have done something like this in the tut really, but as I said, it was just a quick demonstration. I could easily spend hours fine tuning things (OCD style) if I let myself get carried away. [import]uid: 74503 topic_id: 27557 reply_id: 112029[/import]

Funny you mention the secondary png on top, I was just experimenting with it.

I think that’s why it is taking me so long to release my game (going on I think 9 months now, lost track). I’m OBSESSED with every pixel and how things align and things like light sources. It bothers me in the 2d realm and I have to deal with it.

However, this option of secondary png is kind of working out, I haven’t quite figured it out i’m messing with gloss effects etc then layering that on top on screen.

I think I am OCD crazy though. I can prove it.

True story, happens EVERYTIME the wife and I go out to a movie:

We show up at the movie, I want to be there at least 10 minutes or more ahead of the actual start time, even 20 is good.

The movie theatre after I walk in my wife starts staring at my eyes. Why?

Why does she does this? Because she knows I am COUNTING the seats. Why do I count the seats because I MUST HAVE THE MIDDLE SEAT IN THE THEATRE OF THAT ROW.

So here is what happens: I count the rows, if they have an odd number AND the spacing of the isles on each side is even (and the theatre seats are not offset) THEN I count. If it’s 9 seats I can go to the 5th seat and be in the middle of the ROW. IF there is an “isle offset” I run a method that eyeballs the isle on each side by using a seat width as measurement. If I see that there is a isle on ONE side of the theatre, but not the other. I can figure that ok 2 and a half seats make an isle, then I subtract that from the row count and do my best to find the middle. Otherwise I’ll flip out…

That’s just one example, I tell that to everyone because I am PROUD of it, and even though people are like “WHAT THE F IS WRONG WITH YOU” I just smile…it’s awesome :slight_smile:

lol. CANT TOUCH THIS. [import]uid: 61600 topic_id: 27557 reply_id: 112037[/import]

hmmmmm…

I saw this

http://docs.coronalabs.com/api/event/accelerometer/deltaTime.html

And it says this…
“Accelerometer measurements will not be recorded at the exact times specified by the system.setAccelerometerInterval() function. This means you cannot assume that a configured interval of 10 Hz (i.e.: 100 milliseconds) will yield measurements recorded exactly 100 milliseconds apart. These measurements will likely be recorded slightly late. This is a limitation of the operating system on both iOS and Android. To compensate for this, event.deltaTime is provided to help make your calculations as accurate as possible.”
And you may say “What does this have to do with rotating and clicking, that is for acceleration”. I realize that my good sir, but allow me to elaborate.

I bet that this:

“This means you cannot assume that a configured interval of 10 Hz (i.e.: 100 milliseconds) will yield measurements recorded exactly 100 milliseconds apart. These measurements will likely be recorded slightly late. This is a limitation of the operating system on both iOS and Android.”

means that my clicking scenario is probably not going to work the way I want at least not as accurate as I want.

Time to dig some more!

ng
[import]uid: 61600 topic_id: 27557 reply_id: 112062[/import]