Godot Version
4.5.1.stable
Question
Hi! I’m new to Godot (but not completely new to gamedev). I’ve spent the past week or so trying to recreate the 3D grid movement from Pokemon Black/White. I’m using this 2D tutorial as a starting point, and just as of today I’ve got it working (yippee!). The only issue I’m running into now is when going up slopes the movement isn’t smooth, it’s all jittery because the Y is slightly offset, I think. I can’t directly upload a video yet but here’s an link to one.
I’m not sure exactly what’s causing this, or how to fix it. Anyone else have a clue?
I have a suspicion it has to do with the tweens I’m using to move my player, but idk. This code below is what is supposed to be smoothly snapping the character to the floor, the rest of the script is in the block at the bottom.
Thanks much (•:
if floor_ray.is_colliding():
floor_height = floor_ray.get_collision_point()
position.y = floor_height.y
extends CharacterBody3D
# Movement variables
const tile_size = 1
var speed : float
@export var walk_speed = 0.45
@export var sprint_speed = 0.2
@onready var collision_ray = $collision_raycast
@onready var floor_ray = $floor_raycast
var input_dir # May be better refered to as target_pos, but eh
var is_moving = false # May be better refered to as can_move, but eh
var floor_height : Vector3
# Animation variables
var facing : String
var button_timer = 0
# Movement
func _physics_process(delta: float) -> void:
# Change speeds
if Input.is_action_pressed("sprint") and is_moving == false:
speed = sprint_speed
else:
speed = walk_speed
# Snap player to floor
if floor_ray.is_colliding():
floor_height = floor_ray.get_collision_point()
position.y = floor_height.y
# Get input to decide where the target position is, then move_and_slide (??? what does that mean)
input_dir = Vector3.ZERO # If player isnt trying to move, set target to none
if button_timer > 1 : button_timer = 1 # Just so the button timer doesen't go crazy
if Input.is_action_pressed("move_down"):
input_dir = Vector3(0, 0, 1)
facing = "down"
move()
button_timer += 0.1
elif Input.is_action_pressed("move_up"):
input_dir = Vector3(0, 0, -1)
facing = "up"
move()
button_timer += 0.1
elif Input.is_action_pressed("move_right"):
input_dir = Vector3(1, 0, 0)
facing = "right"
move()
button_timer += 0.1
elif Input.is_action_pressed("move_left"):
input_dir = Vector3(-1, 0 ,0)
facing = "left"
move()
button_timer += 0.1
else:
button_timer = 0
# Set position
func move():
if button_timer > 0.4:
if input_dir.z != 0:
collision_ray.target_position = input_dir * (tile_size + 0.01)
# That little 0.01 is too make sure the player doesen't move into any collision that's not perfectly on the grid.
collision_ray.force_raycast_update()
if not collision_ray.is_colliding():
if is_moving == false:
is_moving = true
var tween = create_tween()
tween.tween_property(self, "position:z", position.z + (input_dir.z * tile_size), speed)
tween.tween_callback(move_false)
elif input_dir.x != 0:
collision_ray.target_position = input_dir * (tile_size + 0.01)
# That little 0.01 is too make sure the player doesen't move into any collision that's not perfectly on the grid.
collision_ray.force_raycast_update()
if not collision_ray.is_colliding():
if is_moving == false:
is_moving = true
var tween = create_tween()
tween.tween_property(self, "position:x", position.x + (input_dir.x * tile_size), speed)
tween.tween_callback(move_false)
func move_false():
is_moving = false


