I am using raycasts to detect obstructions and prevent the player from moving. However, I am clearly doing something wrong as the player collides with no vertical walls but is unable to move when under/above a horizontal wall (not even left or right). It seems that the problem lies in the first for loop of _physics_process, specifically with the variable valid_move, but I have no idea why it's behaving like this. Please have a look at the code and see if you can spot the error:
extends CharacterBody2D
var direction := Vector2.ZERO
var target := Vector2.ZERO
var target_reached := true
const SPEED = 150.0
@onready var casts := $RayCasts.get_children() # +x, +y, -x, -y
var valid_move := true
func _ready() -> void:
position = Vector2(8,8)
func _physics_process(delta: float) -> void:
# Check for collisions with walls or enemies in the direction that the player wants to move:
for axis_i in range(2):
if (direction[axis_i] > 0 and casts[axis_i].get_collider()) or (direction[axis_i] < 0 and casts[axis_i+2].get_collider()):
print("this move is illegal")
valid_move = false
else:
print("this move is fine")
valid_move = true
# Handle the acceleration and deceleration:
if direction and valid_move:
if (target-position).length() > 0.00390625:
target_reached = false
position = position.move_toward(target, SPEED * delta)
else:
target_reached = true
position = target
direction = Vector2.ZERO
"""
print("pos:", position)
print("tar:", target)
print("dist:", target-position)
print("pythag dist:", (target-position).length())
print("reached?:", target_reached)
print("dir:", direction)
print("valid?:", valid_move)"""
func _input(event: InputEvent) -> void:
# If the user tries to move, update the direction vector:
if target_reached and (event.is_action_pressed("character_move_left") or event.is_action_pressed("character_move_down") or event.is_action_pressed("character_move_right") or event.is_action_pressed("character_move_up")):
direction = Vector2(Input.get_axis("character_move_left", "character_move_right"),Input.get_axis("character_move_up", "character_move_down"))
target = position + direction * 16
#print(target)
I have changed the code to the following because I realised that a for loop would potentially set the vaild_move variable back to true in certain cases and thought this would fix it. It did not:
extends CharacterBody2D
var direction := Vector2.ZERO
var target := Vector2.ZERO
var target_reached := true
const SPEED = 150.0
@onready var casts := $RayCasts.get_children() # +x, +y, -x, -y
var valid_move := true
func _ready() -> void:
position = Vector2(8,8)
func _physics_process(delta: float) -> void:
# Check for collisions with walls or enemies in the direction that the player wants to move:
if (direction[0] > 0 and casts[0].get_collider()) or (direction[1] < 0 and casts[2].get_collider()) or (direction[0] > 0 and casts[1].get_collider()) or (direction[1] < 0 and casts[3].get_collider()):
print("this move is illegal", direction)
valid_move = false
else:
print("this move is fine", direction)
valid_move = true
# Handle the acceleration and deceleration:
if direction and valid_move:
if (target-position).length() > 0.00390625:
target_reached = false
position = position.move_toward(target, SPEED * delta)
else:
target_reached = true
position = target
direction = Vector2.ZERO
"""
print("pos:", position)
print("tar:", target)
print("dist:", target-position)
print("pythag dist:", (target-position).length())
print("reached?:", target_reached)
print("dir:", direction)
print("valid?:", valid_move)"""
func _input(event: InputEvent) -> void:
# If the user tries to move, update the direction vector:
if target_reached and (event.is_action_pressed("character_move_left") or event.is_action_pressed("character_move_down") or event.is_action_pressed("character_move_right") or event.is_action_pressed("character_move_up")):
direction = Vector2(Input.get_axis("character_move_left", "character_move_right"),Input.get_axis("character_move_up", "character_move_down"))
target = position + direction * 16
#print(target)
extends CharacterBody2D
var direction := Vector2.ZERO
var target := Vector2.ZERO
var target_reached := true
const SPEED = 150.0
@onready var casts := $RayCasts.get_children() # +x, +y, -x, -y
var valid_move := true
func _ready() -> void:
position = Vector2(8,8)
func _physics_process(delta: float) -> void:
# Check for collisions with walls or enemies in the direction that the player wants to move:
if (direction[0] > 0 and casts[0].get_collider()) or (direction[1] > 0 and casts[1].get_collider()) or (direction[0] < 0 and casts[2].get_collider()) or (direction[1] < 0 and casts[3].get_collider()):
print("this move is illegal", direction)
valid_move = false
else:
print("this move is fine", direction)
valid_move = true
# Handle the acceleration and deceleration:
if direction and valid_move:
if (target-position).length() > 0.00390625:
target_reached = false
position = position.move_toward(target, SPEED * delta)
else:
target_reached = true
position = target
direction = Vector2.ZERO
"""
print("pos:", position)
print("tar:", target)
print("dist:", target-position)
print("pythag dist:", (target-position).length())
print("reached?:", target_reached)
print("dir:", direction)
print("valid?:", valid_move)"""
func _input(event: InputEvent) -> void:
# If the user tries to move, update the direction vector:
if target_reached and (event.is_action_pressed("character_move_left") or event.is_action_pressed("character_move_down") or event.is_action_pressed("character_move_right") or event.is_action_pressed("character_move_up")):
direction = Vector2(Input.get_axis("character_move_left", "character_move_right"),Input.get_axis("character_move_up", "character_move_down"))
target = position + direction * 16
#print(target)
now the player gets to the edge but they can still move for some reason? idk anyway they move and they get a tiny bit stuck in the wall, I think _physics_process might be moving them a bit before it realises that it’s an invalid move. anyway heres the code:
extends CharacterBody2D
var direction := Vector2.ZERO
var target := Vector2.ZERO
var target_reached := true
const SPEED = 150.0
@onready var casts := $RayCasts.get_children() # +x, +y, -x, -y
var valid_move := true
func _ready() -> void:
position = Vector2(8,8)
func _physics_process(delta: float) -> void:
# Handle the acceleration and deceleration:
if direction and valid_move:
if (target-position).length() > 0.00390625:
target_reached = false
position = position.move_toward(target, SPEED * delta)
else:
target_reached = true
position = target
direction = Vector2.ZERO
# Check for collisions with walls or enemies in the direction that the player wants to move:
if (direction[0] > 0 and casts[0].get_collider()) or (direction[1] > 0 and casts[1].get_collider()) or (direction[0] < 0 and casts[2].get_collider()) or (direction[1] < 0 and casts[3].get_collider()):
print("this move is illegal", direction)
print(target_reached)
valid_move = false
else:
print("this move is fine", direction)
valid_move = true
"""
print("pos:", position)
print("tar:", target)
print("dist:", target-position)
print("pythag dist:", (target-position).length())
print("reached?:", target_reached)
print("dir:", direction)
print("valid?:", valid_move)"""
func _input(event: InputEvent) -> void:
# If the user tries to move, update the direction vector:
if target_reached and (event.is_action_pressed("character_move_left") or event.is_action_pressed("character_move_down") or event.is_action_pressed("character_move_right") or event.is_action_pressed("character_move_up")):
direction = Vector2(Input.get_axis("character_move_left", "character_move_right"),Input.get_axis("character_move_up", "character_move_down"))
target = position + direction * 16
#print(target)
the player can sometimes get 2.5 pixels (the amount that they move per call of physics_process(), at least on my machine) into a wall, but only if their direction has changed from what it was before for some reason.
extends CharacterBody2D
var direction := Vector2.ZERO
var target := Vector2.ZERO
var target_reached := true
const SPEED = 150.0
@onready var casts := $RayCasts.get_children() # +x, +y, -x, -y
var valid_move := true
func _ready() -> void:
position = Vector2(40,24)
func _physics_process(delta: float) -> void:
# Handle the acceleration and deceleration:
if direction and valid_move:
if (target-position).length() > 0.00390625:
target_reached = false
position = position.move_toward(target, SPEED * delta)
else:
target_reached = true
position = target
# Check for collisions with walls or enemies in the direction that the player wants to move:
if (direction[0] > 0 and casts[0].get_collider()) or (direction[1] > 0 and casts[1].get_collider()) or (direction[0] < 0 and casts[2].get_collider()) or (direction[1] < 0 and casts[3].get_collider()):
#print("this move is illegal", direction)
#print("posisionn", position)
#print(target_reached)
valid_move = false
else:
#aprint("this move is fine", direction)
valid_move = true
"""
print("pos:", position)
print("tar:", target)
print("dist:", target-position)
print("pythag dist:", (target-position).length())
print("reached?:", target_reached)
print("dir:", direction)
print("valid?:", valid_move)"""
func _input(event: InputEvent) -> void:
# If the user tries to move, update the direction vector:
if target_reached and (event.is_action_pressed("character_move_left") or event.is_action_pressed("character_move_down") or event.is_action_pressed("character_move_right") or event.is_action_pressed("character_move_up")):
direction = Vector2(Input.get_axis("character_move_left", "character_move_right"),Input.get_axis("character_move_up", "character_move_down"))
target = position + direction * 16
#print(target)
It’s fixed!!! I changed a couple things, like making it so that the player only actually moves at the end of _physics_process(), removing valid_move entirely and getting rid of invalid moves by resetting the target to position. Here’s the final code if anyone wants it:
extends CharacterBody2D
var direction := Vector2.ZERO
var target := Vector2.ZERO
var target_reached := true
const SPEED = 150.0
@onready var casts := $RayCasts.get_children() # +x, +y, -x, -y
func _ready() -> void:
# Align to grid:
position = Vector2(8,8)
func _physics_process(delta: float) -> void:
# Handle the acceleration and deceleration:
if direction:
if (target-position).length() > 0.00390625:
target_reached = false
else:
# Close enough, put them exactly on the tile:
target_reached = true
position = target
# Check for collisions with walls or enemies in the direction that the player wants to move:
if (direction[0] > 0 and casts[0].get_collider()) or (direction[1] > 0 and casts[1].get_collider()) or (direction[0] < 0 and casts[2].get_collider()) or (direction[1] < 0 and casts[3].get_collider()):
# Make sure the player doesn't try to move:
target = position
# Move the player a little bit:
if not target_reached:
position = position.move_toward(target, SPEED * delta)
func _input(event: InputEvent) -> void:
# If the user tries to move, update the direction vector:
if target_reached and (event.is_action_pressed("character_move_left") or event.is_action_pressed("character_move_down") or event.is_action_pressed("character_move_right") or event.is_action_pressed("character_move_up")):
direction = Vector2(Input.get_axis("character_move_left", "character_move_right"),Input.get_axis("character_move_up", "character_move_down"))
target = position + direction * 16