• Godot Help
  • I need help rotating a Node3D with Tween (360° limit)

Hi, i'm using tween on a Node3D for the movements in my project.

tween.tween_property(cam_target, "position", temp_v,T_SPEED)

tween.parallel().tween_property(cam_target, "global_rotation_degrees",
				 Vector3(0,90,0),1.5).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_QUINT)

there are 4 tweens like that for each direction 90,-90,0,180 and it works fine but when i reach 360° or -360°, the Node3D do a full 360° before going on.

i tryed to change my cam_target.rotation.y using lerp_angle, or other algos with or without tween but nothing worked as expected.
could you tell me how to do it? so my camera can smoothly turns toward west, east, north and south.

thanks

  • xyz replied to this.

    noals Instead of euler angles, animate the quaternion property. Much better suited for managing orientation in 3D space.

    Really, i'm lost.
    I've been trying for days, doesn't work properly in any way i try and it just confuse me even more with quaternion.
    with lerp, lerp_angle, interpolation, degrees, rad, Vector3, basis, .FOWARD ... ><

    the only thing that i found on the net that kinda helped me understand it a little more is that

    so my target "angles" should be 0.25, -0.25, 0, 0.5 as normalized angle right? but with which algorythm? i failed many times using the interpolation example or lerp example of the doc or any other example i found on the net anyway...
    i'm not even sure if i should keep using the tween for my rotation.

    any enlightment ?

    thx

    • xyz replied to this.

      noals You can do it either with tween or with lerping. If rotation is triggered by user input, lerping may be better because it can be updated/cancelled in realime. Take a look at example I posted in this thread

      • xyz replied to this.

        noals Here's even shorter example that just uses single local axis:

        extends Node3D
        
        var basis_wanted: Basis
        
        func _process(delta):
        	transform.basis = transform.basis.slerp(basis_wanted, .1)
        	
        func _input(event):
        	var axis =  Input.get_axis("ui_right", "ui_left")
        	if axis:
        		basis_wanted *= Basis(Vector3.UP*axis, PI/2)

        xyz And here's the same thing with a tween:

        extends Node3D
        
        var q_wanted: Quaternion
        
        func _input(event):
        	var axis = Input.get_axis("ui_right", "ui_left");
        	if axis:
        		q_wanted *= Quaternion(Vector3.UP*axis, PI/2)
        		create_tween().tween_property(self, "quaternion", q_wanted, .25)

        Here is what i tryed without success ^^;

        var q_wanted: Quaternion
        var w_ax= Vector3(-1,0,0)

        and in my function triggering the tween

        q_wanted *= Quaternion(Vector3.UP*w_ax, PI/2)
        tween.parallel().tween_property(cam_target, "Quaternion", q_wanted, R_SPEED)

        i didn't try much yet but i answer already to explain what i try to do.
        I'm using TextureButton for the signal but it doesn't really trigger the movement, it send a path like "WWNE" to a function that make my cam_target move one tile at a time using the tween.

        so for this example WWNE, the tween will be instantiated 4 times and move my cam_target west, west, north and east; and i was using tween.parallel() for the rotation because it must be triggered at each step of the move and while moving from a direction to another (if it changes).

        i actually changed my function and put it in func _process(delta) because i wanted to try different things with delta but i wasn't successfull either...

        • xyz replied to this.

          noals So each time the camera changes direction you want it to rotate smoothly to face that direction? In case of NSNS there will be three 180 degrees turns?

          noals Here's an example that executes the sequence. If you have a sequence, using a tween is much better option than doing it in _process() where you need to manage the sequence progress yourself. For simplicity, assumed step distance is 1:

          extends Node3D
          
          func execute_move(sequence: String, step_duration = .3, turn_duration = .1, delay = .1 ):
          	var dir = {"N": Vector3.FORWARD, "S": Vector3.BACK, "E": Vector3.RIGHT, "W": Vector3.LEFT }
          	var t = create_tween()
          	for s in sequence:
          		t.tween_property(self, "position", dir[s], step_duration).as_relative()
          		var q = Quaternion(Vector3.UP, atan2(-dir[s].x, -dir[s].z)) 
          		t.parallel().tween_property(self, "quaternion", q, turn_duration);
          		t.tween_interval(delay)

          Call it like this:

          execute_move("NNESW")

            xyz

            Thank you!
            It works perfectly!

            the .as_relative() makes me wonder because i was calculating the coordinate of each step before your method. ^^;
            It's great, thanks again.

            • xyz replied to this.

              noals Try to understand it, not just copy paste it 😉.

              This stuff is rather basic in 3D games. Similar problems pop up over and over during the development process. So if this makes you lose days banging your head against the wall - it's time to change the approach. Instead of relying on luck in finding adequate tutorials and code snippets on the web, put some effort into understanding and learning to apply vector/matrix math and trigonometry. It will make your life much easier in the long run.

              When you write it like that, it's kinda easy to understand, you just use the tangent of the x and the z axis as a rotation arount the "UP" axis that is y and apply it as a quaternion rotation instead of the usual rotation parameter.
              If i get it well, the tangent simply represent the interpolation points of the function.
              It was not that obviious when i tryed it by myself lol I didn't know i was able to use for s in sequnce without getting the size() or length() of the String by the way. I never used quaternion before.

              Thanks for the help.