Hands-On Challenge: Sending, Receiving and Ownership in Scripting
Meta Horizon World Creator ManualLocal EventsOnUpdateCode Blocks EventsBroadcastEventsEvents Best PracticesLocal and Default scriptsHands-On Challenge Overview
In challenge, you'll practice using the Events System and Ownership in Worlds scripting. You'll set up a scenario where a player presses a button to open a door, learning how to send and receive events, transfer ownership, and coordinate behaviors between entities. This challenge will help you build more responsive multiplayer experiences and understand the difference between server and local ownership.
You’ll learn how to:
- Transfer ownership of entities
- Send and receive events
- Use event listeners for built-in interactions (Code Block Events)
- Coordinate behaviors between entities (e.g., button and door)
- Understand server vs. local ownership and why it matters for responsiveness
Estimated Time: 1 hour
What You’ll Need:
- Access to the Worlds Desktop Editor
- An existing world project or a new one to work in.
- Basic familiarity with Worlds TypeScript and scripting APIs
Challenge Steps:
1. Set Up Your Scene
- Add two empty objects to your world and name them "ServerDoor" and "LocalDoor". Add a mesh (e.g., a cube or panel) as a child of each to visually represent the doors.
- Add a Trigger Gizmos to your scene and place it near the doors.
2. Create Door Button
- Position the Trigger Gizmo where you want players to activate the doors.
- In the properties panel of the Trigger Gizmo, press the Attach Script button. Then, click New Trigger Script at the bottom of the list.
- Click the 3 dots on the right side of the script that you created, and click edit script.
- This should open your code editor with a default UI template. Click the 3 dots on the right side of the script that you created, and click edit script.
- This should open your code editor with a default trigger template.
3. Transfer Local Door Ownership
- Define a property for your local door using PropTypes.Entity so you can assign it in the editor.
- Example:
static propsDefinition = {
localDoor: { type: PropTypes.Entity },
};- Add an onPlayerEnterWorld event and create a new method for it. In the new method, assign the localDoor owner to the player.
- Example:
start(){
//…other trigger events
this.connectCodeBlockEvent(this.entity, CodeBlockEvents.OnPlayerEnterWorld, this.onPlayerEnterWorld);
}
onPlayerEnterWorld = (player:Player) => {
this.props.localDoor?.owner.set(player)
}
4. Send Door Open Event
- Create a new script in the code editor called Events.ts.
- In this new file, add a network event.
- Example:
import { NetworkEvent } from "horizon/core";export const OpenDoorEvent = new NetworkEvent("openDoor")import { NetworkEvent } from "horizon/core";export const OpenDoorEvent = new NetworkEvent("openDoor")
- On the Trigger script, add a send network broadcast event in onPLayerEnterTrigger.
- Example:
OnPlayerEnterTrigger(player: Player) {
this.sendNetworkBroadcastEvent(OpenDoorEvent, {})
}5. Script the Doors
- To script the doors, create a new script file for each door (e.g., LocalDoor.ts and ServerDoor.ts).
- Below is an example of how to implement the logic for a door that opens in response to a network event:
import { OpenDoorEvent } from 'Event';
import * as hz from 'horizon/core';
class LocalDoor extends hz.Component<typeof LocalDoor> {
static propsDefinition = {};
shouldOpen = false;
startPosition = hz.Vec3.zero;
endPosition = hz.Vec3.zero;
timeElapsed = 0;
maxTime = 3;
start() {
this.startPosition = this.entity.position.get();
this.endPosition = this.startPosition.add(new hz.Vec3(0, -1, 0)); // Move down 1 unit
this.connectNetworkBroadcastEvent(OpenDoorEvent, this.onOpenDoor.bind(this));
this.connectLocalBroadcastEvent(hz.World.onUpdate, this.onWorldUpdate.bind(this));
}
onOpenDoor() {
this.shouldOpen = true;
}
onWorldUpdate(data: { deltaTime: number }) {
if (!this.shouldOpen) return;
this.timeElapsed = Math.min(this.maxTime, this.timeElapsed + data.deltaTime);
const t = this.timeElapsed / this.maxTime;
const newPosition = hz.Vec3.lerp(this.startPosition, this.endPosition, t);
this.entity.position.set(newPosition);
if (this.timeElapsed === this.maxTime) {
this.timeElapsed = 0;
this.shouldOpen = false;
}
}
}
hz.Component.register(LocalDoor);
- To create a server door, copy this code and rename the class and script file to "ServerDoor".
- Assign the LocalDoor script to the LocalDoor entity and the ServerDoor script to the ServerDoor entity in your world.
- Important: For the LocalDoor script, set its execution mode to Local in the Script Panel.
6. Test the Buttons
- Enter play mode and walk into the Trigger Gizmo.
- Observe the difference: the server-owned door may have more latency, while the locally owned door should open more responsively.
Level Up:
- Test out how ownership transfer affects gizmos, like particles gizmo and projectile gizmo. See how they become more responsive when playing them in local scripts.
- Try broadcasting an event, local or network, that multiple entities respond to at once.
Need Help?