Skip to content

Instantly share code, notes, and snippets.

@Falconerd
Created April 13, 2026 06:43
Show Gist options
  • Select an option

  • Save Falconerd/c653ab4b3357ef83a827cbbb41297078 to your computer and use it in GitHub Desktop.

Select an option

Save Falconerd/c653ab4b3357ef83a827cbbb41297078 to your computer and use it in GitHub Desktop.
handles example
package main
import "core:fmt"
import "core:math/rand"
import rl "vendor:raylib"
Entity :: struct {
name: cstring,
pos: [2]f32,
following: Entity_Handle,
color: rl.Color,
is_dead: bool,
generation: int,
}
Entity_Handle :: struct {
id: int,
generation: int,
}
MOVE_SPEED :: 450
entities: [dynamic]Entity
entity_create :: proc(data: Entity = {}) -> Entity_Handle {
for &entity, i in entities {
if entity.is_dead {
gen := entity.generation + 1
entity = data
entity.is_dead = false
entity.following = {} if data.following.id == 0 else data.following
entity.generation = gen
return Entity_Handle{id = i, generation = entity.generation}
}
}
index := len(entities)
append(&entities, data)
entity := &entities[index]
entity.following = {} if data.following.id == 0 else data.following
entity.generation += 1
return Entity_Handle{id = index, generation = entity.generation}
}
entity_get :: proc(handle: Entity_Handle) -> (entity: ^Entity, ok: bool) {
if handle.id < 0 || handle.id >= len(entities) do return
if entities[handle.id].is_dead do return
if entities[handle.id].generation != handle.generation do return
return &entities[handle.id], true
}
entity_destroy :: proc(handle: Entity_Handle) {
if handle.id < 0 || handle.id >= len(entities) do return
if entities[handle.id].generation != handle.generation do return
entities[handle.id].is_dead = true
}
main :: proc() {
rl.InitWindow(1920, 1080, "Handles")
font := rl.LoadFontEx("./JetBrainsMono-Bold.ttf", 40, nil, 256)
entity_a_handle := entity_create({name = "A", pos = {96, 96}, color = rl.BLUE})
entity_b_handle := entity_create({name = "B", pos = {120, 512}})
teleporter_handle := entity_create({name = "Teleporter", pos = {1700, 700}, color = rl.YELLOW})
if entity_a, ok := entity_get(entity_a_handle); ok {
entity_a.following = entity_b_handle
}
entities_addr := &entities[0]
for !rl.WindowShouldClose() {
dt := rl.GetFrameTime()
teleporter, _ := entity_get(teleporter_handle)
if entity_b, ok := entity_get(entity_b_handle); ok {
if rl.IsKeyDown(.A) do entity_b.pos.x -= MOVE_SPEED * dt
if rl.IsKeyDown(.D) do entity_b.pos.x += MOVE_SPEED * dt
if rl.IsKeyDown(.W) do entity_b.pos.y -= MOVE_SPEED * dt
if rl.IsKeyDown(.S) do entity_b.pos.y += MOVE_SPEED * dt
if rl.Vector2Distance(entity_b.pos, teleporter.pos) < 20 {
entity_destroy(entity_b_handle)
entity_b_handle = {}
}
}
if rl.IsKeyPressed(.SPACE) {
x := rand.float32_range(0, 1920)
y := rand.float32_range(0, 1080)
entity_create({name = "C", pos = {x, y}, color = rl.GREEN})
}
// Follow behavior
for &entity in entities {
if entity.is_dead do continue
if target, ok := entity_get(entity.following); ok {
direction := rl.Vector2Normalize(target.pos - entity.pos)
entity.pos += direction * dt * MOVE_SPEED * 0.75
}
}
rl.BeginDrawing()
rl.ClearBackground({0, 0, 0x1C, 0xFF})
#reverse for entity in entities {
if entity.is_dead do continue
rl.DrawRectangleV(entity.pos - 64, 128, entity.color != {} ? entity.color : rl.RED)
text_size := rl.MeasureTextEx(font, entity.name, 40, 0)
text_pos := entity.pos - text_size / 2
text_pos.y -= 80
rl.DrawTextEx(font, entity.name, text_pos, 40, 0, rl.WHITE)
}
if &entities[0] != entities_addr {
rl.DrawTextEx(
font,
fmt.ctprintf("entities address changed! %p -> %p", entities_addr, &entities[0]),
{8, 8},
40,
0,
rl.WHITE,
)
}
p: [2]f32 = 40
for entity in entities {
color := entity.color == {} ? rl.RED : entity.color
text := entity.name
if entity.is_dead {
color = rl.GRAY
text = fmt.ctprintf("%s (%d) (DEAD)", entity.name, entity.generation)
}
rl.DrawTextEx(font, text, p, 40, 0, color)
p.y += 40
}
rl.EndDrawing()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment