Saltar al contenido
ReadySpawn

Cómo hacer un sistema de inventario en primera persona en Godot 4

Por Imersa Studios · Actualizado el

Describe los objetos como Resource, guarda las ranuras en un autoload para que todas las escenas lleguen a ellas, recoge objetos con un RayCast3D en la cámara y cambia la ranura seleccionada con la rueda del ratón. Guarda los ids de los objetos en JSON.

1. Objetos como resources

Un Resource es la forma de Godot de describir datos que editas en el Inspector. Un archivo .tres por objeto saca nombres e iconos del código:

class_name Item
extends Resource

@export var id := ""
@export var display_name := ""
@export var icon: Texture2D

2. Un autoload que guarda las ranuras

Añade este script en Project Settings > Globals > Autoload como Inventory. Una señal avisa a la interfaz para que se redibuje:

extends Node

signal changed
const SIZE := 9
var slots: Array[Item] = []
var selected := 0

func _ready() -> void:
    slots.resize(SIZE)

func add(item: Item) -> bool:
    for i in SIZE:
        if slots[i] == null:
            slots[i] = item
            changed.emit()
            return true
    return false

func drop_selected() -> Item:
    var item := slots[selected]
    slots[selected] = null
    changed.emit()
    return item

3. Recoge lo que estás mirando

Pon un RayCast3D en la cámara, de unos 2 m. Cuando el jugador pulsa la acción de interactuar y el rayo toca un objeto, añádelo y libera el nodo:

@onready var ray: RayCast3D = $Camera3D/RayCast3D

func _unhandled_input(event: InputEvent) -> void:
    if event.is_action_pressed("interact") and ray.is_colliding():
        var target := ray.get_collider()
        if target is Pickup and Inventory.add(target.item):
            target.queue_free()
    if event is InputEventMouseButton and event.pressed:
        if event.button_index == MOUSE_BUTTON_WHEEL_UP:
            Inventory.selected = posmod(Inventory.selected - 1, Inventory.SIZE)
        elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
            Inventory.selected = posmod(Inventory.selected + 1, Inventory.SIZE)
        Inventory.changed.emit()

Pickup es un script pequeño en un StaticBody3D o RigidBody3D con un item: Item exportado. Para la barra rápida basta un HBoxContainer de TextureRects que se redibuja con Inventory.changed.

4. Guarda el inventario

Guarda los ids de los objetos, no los resources, para que la partida siga funcionando cuando cambies un icono:

func save_inventory() -> void:
    var ids := Inventory.slots.map(func(i): return i.id if i else "")
    var file := FileAccess.open("user://inventory.json", FileAccess.WRITE)
    file.store_string(JSON.stringify(ids))

Al cargar, lee los ids y relaciona cada uno con su .tres mediante un diccionario de objetos. El mismo patrón guarda puertas, monedas y checkpoints.

5. O empieza con sistemas que ya funcionan

La colección 10 Game Systems para Godot 4 trae este inventario junto con guardar y cargar, puertas con llave y teclado numérico, tienda, RPG inicial y cinco más, cada uno con escena de demostración y GDScript tipado. El Door System es gratis.

Preguntas frecuentes

Quién lo escribió

Imersa Studios crea los sistemas Unity, los packs low poly y las guías que se venden en itch.io. El código y las técnicas de aquí salen de publicar esos productos. Más sobre el estudio.