Quick answer: RigidBody2D → continuous_cd = CCD_MODE_CAST_RAY. Or raise physics_ticks_per_second. For hitscan, sweep a Raycast manually each tick.

Bullet at 1500 px/s. 60 Hz tick. 25 px gap per step. Hits anything thinner than 25 px? Sometimes. Anything thinner than 12 px? Almost never.

The Symptom

Some bullets damage; identical bullets at the same target miss without any visible reason.

The Fix

# Bullet
extends RigidBody2D

func _ready():
    continuous_cd = CCD_MODE_CAST_RAY
    linear_velocity = Vector2.RIGHT * 1500

# Or per-project: physics tick rate
# project.godot → physics → common → physics_ticks_per_second = 120

# Hitscan alternative
func _physics_process(_d):
    var ray = PhysicsRayQueryParameters2D.create(prev_pos, position)
    var hit = get_world_2d().direct_space_state.intersect_ray(ray)
    if hit:
        hit.collider.take_damage()
        queue_free()
    prev_pos = position

CCD adds a sweep cost; use only on fast movers. Tick-rate bump affects every body, expensive at scale. Hitscan is cheapest if you don’t need ballistic bullets.

Verifying

Fire bullets at a thin (5 px) wall. Without CCD: most pass through. With CCD: every shot registers.

“CCD on fast bodies. Or sweep manually. Hits land.”

Related Issues

For client prediction, see prediction. For tween signal, see tween signal.

CCD on. Tunnels close. Hits land.