Godot Version
godot 4.3.stable
Question
I have a player as a characterbody2d node, but when It walks on a collision polygon the movement gets all jittery and sometimes the player even just gets stuck and can't move. How do I fix this?
It’s also not a regular character controller, it is designed to walk around a spherical body that is also moving (although without physics calculations) and the planet the player is on also updates the player’s position every time it moves by getting the amount it has travelled every frame and adding that to the player’s position as well as its own. I have a planet that is a polygon (not a sphere cause a sphere can’t have any bumps in it and planets aren’t perfectly round).
please help, It ruins the gameplay and I’ve been stuck on it for ages now. If you want to see some code, I can share it
Yes, share some code. Is all the movement happening during the physics update?
the planet is updating its position with _process and the player _physics_process because for some reason I can’t be bothered to work out it means that you don’t notice that the planet is moving
heres the player script:
extends CharacterBody2D
@export var speed : float = 100.0
@export var jump_vel : float = 55.0
@export var mode : int = 0
@export var currentplanet : Node = null
var dir = Vector2.DOWN
var gravitational_field_strength : float = 0.0
var dist_to_planet : float = 0.0
var target_eyepos : Vector2 = Vector2()
var interacting : bool = false
var interacting_node : Node = null
var rocket : String = ""
var oxygen : float = 100.0
func _ready() -> void:
if currentplanet != null:
gravitational_field_strength = currentplanet.gravity
func _physics_process(delta : float) -> void:
$heat.global_rotation_degrees = rad_to_deg(velocity.angle()) - 90.0
if currentplanet != null and currentplanet.has_atmosphere:
$heat.modulate.a = lerp($heat.modulate.a, clamp((pcent(velocity.length(), 2525.0) / 100.0) - 0.25, 0.0, 1.0), delta * 2.0)
else:
$heat.modulate.a = lerp($heat.modulate.a, 0.0, delta * 2.0)
oxygen = clamp(oxygen, 0.0, 100.0)
$canvas/info/oxygen/bar.value = oxygen
if mode == 2 and get_tree().current_scene.get_node(rocket) != null:
if "maxfuel" in get_tree().current_scene.get_node(rocket):
$canvas/info/fuel/bar.max_value = get_tree().current_scene.get_node(rocket).maxfuel
if "fuel" in get_tree().current_scene.get_node(rocket):
$canvas/info/fuel.visible = get_tree().current_scene.get_node(rocket).fuel > 0.0
$canvas/info/fuel/bar.value = get_tree().current_scene.get_node(rocket).fuel
else:
$canvas/info/fuel.hide()
for i in $canvas/info.get_children():
if i is VBoxContainer:
i.get_node("label").text = i.name.to_upper()
if currentplanet != null:
gravitational_field_strength = currentplanet.gravity
else:
gravitational_field_strength = 0.0
$canvas/gravity.text = "GRAVITY : " + str(round(gravitational_field_strength * dist_to_planet * 100.0) / 100.0)
$suit.visible = mode != 2
$arrow.visible = get_tree().current_scene.markervisible
if get_parent().current_camera != null:
$arrow.scale = Vector2(0.018, 0.018) / get_tree().current_scene.current_camera.zoom
$arrow.look_at(get_parent().markerpos)
if currentplanet != null:
$planetrotation.global_position = currentplanet.global_position
$planetrotation.look_at(global_position)
if get_parent().current_camera != null:
$camera.enabled = get_tree().current_scene.current_camera == $camera
var zoom : float
if Input.is_action_just_pressed("zoomin"):
zoom = 1.0
elif Input.is_action_just_pressed("zoomout"):
zoom = -1.0
else:
zoom = 0.0
if $camera.enabled:
$camera.zoom = clamp($camera.zoom + Vector2(zoom, zoom) / 10, Vector2(0.1, 0.1), Vector2(9.0, 9.0))
if get_parent().current_camera != null:
$playermarker.scale = Vector2(0.025, 0.025) / get_tree().current_scene.current_camera.zoom
$playermarker.visible = get_tree().current_scene.current_camera.zoom.x <= 0.2
interacting = mode != 2 and interacting
if Input.is_action_just_pressed("interact") and interacting:
rocket = interacting_node.name
if interacting_node != null:
if interacting_node == get_tree().current_scene.get_node(rocket):
mode = 2
if Input.is_action_just_pressed("leave") and mode == 2:
mode = 0
if get_tree().current_scene.get_node(rocket) != null:
global_position = get_tree().current_scene.get_node(rocket).to_global(get_tree().current_scene.get_node(rocket).playerexitpos)
velocity = get_tree().current_scene.get_node(rocket).velocity
$etointeract.visible = interacting and !$playermarker.visible
$canvas/planet_minimap.visible = currentplanet != null
$canvas/planet_minimap.pivot_offset = $canvas/planet_minimap.size / 2.0
$canvas/planet_minimap.rotation_degrees = -$planetrotation.rotation_degrees - 90.0
if currentplanet == null:
if mode != 2:
mode = 1
dist_to_planet = 0.0
else:
dist_to_planet = invert((global_position.distance_to(currentplanet.global_position) - (currentplanet.radius + $detect/collider.shape.radius)) / (currentplanet.get_node("gravitationalfield/collider").shape.radius - (currentplanet.radius + $detect/collider.shape.radius)), 1.0)
dist_to_planet = clamp(dist_to_planet, 0.1, 1.0)
if currentplanet != null and currentplanet.has_oxygen and mode != 2:
oxygen += delta * dist_to_planet
elif mode != 2:
oxygen -= delta / 4.0
elif get_tree().current_scene.get_node(rocket) != null and get_tree().current_scene.get_node(rocket).fuel > 0.0:
oxygen += delta
if mode == 0:
$collider.disabled = false
if currentplanet != null:
dir = (currentplanet.global_position - global_position).normalized()
velocity += delta * dir * gravitational_field_strength * dist_to_planet * 10.0
var right_vector: Vector2 = dir.orthogonal()
var direction: float = Input.get_axis("left", "right")
if direction:
if mode == 0:
velocity += delta * dir * gravitational_field_strength * 5.0 * direction
target_eyepos.x = direction * 70.0
velocity = velocity.slide(right_vector) + direction * speed * right_vector
else:
target_eyepos.x = 0.0
velocity = velocity.slide(right_vector)
if mode == 1:
var directiony : float = Input.get_axis("jump", "down")
if directiony:
target_eyepos.y = Input.get_axis("jump", "down") * 70.0
velocity = velocity.slide(dir) + directiony * speed * dir
else:
target_eyepos.y = 0.0
velocity = velocity.slide(dir)
var angle : float = Input.get_axis("rotateleft", "rotateright")
if angle:
rotation_degrees += angle * 2.0
dir = Vector2.DOWN.rotated(rotation).normalized()
elif mode == 0:
$collider.disabled = false
target_eyepos.y = 0.0
elif mode == 2 and get_tree().current_scene.get_node(rocket) != null:
$collider.disabled = true
target_eyepos = Vector2()
velocity = Vector2()
position = get_tree().current_scene.get_node(rocket).position
rotation_degrees = get_tree().current_scene.get_node(rocket).rotation_degrees
if Input.is_action_pressed("jump") and is_on_floor():
velocity = velocity.slide(dir) + dir * -jump_vel
up_direction = -dir
move_and_slide()
if mode == 0:
rotation_degrees = lerp_deg(rotation_degrees, rad_to_deg(dir.angle()) - 90.0, delta * 5.0)
$suit/leye.position = lerp($suit/leye.position, target_eyepos + Vector2(-150.0, -500.0), delta * 10.0)
$suit/reye.position = lerp($suit/reye.position, target_eyepos + Vector2(150.0, -500.0), delta * 10.0)
$suit/leye.position.y = clamp($suit/leye.position.y, -650.0, 0.0)
$suit/reye.position.y = clamp($suit/reye.position.y, -650.0, 0.0)
func _on_detect_area_entered(area: Area2D) -> void:
if area.is_in_group("gravitational_field"):
print(area.get_parent())
currentplanet = area.get_parent()
$canvas/planettitle.text = currentplanet.name.capitalize()
$canvas/planetmessage.text = "'" + currentplanet.message.capitalize() + "'"
if mode != 2:
mode = 0
$textanimator.stop()
$textanimator.play("show")
if area.is_in_group("interact"):
interacting = true
interacting_node = area.get_parent()
func detect_area_exited(area: Area2D) -> void:
if area.is_in_group("gravitational_field"):
print(area.get_parent())
$canvas/planettitle.text = "Now exiting " + currentplanet.name.capitalize()
$canvas/planetmessage.text = "into the vast reaches of space"
$textanimator.play("show")
currentplanet = null
if area.is_in_group("interact"):
interacting = false
interacting_node = null
func pcent(what, out_of):
return what / out_of * 100.0
func invert(val, max):
return -val + max
func lerp_deg(angle : float, to : float, weight : float) -> float:
return rad_to_deg(lerp_angle(deg_to_rad(angle), deg_to_rad(to), weight))
*rocket is a string var and not a node because I was experimenting with something a while ago
You definitely should put all physics relevant movement and rotation into _physics_process.
Also, for people to be able to help you, you should reduce your code to only the relevant sections.
1 Like
but I still don’t know whats causing it