# Raycasts

> Recursive raycast system with the Kore helpers module - step-based raycasting with block hit, max distance, and per-step callbacks.

Updated 2026-10-22. Canonical: https://kore.ayfri.com/docs/helpers/raycasts

Raycasts generate a set of recursive functions that step forward from the entity's eyes until they hit a block or reach
max distance. Each step is a local-coordinate [`execute positioned`](https://minecraft.wiki/w/Commands/execute) call, so
precision scales with the step size.

They are ideal for "look at" interactions, custom tools, line-of-sight checks, or visual debugging because the helper
pre-builds the recursive command chain for you.

> [!FOOTPRINT]
> - **Objectives:** `kore_raycast`, shared by every ray.
> - **Storage:** none.
> - **Entities:** none. The caster carries the `kore_raycasting` tag while its ray runs, removed on hit or at max distance.
> - **Forceloaded chunks:** none.
> - **Every tick:** no, a cast runs within the tick it starts in.
> - **Load and files:** `kore_raycast_init` creates the objective, and each ray gets `raycast_<name>_start`, `_step`, `_hit` and `_max`.

## API overview

The helper is centered around two entry points:

- `raycast { ... }` - builds a fresh `RaycastConfig` inline.
- `raycast(config)` - reuses an already configured `RaycastConfig` instance.

The generated `RaycastHandle` exposes a single `cast()` method that launches the raycast from the current function
context.

`RaycastConfig` defaults:

- `name = "raycast"`
- `maxDistance = 100`
- `step = 0.5`
- `onHitBlock = {}`
- `onStep = null`
- `onMaxDistance = null`

## DSL builder

```kotlin
val ray = raycast {
	name = "my_ray"
	maxDistance = 50
	step = 0.5
	onHitBlock = { say("Hit!") }
	onMaxDistance = { say("Too far!") }
	onStep = { particle(Particles.FLAME, vec3()) }
}

function("use_ray") {
	with(ray) { cast() }
}
```

## Callback lifecycle

- `onStep` runs for every successful step before the ray stops.
- `onHitBlock` runs when the next step collides with a block.
- `onMaxDistance` runs when the ray reaches the configured limit without hitting anything.

If `onMaxDistance` is omitted, the ray quietly removes its internal tag when it reaches the limit, so the generated
functions stop recursing without firing a fallback callback.

This makes it easy to keep gameplay logic explicit: particles can live in `onStep`, impact logic in `onHitBlock`, and
fallback behavior in `onMaxDistance`.

## Practical usage pattern

```kotlin
val scanner = raycast {
	name = "scanner"
	maxDistance = 24
	step = 0.25
	onStep = { particle(Particles.END_ROD, vec3()) }
	onHitBlock = { say("Target acquired") }
	onMaxDistance = { say("No target found") }
}

function("scan_once") {
	with(scanner) { cast() }
}
```

The callbacks are plain function bodies, so a step can draw any [particle option](https://kore.ayfri.com/docs/commands/commands.md#particle-options), a colored
dust beam for instance:

```kotlin
onStep = { particle(dustParticle(rgb(0x55FFFF), 0.5f), vec3()) }
```

```mcfunction
particle minecraft:dust{color:5636095,scale:0.5f} ~ ~ ~
```

For precise interaction beams, prefer a smaller `step`; for cheaper "good enough" scans, use a larger one.

The step value is measured in blocks and is applied through a local-position offset, so smaller values increase
precision while also generating more recursive calls.

## See also

- [Area](https://kore.ayfri.com/docs/helpers/area.md) - Define spatial zones that complement what a ray can detect or trigger.
- [VFX Particles](https://kore.ayfri.com/docs/helpers/vfx-particles.md) - Use particles inside `onStep` for visual debugging or beam effects.
- [Entities & Players](https://kore.ayfri.com/docs/oop/entities-and-players.md) - Execute raycasts from player or mob contexts with reusable
  selectors.
