I'm making a game for a game jam and I'm trying to do those box sliding puzzle games, the problem is, because of godot's safe margin, the body of the box will get stuck in pixel perfect holes, so i decided to make the collision of the box 1 pixel smaller and use a ray cast so it can stop when it collides with a wall

and then everything fell appart

the ray cast is innacurate, if it moves for long enough (around 1-2 seconds) it will move 1-2 pixels extra and misalign with the tile set, since it's a sliding box game, it shouldn't really misalign (and it makes the game look kinda ugly)

after that, I went to the discord of the jam and asked for some help, they said for me to use the available physics systems, so I decided to try and change from a raycast to just an area2D, but because of the fact that the function for the Area2D only goes once, now it'll get stuck in walls eternally moving if you try to move twice to the same direction, into a wall. I tried to stop the monitoring when the area2D touches the wall, but it caused the box to either: 1: only move once and never again or 2: move like a normal topdown game

I have no idea how to fix this and there's 5 days left on the jam, I really need this bug fixed, I'll leave the code for both the raycast box and the area2d box

#raycast body:

const SPEED = 300
var schmooving:bool = false
var selected:bool = false
@onready var ray:RayCast2D = get_node("ray")

func _physics_process(delta):
	if not schmooving and selected:
		ray.enabled = true
		var frontdir = Input.get_axis("left","right")
		var sidedir = Input.get_axis("up","down")
		if sidedir:
			ray.target_position = Vector2(0,9)*sidedir
			velocity.y = SPEED*sidedir
			schmooving = true
		elif frontdir:
			ray.target_position = Vector2(9,0)*frontdir
			velocity.x = SPEED*frontdir
			schmooving = true

	if ray.is_colliding():
		velocity = Vector2.ZERO
		schmooving = false
	move_and_slide()

#area2d body:

extends CharacterBody2D


const SPEED = 300

var schmooving:bool = false


@onready var vision:Area2D = get_node("Vision")
@onready var visionCol: CollisionShape2D = get_node("Vision/CollisionShape2D")

func _physics_process(delta):
	if not schmooving and selected:
		vision.monitoring = true
		var frontdir = Input.get_axis("left","right")
		var sidedir = Input.get_axis("up","down")
		if sidedir:
			visionCol.shape.b = Vector2(0,9)*sidedir
			velocity.y += SPEED*sidedir
			schmooving = true
		elif frontdir:
			visionCol.shape.b = Vector2(9,0)*frontdir
			velocity.x += SPEED*frontdir
			schmooving = true
	move_and_slide()

func _on_vision_area_entered(area):
	velocity = Vector2(0,0)
	schmooving = false` 

one thing to note is that, when I change the speed of the raycast box, the collisions work differently, on 100 speed, it works just like I want it to, on 50 or 150 it works, but the sprite flickers and distorts when standing still, on 200 it already stops working again, please help

edit: forgot to say it, but the box needs to keep moving untill it hits a wall

    anotter-random-dev I'm trying to format it to be on code blocks, it just won't work, sorry

    Place ~~~ on lines before and after the code.

    Since you're short of time, you could try using a non-physics method. Detect the cursor position and reposition the box to a preset position, without using collisions or physics.

      DaveTheCoder I'm trying to make the box slide, so teleporting it to the point wouldn't really work

      also thanks for the formatting help, now it looks a lot better

      also also I changed the physics tics per second rate to 120 and now the y axis works perfectly, but not the x, which is misaligned by one pixel to the left, and the image of the box changing stopped, I was using an tilemap and setting it's coords in the sprite2d, but changed to just an image and now it works fine

      This seems like an ideal use case for tweening from its position to the desired end position. No _physics_process-ing required. e.g.

      var tween = create_tween()
      tween.tween_property(box, "position", <your_end_position_here>, 1)

      Will move box to <your_end_position> over 1 second. Trigger the tween when desired, calculate the end position (i.e. where it should hit the wall), let the tween do all the work. I feel using physics is overkill!

        spaceyjase well that's what I'm doing now! after a little while i noticed that using physics for grid based movement is kinda not ideal at all, so I'm now calculating the destination using the tilemap, but, when I use the tween to move instead of simply teleporting to the location, the tween makes the box move 1 square over the intended distance, I'm trying to fix this now

        I'll leave the code here, if you can help me with this I'll be really gratefull

        extends CharacterBody2D
        
        enum dir {NULL,X,Y}
        
        
        var schmooving:bool = false
        var selected:bool = false
        var curdir:int
        var dire = dir.NULL
        @onready var ray:RayCast2D = get_node("ray")
        @onready var tilemap:TileMap = get_parent().get_node("objects")
        
        func _physics_process(delta):
        	#move
        	var tween:Tween = create_tween()
        	if schmooving:
        		match dire:
        			dir.Y:
        				ray.target_position = Vector2(0,9)*curdir
        			dir.X:
        				ray.target_position = Vector2(9,0)*curdir
        		ray.force_raycast_update()
        		if ray.is_colliding():
        			schmooving = false
        			ray.target_position = Vector2(0,0)
        			dire = dir.NULL
        			tween.kill()
        		elif !ray.is_colliding() and dire == dir.Y:
        			var current_tile: Vector2i = tilemap.local_to_map(position)
        			var next_tile: Vector2i = current_tile + Vector2i.DOWN*Vector2i(curdir,curdir)
        			var new_position: Vector2 = tilemap.map_to_local(next_tile)
        			tween.tween_property(self,"position",new_position,1)
        		elif !ray.is_colliding() and dire == dir.X:
        			var current_tile: Vector2i = tilemap.local_to_map(position)
        			var next_tile: Vector2i = current_tile + Vector2i.RIGHT*Vector2i(curdir,curdir)
        			var new_position: Vector2 = tilemap.map_to_local(next_tile)
        			tween.tween_property(self,"position",new_position,1)
        
        
        func _on_area_2d_input_event(viewport, event, shape_idx):
        	#select (click the box)
        	if (event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT):
        		if not selected:
        			selected = true
        
        func _input(event):
        	#deselect (click nywhere BUT the box)
        	if (event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT):
        		var evLocal = make_input_local(event)
        		if !Rect2($FilColS/CollisionShape2D.global_position,$FilColS/CollisionShape2D.shape.size).has_point(evLocal.position) and selected:
        				selected = false
        	
        	#get current direction based on key inputs
        	if event is InputEventKey and not schmooving:
        		var frontdir = Input.get_axis("left","right")
        		var sidedir = Input.get_axis("up","down")
        		if frontdir and selected:
        			dire = dir.X
        			curdir = frontdir
        			schmooving = true
        		elif sidedir and selected:
        			dire = dir.Y
        			curdir = sidedir
        			schmooving = true

        update: did some tests and it seems that for that last movement the part of the process function that calculates the movement is not running, so therefore the tween shouldn't even be animating, since it hasn't been called to do that, any ideas why that happens?

        update 2: and for some reason if I tween the box the raycast can't see the objective, but if I simply change its position, it does...
        why are tween so annoying to use? they just break stuff and cause a million errors, good lord

        update 3: actually, it does see the objective, but it happens before the objective checks to see if it is touching, so it considers itself not touching anything? I swear to god tweens are ruining me

        • xyz replied to this.

          anotter-random-dev If this is just sliding boxes, you shouldn't burden the system with any of physics and collision stuff, including raycasts. Simply calculate target positions and tween to them.