Jumping on rotation

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By ZENAJ

Hello there, I just want to say that I’m extremely new to Godot and still am trying to find my way into game development. Thus I started developing a small game in which an arrow rotates approx 180 degrees around an origin point at the bottom of the screen, while having to jump around to dodge incoming platforms. At the moment I’m failing a little at properly getting my sprite to jump “away” from the origin point rather than just vertically upwards. I’ve provided the code in its current state below:

var rotation_speed = 90  # Adjust the rotation speed as desired
var rotation_direction = 0 # defines the default state of rotation direction
var jumping = 0 # defines the default state of jumping
var jump_speed = 500 #defines the speed of the jump animation
var jump_height = 0 #defines the default state of height of jump
var jump_distance = 200  # Adjust the jump distance as desired
const MAX_ROTATION = 75 # defines the maximal range of rotation

var forward_vector = Vector2.ZERO #defines the nul state of the x and y vector (0,0)
var vertical_velocity = 0 # defines the default state of vertical_velocity
const GRAVITY = 2000  # Adjust the gravity strength as desired
var dpoint = Vector2(100,0)

    func _process(delta):
        rotation_angle += rotation_speed * rotation_direction * delta
        rotation_angle = clamp(rotation_angle, -MAX_ROTATION, MAX_ROTATION) # 
            sets the margins in both directions

if jumping:
	vertical_velocity -= GRAVITY * delta

jump_height += vertical_velocity * delta

if jump_height <= 0:
	jump_height = 0
	vertical_velocity = 0
	jumping = 0

self.rotation_degrees = rotation_angle
self.position.y = (jump_height*-1)

    func _input(event):
      if event is InputEventKey:
	        if event.is_action_pressed("rotate_left"):
		         rotation_direction = -1  # Rotate left
	        elif event.is_action_pressed("rotate_right"):
		         rotation_direction = 1  # Rotate right
	        elif event.is_action_pressed("jump") and not jumping:
		          jumping = 1
		          vertical_velocity = jump_speed

if event is InputEventKey:
	if event.is_action_released("rotate_left") and rotation_direction == -1:
		rotation_direction = 0  # Stop rotation
	if event.is_action_released("rotate_right") and rotation_direction == 1:
		rotation_direction = 0  # Stop rotation

I’ve also tried to utilize:

var dpoint = Vector2(100,0)
position = dpoint + (position - dpoint).rotated(rotation_angle)

but that just caused a weird jittery glitch when my sprite jumps.

if anyone has something that can give me a clue on how to fix it (or perhaps critique on my code), it’d be much appreciated. :slight_smile:

:bust_in_silhouette: Reply From: PAndras


First of all, I have to say that the placing of whitespace characters are terrible. It’s hardly readable. I assume, that the original programcode does not look like this. I have to emphasise, that I’m quite a beginner with Godot, also am not a professional programmer, so take my critique like that. I didn’t find the bug, It would require a deeper understanding from me, but if you apply some of my tips below, your script would be more understandable.

In your place, I’d use enum a lot. Just like that:

enum Rotation_direction {
STOP = 0,
RIGHT = 1,
LEFT = -1

In my version of this script var jumping would be a bool.

Instead of the _input-function, I’d write this:

func _process(_delta):
  if xnor(Input.is_action_pressed("rotate_left"), Input.is_action_pressed("rotate_right")):
       rotation_direction = Rotation_direction.STOP
  elif Input.is_action_pressed("rotate_right"):
       rotation_direction = Rotation_direction.RIGHT
  elif Input.is_action_pressed("rotate_left"):
       rotation_direction = Rotation_direction.LEFT
  if Input.is_action_just_pressed("jump") and not jumping:
        jumping = true
        vertical_velocity = jump_speed

xnor (a.k.a. exclusive nor) is not a built in function, and it is a matter of taste to use it or not, but you should think about those frames, where the player pushes the right and the left buttons at the same time. In your version the right button just overrwrites the left.

I also recommend to read about the_physics_processfunction. I’d use that for character movement instead of _process.

You directly reset the position of the player’s body. I’d make it a KinematicBody2D node. And then it would have a move_and_collide-method.

Have a nice day.

Thank you for your response. For some reason I wasn’t able to properly line everything up when writing it out. So I shall try to redo it on my pc soon.
Furthermore I shall try out what you’ve suggested and circle back soon enough

A nice day to you too.

ZENAJ | 2023-06-13 15:19

I had to reedit my previous comment. You were actually right about the InputEvent.is_action_pressed method. I mixed it up with Input.is_action_pressed. (Sorry.) But if you want to make your game single player, I think Input.is_action_pressed is just more suitable for you.

PAndras | 2023-06-13 15:46

Alright, i’ll look both of them up since I don’t really know what the difference is.

ZENAJ | 2023-06-13 18:46

:bust_in_silhouette: Reply From: bigstinky

At a quick glance, it looks to me like you are only modifying the objects y position, which could explain why it is only going up and down. Even though the object is rotating that doesn’t mean the x and y axes are rotating with it, you also have to rotate the velocity vector. In fact it doesn’t look like you are using any vectors in your code, which are necessary for any kind of 2D motion. I see at the top you define a vector but I don’t see it used in the program. Also doesn’t look like you are using a Characterbody2D node for the arrow. The Characterbody2D type has a lot of useful methods that make moving characters very simple. I would recommend looking at some of the tutorials in the godot documentation, they have a lot of examples using Characterbody2D and introductions to using vectors.

Alright, sounds like I went an unnecessary more complicated route . I’ll look them up since I couldn’t really find information on specific questions. I’ll make sure to use vectors a lot more.

ZENAJ | 2023-06-14 06:01

If you were using a Characterbody2D your code could look something like.

func _physics_process(delta: float) -> void:
    # code for getting the angle of rotation
    velocity = velocity.normalized() * (velocity.length() - GRAVITY * delta)
    velocity = velocity.rotate(rotation_angle)
    # code for keeping the arrow centered on the origin point

bigstinky | 2023-06-14 06:09

I have utilized this little piece of code (as best as I could) and reworked my node2D to a CharacterBody2D, and it makes everything work a little more nicely indeed. The only problem I currently have is that my sprite is a little off to the side of my intended rotation point. I want to add to this, that my intended rotation point is a little ball at the bottom center of my screen (hence why I clamped a MAX_ROTATION and a -MAX_ROTATION). Is this just a matter of repositioning or connecting the character node to a base node?

Edit: nevermind I got it fixed.

ZENAJ | 2023-06-14 22:10

you may want to check that the sprite is centered at the origin of the character scene, because that is where the position is based on.

bigstinky | 2023-06-15 03:08