i'm working on top-down space game built using swift , scenekit following setup:
scnnode representing spaceship
- rotation constrained y axis; values range
-m_pi_2m_pi + m_pi_2 - movement constrained x , z axes.
game controller thumbstick input
- values range
-1.01.0on x , y axes.
when game controller's thumbstick changes position, spaceship should rotate using physics body match thumbstick's radian.
the target radian of thumbstick can calculated following:
let targetradian = m_pi_2 + atan2(-y, -x) the current radian of node can obtained following:
let currentradian = node.presentationnode.rotation.w * node.presentationnode.rotation.y nstimeinterval deltatime provides time in seconds since last rotation calculation.
how can node rotated using angularvelocity, applytorque, or physics method reach targetradian?
the difference between targetradian , currentradian ranged 0.0 -2π depending on value of currentradian. equation determine shortest direction turn, .clockwise or .counterclockwise, reach targetradian:
let turndirection = (radiandifference + (m_pi * 2)) % (m_pi * 2) < m_pi ? rotationdirection.counterclockwise : rotationdirection.clockwise using applytorque, there possibility over-rotate past targetradian resulting in wobbling effect, compass magnetizing toward point, rotation changes direction , forth reach targetradian. following, while not perfect solution, dampened effect:
let turndampener = abs(radiandifference) < 1.0 ? abs(radiandifference) : 1.0 the complete solution thus:
enum rotationdirection: double { case clockwise = -1.0 case counterclockwise = 1.0 } func rotatenodetowarddirectionalvector(node: scnnode, targetdirectionalvector: (x: double, y: double), deltatime: nstimeinterval) { guard abs(targetdirectionalvector.x) > 0.0 || abs(targetdirectionalvector.y) > 0.0 else { return } let currentradian = double(node.presentationnode.rotation.w * node.presentationnode.rotation.y) let targetradian = m_pi_2 + atan2(-targetdirectionalvector.y, -targetdirectionalvector.x) let radiandifference = targetradian - currentradian let π2 = m_pi * 2 let turndirection = (radiandifference + π2) % π2 < m_pi ? rotationdirection.counterclockwise : rotationdirection.clockwise let absradiandifference = abs(radiandifference) let turndampener = absradiandifference < 1.0 ? absradiandifference : 1.0 node.physicsbody?.applytorque(scnvector4make(0, cgfloat(turndirection.rawvalue), 0, cgfloat(deltatime * turndampener)), impulse: true) }
Comments
Post a Comment