Saltar al contenido principal

Patrones comunes de jugabilidad

Estas recetas combinan APIs Components y Lua de uso general. No son módulos de género: adapta los datos, nombres y reglas al juego que estás construyendo.

Objeto recolectable con trigger y estado persistente​

Cree un GameObject visible con un disparador Collider y Lua Behaviour. Dale al jugador una etiqueta Player estable.

pickupKey = "pickup.keycard"

function Start(gameObjectId)
if PlayerPrefs.GetInt(pickupKey, 0) == 1 then
GameObject.SetActive(gameObjectId, false)
end
end

function OnTriggerEnter(gameObjectId, otherGameObjectId)
if not GameObject.CompareTag(otherGameObjectId, "Player") then
return
end

local previous = PlayerPrefs.GetInt(pickupKey, 0)
if not PlayerPrefs.SetInt(pickupKey, 1) or not PlayerPrefs.Save() then
local reason = SaveData.GetLastError()
PlayerPrefs.SetInt(pickupKey, previous)
Log.Print("Pickup save failed: " .. reason)
return
end
AudioSource.PlayOneShot(gameObjectId)
GameObject.SetActive(gameObjectId, false)
end

Esta receta deja la recolección disponible después de un fallo de guardado. Sal del trigger y vuelve a entrar para reintentar. Agrega un Audio Source para reproducir el efecto una sola vez.

Interacción de Raycast​

Usa Physics.Raycast cuando el proyecto necesite un flujo de interacción personalizado en lugar del Interaction Ray y el emparejamiento Interactable integrados.

cameraGameObjectId = -1
interactionDistance = 2.25

function TryInteract(gameObjectId)
local origin = Transform.GetPosition(cameraGameObjectId)
local rotation = Transform.GetRotation(cameraGameObjectId)
if origin == nil or rotation == nil then return end

local yaw = math.rad(rotation.y)
local pitch = math.rad(rotation.x)
local dx = math.sin(yaw) * math.cos(pitch)
local dy = -math.sin(pitch)
local dz = math.cos(yaw) * math.cos(pitch)

local hit, targetGameObjectId = Physics.Raycast(
origin.x, origin.y, origin.z,
dx, dy, dz,
interactionDistance,
nil,
false
)
if hit then
GameObject.Invoke(targetGameObjectId, "Interact", gameObjectId)
end
end

Para la mayoría de los proyectos en primera persona, el Components nativo es más simple y proporciona rango de prompt, línea de visión, enlace de entrada y tiempo de reutilización sin necesidad de realizar lecturas de scripts.

Puerta cerrada​

Separar el estado persistente de la presentación. La misma función puede conducir una animación Collider, Portal y transformar.

requiredItemKey = "pickup.keycard"
portalGameObjectId = -1

function Interact(gameObjectId, sourceGameObjectId)
if PlayerPrefs.GetInt(requiredItemKey, 0) ~= 1 then
return
end

Collider.SetIsTrigger(gameObjectId, true)
Portal.SetOpen(portalGameObjectId, true)
TransformAnimator.Play(gameObjectId, "Open")
Interactable.SetEnabled(gameObjectId, false)
end

Menú de Canvas​

La visibilidad del lienzo y el enfoque del controlador son responsabilidades separadas. Siempre selecciona un botón válido después de abrir un menú.

menuCanvasName = "Pause Menu"
resumeButtonName = "Resume Button"

local menuCanvasId = -1
local resumeButtonId = -1

function Start(gameObjectId)
menuCanvasId = Canvas.Find(menuCanvasName)
resumeButtonId = UI.Find(resumeButtonName)
end

function SetMenuOpen(open)
if Canvas.SetEnabled(menuCanvasId, open) and open then
Selectable.Select(resumeButtonId)
end
end

Las callbacks de botón de UI reciben el ID de GameObject de destino, el ID de elemento, el nombre de elemento y "click". Configura el nombre exacto de la función personalizada en el Botón Inspector.

Guardia de transición de escena​

Impedir que la entrada repetida o la presentación de Botón vuelvan a hacer cola en la transición:

targetScene = "Scenes/hub.json"
local loading = false

function OpenScene(gameObjectId)
if loading then return end
loading = true
AudioSource.Play(gameObjectId)
SceneManager.LoadScene(targetScene)
end

La escena de destino debe estar habilitada en Build Settings.

Configuración tecleada​

function ApplyAudioSettings(gameObjectId)
Music.SetVolume(PlayerPrefs.GetFloat("musicVolume", 0.8))
end

function SetMusicVolume(gameObjectId, value)
if PlayerPrefs.SetFloat("musicVolume", value) then
if not PlayerPrefs.Save() then
Log.Print("Volume preference not persisted: " .. SaveData.GetLastError())
end
Music.SetVolume(value)
end
end

Usa SaveData sin procesar solo cuando el almacenamiento a nivel de cadena sea intencional. PlayerPrefs y SaveData comparten el mismo almacén de tarjetas de memoria fijo.

Lista de comprobación de depuración​

  • confirmar que cada GameObject posee el componente requerido por la API;
  • cachear y validar los ID de GameObject, Canvas e UI;
  • coincidir con los nombres de callback personalizados exactamente;
  • incluir cada destino SceneManager.LoadScene en Build Settings;
  • manejar las capacidades de audio, navegación, persistencia y controlador fallidos;
  • Ejecuta Validate Project, Show PS1 Budget, Build with Readiness Checks y el CUE empaquetado.