I want to create a 2d board game that involve a spinning wheel that has 1 - 6 numbers that pick in random then it will animate in the wheel. how can i code the physics of a spinning wheel while generating an random number 1 - 6??
1 Answer
Since you want a physics simulation, in 2D, in Godot, for a wheel spinning...
We will make the wheel as a RigidBody2D
. It will have a a Sprite
child for visual representation.
A couple options for fixing it in place come to mind:
- You can set its
gravity_scale
to0
, so it does not fall. In theory something else could knock it off. - You can use a
PinJoint2D
to fix it anStaticBody2D
. Make sure thePinJoint2D
hasNode A
andNode B
connected to theStaticBody2D
andRigidBody2D
.
I'll also suggest to have a Node2D
to contain the whole arrangement (that way you can position the parent Node2D
instead of moving its children nodes). It is also convenient to put our code there, in particular if we want to save this as a scene and instance it somewhere else.
CollisionShape
s are NOT strictly necessary in this case, but you may add them too.
For the rotation the simplest solution is to give it a random angular_velocity
.
I'll be writing the code for the parent Node2D
. For example:
func spin() -> void:
$RigidBody2D.angular_velocity = rand_range(500.0, 10000.0)
And it will slow down and stop according to its angular_damp
.
We also need to know when it stopped. For that we can add a custom signal:
signal stopped_spinning
And check the angular velocity in _physics_process
to know when it stopped.
By the way, we cannot rely on the angular velocity hitting 0. Instead we will consider it stopped when it is close to zero.
I will take advantage of set_physics_process
to enable when spinning, and disable it is when done:
extends Node2D
signal stopped_spinning
func _ready() -> void:
set_physics_process(false)
func spin() -> void:
$RigidBody2D.angular_velocity = rand_range(500.0, 10000.0)
set_physics_process(true)
func _physics_process(_delta: float) -> void:
if abs($RigidBody2D.angular_velocity) < 0.02:
$RigidBody2D.angular_velocity = 0.0
emit_signal("stopped_spinning")
set_physics_process(false)
In my test, the angular velocity gets down to 0.010584
. So I picked 0.02
as threshold. If that gives you problems, experiment with the value.
Even though I only put positive angular velocities, I decided to use abs
so the code can handle a negative value.
You can then create a button, and make it call spin
when pressed. You can also handle the custom "stopped_spinning"
signal to get the result. For that, you may use $RigidBody2D.rotation_degrees
and some arithmetic, for example:
func get_value() -> int:
var offset_degrees = 90
var options = 6
var option_degrees = 360 / options
return int(fposmod($RigidBody2D.rotation_degrees + offset_degrees, 360) / option_degrees) + 1
The fposmod
will give you a value between 0 and the second parameter (360 in this case).
I added offset_degrees
to account for the fact that I don't know at what angle the first option is. Also, I added 1 at the end because it would give you values in the range [0, options), but you probably want a value on the range [1, options]. Tweak that as needed.