For my first game, I’m attempting to recreate Pac-Man. In order to recreate the fact that he constantly moves, I had the keys simply change Pac-Man’s direction rather than move him directly, and he automatically moves based on that. That worked well, but I realized that there was no grid snapping like in the original, so it was easy to get caught on walls. The only way I could figure to recreate it was to block the players input for a certain amount of time until Pac-Man was in the center of a tile. I have his speed at 100 and my tiles are 16x16, I set the timer to .16 seconds, and of course set it to one shot.
So every time the player moves, it blocks inputs and starts the timer. When the timer runs out, it’s supposed to unblock the input. But upon starting, not only does Pac-Man no longer move at all, but the input is blocked permanently, and the timer seems to never run out. Here’s the code for movement:
func _physics_process(delta):
if allow_input == true:
if direction == 0:
if ray_cast_right.is_colliding():
animated_sprite.play("Idle")
else:
position.x += SPEED * delta
animated_sprite.play("Right")
timer.start()
allow_input = false
print("no move")
if direction == 1:
if ray_cast_down.is_colliding():
animated_sprite.play("Idle")
else:
position.y += SPEED * delta
animated_sprite.play("Down")
timer.start()
allow_input = false
print("no move")
if direction == 2:
if ray_cast_left.is_colliding():
animated_sprite.play("Idle")
else:
position.x -= SPEED * delta
animated_sprite.play("Left")
timer.start()
allow_input = false
print("no move")
if direction == 3:
if ray_cast_up.is_colliding():
animated_sprite.play("Idle")
else:
position.y -= SPEED * delta
animated_sprite.play("Up")
timer.start()
allow_input = false
print("no move")
move_and_slide()
And then the timer
func _on_timer_timeout():
allow_input = true
print("you can move")
The “no move” print does pop up, but not the “you can move” one
It is set to true by default
Here’s the rest of the code if you need it, all set before the above code
extends CharacterBody2D
@onready var animated_sprite = $AnimatedSprite2D
@onready var ray_cast_right = $RayCastRight
@onready var ray_cast_down = $RayCastDown
@onready var ray_cast_left = $RayCastLeft
@onready var ray_cast_up = $RayCastUp
@onready var timer = $Timer
var allow_input = true
#0 right, 1 down, 2 left, 3 up
var direction = 0
const SPEED = 100
func _process(delta):
if Input.is_action_just_pressed("right"):
direction = 0
if Input.is_action_just_pressed("down"):
direction = 1
if Input.is_action_just_pressed("left"):
direction = 2
if Input.is_action_just_pressed("up"):
direction = 3
Hello @PlayerZeroStart !
I’ve been looking at your code and I’m wondering if the player is always colliding. If that’s the case, there is no way you can start the timer because the condition can’t be false. Can you try to print something to check your raycast is working properly? Something like:
if ray_cast_up.is_colliding():
print("Is colliding")
animated_sprite.play("Idle")
Add this line to every condition to check if it is colliding or not (my bet is it is always colliding).
So I figured that shouldn’t be the issue, cause the code is only checking for collision in the direction Pac-Man is facing. I went ahead and tried it anyways just in case, but indeed, the colliding print never happens.
Ok, well we have somewhere to start working.
Something I’m also thinking is, the Idle status is something supposed to happen when the character is not moving or the player doesn´t interact with the game. But in your case, the Idle status is waiting for the player to interact. I don´t know if that is intended or not, I’m just pointing it out because it has caught my attention.
Let´s try to figure out what is happening.
Can you please check if your raycasts lenght is enough to collide with anything?
As I don´t know what it is supposed to hit, check if your raycasts Collide with > Areas and Collide with > Bodies are checked (I don´t know if you are trying to hit an StaticBody or an Area)
So, because of how Pac-Man works, it’s always moving in some direction, and only stops when running into a wall. Initially, I tried to recreate this effect by checking if he was moving, but that didn’t work, so I swapped to this raycast method that worked.
I already know the raycasts work as intended from before I tried to do this timer method, but to answer your questions:
Yes, the raycasts are just long enough that while Pac-Man is in the center of a tile, the raycasts reach into the 4 surrounding tiles
The raycasts are set to collide with bodies but not with areas.
Wow that seems weird. So raycasts were working properly before you introduced the timer?
Can you check if your code prints anything when you modify the direction variable? Like this:
if direction == 0:
#Add this line
print(str("Direction is ", direction))
#-------------
if ray_cast_right.is_colliding():
animated_sprite.play("Idle")
else:
position.x += SPEED * delta
animated_sprite.play("Right")
timer.start()
allow_input = false
print("no move")
It seems to me that it is something related with physics. I was trying something similar but without tilemaps, tried with bodies and areas and worked great.
Can you toggle the Collide with > Areas as well in all raycasts to see if you get the hit this way?
I toggled the collide with areas thing and nothing changed. I even disabled all the collision on Pac-Man, both the Raycasts and the CollisionShape2D, and he’s still stuck in place.