Dungeon Crawler predefined step length

Godot Version

4.3

Question

Hi folks!
I’n quite new to Godot. I have a question. I’m trying to make a simple Dungeon Crawler game and I crashed right at the beginning. I have tis script for the movement:
extends Node3D

extends CharacterBody3D

var move_distance = 120 
var rotation_angle = PI/2

func _input(event):
	if event.is_action_pressed("ui_up"):
		velocity = -transform.basis.z * move_distance
		move_and_slide()
	elif event.is_action_pressed("ui_down"):
		velocity = transform.basis.z * move_distance
		move_and_slide()
	elif event.is_action_pressed("ui_left"):
		rotate_y(rotation_angle)
	elif event.is_action_pressed("ui_right"):
		rotate_y(-rotation_angle)

But there is an issue with the “var move distance” I discovered the value just by trial/error. But whenever I change the window size, the value is not valid anymore (steps are much longer with bigger screen size). How should I change the script to make 1 m steps no matter what screen size I use? (For the simplicity, the size of the “game unit” is 1 m…)
Thank you in advance

Please update your post with proper formatting using ``` for code snippets.
Also, you mentioned “var move distance”, but it’s not in the code anywhere. What do you mean?

I’m sorry, I didn’t know the rules here. The post is updated with the right code.

I’d assume the simplest way would be to scale your game to the screen size. This recent question shows how to do this How do I make sure that the field of view stays the same for all screen sizes?

If you don’t want to scale then you could probably use the Window class to get the window size and use that to calculate your move_distance. However, I’m not sure if this is the best/easiest way.

1 Like

Thank you so much! That was it (the first method). Although I don’t know where does the final value of the move _distance = 240 come from. It has nothing to do with the GrigMap3D cell size, nor the size of the tile… :smiley:

I believe it’s value is pixels/second

Remember that the values being used (for speed at least) are pixels/second.

Is mentioned on this docs page Kinematic character (2D) — Godot Engine (stable) documentation in English

Edit: I just realised you are using 3D not 2D, so the value won’t be pixels/second, it’ll be meters/second.

1 Like

Could there be another approach? Because according your answer, the distance walked in one keypress could change in more / less complicated scenes. As well as with the change of the resolution. Simply put, the engine isn’t capable to walk exactly 240 pixels/second in every situation… Does it also mean that on a faster computer (mine isn’t any killer machine), the value of move_distance should be different?

You are correct, if the game is running at a different FPS the player will seemingly move faster or slower!

The solution is to multiply the speed by the delta time, this way regardless of the FPS movement will be consistent.

This was also discussed recently in this thread Need Help With Delta Time

The delta parameter in the _process() function refers to the frame length - the amount of time that the previous frame took to complete. Using this value ensures that your movement will remain consistent even if the frame rate changes.

From docs Coding the player — Godot Engine (stable) documentation in English

1 Like

I have tried to modify the scrip to obtain a GridMap tile size and use it as a Player step:

extends CharacterBody3D

const rotation_angle = PI/2
var move_distance

func _ready():
	var grid_map = get_node("../GridMap")
	move_distance = grid_map.cell_size.x

func _physics_process(delta):
	if Input.is_action_just_pressed("ui_up"):
		velocity = -transform.basis.z * move_distance
		move_and_slide()
	elif Input.is_action_just_pressed("ui_down"):
		velocity = transform.basis.z * move_distance
		move_and_slide()
	elif Input.is_action_just_pressed("ui_left"):
		rotate_y(rotation_angle) 
	elif Input.is_action_just_pressed("ui_right"):
		rotate_y(-rotation_angle)

But I get this error: Invalid access to property or key ‘cell_size’ on a base object of type ‘null instance’.
This is the main scene tree:
image
And this is the player’s tree:
image
With the script being put on the CharacterBody3D
I suppose, the path is invalid, but what should it look like, please?

You can’t get use get_node in the player scene as the GridMap is not in the player scene.

How are the main scene and the player scene related?

If the main scene includes the player scene, then you could use an @export variable. You’d then set this to the GridMap via the editors inspector.

Thank you! The relation is displayed on the two screenshots, there is the main scene (Node3D) which contains the CameraPlayer scene (the second screenshot. The script in the question is attached to the CharacterBody3D within the CameraPlayer. The SubViewport is there, because I’d like to make an oldschool Dungeon with the maze displayed only on a part of the screen, the first torch is for testing purposes, the torch in the CameraPlayer is attached to the camera view, so it travels with the player. GridMap is the dungeon maze, GridMap2 Ceiling is its ceiling, which I turn off ocasionally so I can see the maze itself better.
I still struggle with the step size. None of the approaches descibed works well. The new script version is loosely inspired by the Dungeon Crawler tutorial which unfortunately doesn’t work in 4.x anymore


I don’t use rays, there is a CollisionShape instead in the CameraPlayer…

The relation is displayed on the two screenshots, there is the main scene (Node3D) which contains the CameraPlayer scene

Oh yeah, sorry I missed that.

I still struggle with the step size. None of the approaches descibed works well. The new script version is loosely inspired by the Dungeon Crawler tutorial which unfortunately doesn’t work in 4.x anymore

I’m pretty new to Godot myself and have never used 3.x. I’d suggest making new topics if you’d like help porting 3.x code to 4.x.

1 Like