Timer never reaches zero? And also character never moves?

Look man, I appreciate you trying to help, but I really do not believe the issue has to do with physics. Like I said before, it was only after implementing the timer that Pac-Man stopped moving. And in fact, when I edit the code so that allow_input is always set to true, he’s able to move around just fine with no issues.

Again, I really appreciate you taking the time out to help me, but I don’t think this line of logic is gonna get us anywhere.

I think you have to set one_shot to false. As i understand it: one_shot stops the timer from resetting the time_left to 0 when its done, but you want to reuse the timer, so when you call timer.start() its already done. Thats why you would want to turn it off

It’s ok, we are here to help. Questions asked are just to gather more info about your problem. :wink: :+1:

I may be super dense, but a few questions:

  1. How does the timer know when to stop? Like the code presented doesn’t state how many ms/seconds are needed to pass before it stops.
  2. Is there a signal being emitted to the timer (and is it being caught?)?
  3. When the timer stops, how does it know it needs to be restarted?
  4. When the timer elapses, does that timer get culled/turned into a null value and thus you need to create a new timer each time the old one elapsed?
  5. It might be useful to have print messages before the _on_timer_timeout() function is called. To see if it is even reaching this section of the codebase, period.
  6. Final question… since it is V4.3 why is the _on_timer_timeout() function written without a return value? ie

func _on_timer_timeout() → void:
#for returning no value.

Yes, when one_shot=true, Timer.wait_time will reset back to 1.

  1. That’s in the Timer Node settings.
  2. I assume that’s what the timer.start() thing is for
  3. Does the One Shot setting on the timer not restart it?
  4. Is that default behavior? I certainly didn’t program it to do so.
  5. What do you mean by this? If I put a print command before _on_timer_timeout(), it gives me the error “Unexpected ‘Identifier’ in class body”, which is because it doesn’t have a function behind it. Telling it what to do, but not when to do it. Or something like that.
  6. The tutorial I followed (Brackeys’) didn’t mention anything about that, and it works just fine in the thing I made using that.

As i said one_shot only sets the remaining time either back to 0 (if turned off) or let it stay at the end (if turned on). You want to reuse the timer so you want it turned off

Alright, thank you. I was under the impression One Shot was “stop it from going below zero”

Has the problem been resolved?

Not yet unfortunately

What exactly is the problem now? Does the timer work now?

It does not. Pac-Man is still stuck in place

Timers seem like the wrong way to implement this.

Instead, I would wait for Pacman to cross the snap line, then check if the player recently gave an input in the perpendicular direction.

Something like this:

  1. Decide how long an input should persist
  2. On input store the last input and start a timer(inputTimer = value from 1.)
  3. On update:
    1. inputTimer -= delta
    2. IF vector from last position → current position has crossed the perpendicular direction snap line AND the last input is a perpendicular direction AND the timer has not expired(inputTimer > 0) THEN snap to the new direction line
    3. Store current position to last position

Easier to implement is to just check if a key in the perpendicular direction is being held using Input.is_key_pressed(keycode: Key). In this case, if you are holding the key while crossing the snap line, then change directions.

Could ya point me to the commands for snap lines and whatnot? Would be very helpful

I’ll try to give you more info later today.

Thank you very much

This probably needs some tweaking. I usually write scripts in C# and I did not test it.

You will need to play with your layout and the grid settings to get them to line up.

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

const SPEED = 100

const GRID_OFFSET_X = 0 # offset of the grid in the x axis
const GRID_OFFSET_Y = 0 # offset of the grid in the y axis
const GRID_SIZE = 32 # size of the grid in pixels, this creates the grid the character will move on

const INPUT_PERSISTENCE = 0.1 # how long the input will be considered after the key is pressed in seconds

enum { UpDown, LeftRight }
enum { None, Up, Down, Left, Right }

var direction = UpDown

var last_input = None
var input_timer = 0

var last_position = Vector2.ZERO

func _input(event):
	#Track last input
	if(event.is_action_pressed("right")):
		last_input = Up
		input_timer = INPUT_PERSISTENCE
	elif(event.is_action_pressed("down")):
		last_input = Down
		input_timer = INPUT_PERSISTENCE
	elif(event.is_action_pressed("left")):
		last_input = Left
		input_timer = INPUT_PERSISTENCE
	elif(event.is_action_pressed("up")):
		last_input = Right
		input_timer = INPUT_PERSISTENCE

func _physics_process(delta):
	# Handle Input and Snapping to Grid
	if(input_timer > 0): #If no recent input has happened, do nothing
		input_timer -= delta

		if direction == UpDown and (last_input == Left or last_input == Right):
			var last_grid_x = round((last_position.x - GRID_OFFSET_X) / GRID_SIZE)
			var grid_x = round((position.x - GRID_OFFSET_X) / GRID_SIZE)
			if last_grid_x != grid_x: # Has the player moved to a new grid cell in x direction?
				direction = LeftRight
				if last_input == Right:
					position.x = grid_x * GRID_SIZE + GRID_OFFSET_X # snap to current grid cell
					velocity = Vector2.right * SPEED
				elif last_input == Left:
					position.x = last_grid_x * GRID_SIZE + GRID_OFFSET_X # snap to last grid cell
					velocity = Vector2.left * SPEED
		elif direction == LeftRight and (last_input == Down or last_input == Up):
			var last_grid_y = round((last_position.y - GRID_OFFSET_Y) / GRID_SIZE)
			var grid_y = round((position.y - GRID_OFFSET_Y) / GRID_SIZE)
			if last_grid_y != grid_y: # Has the player moved to a new grid cell in y direction?
				direction = UpDown
				if last_input == Down:
					position.y = grid_y * GRID_SIZE + GRID_OFFSET_Y # snap to current grid cell
					velocity = Vector2.down * SPEED
				elif last_input == Up:
					position.y = last_grid_y * GRID_SIZE + GRID_OFFSET_Y # snap to last grid cell
					velocity = Vector2.up * SPEED
	
	# Handle Movement
	last_position = position # save last position before moving
	var collision = move_and_collide(velocity * delta) # move_and_collide stops at first collision

	# Stop if there is a collision
	if collision:
		velocity = Vector2.ZERO # stop moving

	# Set Animation based on velocity
	if velocity == Vector2.ZERO:
		animated_sprite.play("Idle")
	elif velocity.x > 0:
		animated_sprite.play("Right")
	elif velocity.x < 0:
		animated_sprite.play("Left")
	elif velocity.y > 0:
		animated_sprite.play("Down")
	elif velocity.y < 0:
		animated_sprite.play("Up")
	

If the script has errors that you can’t figure out, paste them here and I’ll try to work you through them.

Isnt the timer.play being called every physics process call? This would start the timer before it can reach 0 and never reach 0.

Suggest you debug the timer and see what value its on every physics process call