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.LoadSceneen 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.