Components of a Meta Horizon Script(a.k.a. CodeBlocks) | Components of a TypeScript File |
---|---|
Object : Runs an instance of any attached scripts, referred to as Self | Object : Runs an instance of any attached scripts, referred to as this/this.Entity |
Script : Determines the behavior of the object | Script : Determines the behavior of the object |
Variables : Stores values related to the object | Properties : Stores values related to the object (as long as it is read-only, then just make it a private variable inside the class) |
Events : Contains the logic that determines behavior | Functions : Contains the logic that determines behavior |
Actions : Performs the behaviors | Methods : Performs the behaviors |
import * as hz from 'horizon/core';
class ExampleScript extends hz.Component<typeof ExampleScript> {
static propsDefinition = {};
preStart() {}
start() {}
}
hz.Component.register(ExampleScript);
import * as hz from 'horizon/core';
class ExampleScript extends hz.Component<typeof ExampleScript> {
{
at the end. This often specifies the beginning scope of your code. static propsDefinition = {};
preStart() {
}
start() {
}
}
hz.Component.register(ExampleScript);
start() { add code here }
Number
: Can be a single Decimal (base 10), Hexadecimal (base 16) or Octal (base 8).
Ex.: num: { type: hz.PropTypes.Number, default: 0} | num: number = 0 |
NumberArray
: Can be a list of Decimals (base 10), Hexadecimals (base 16) or Octals (base 8).
Ex.: numList: { type: hz.PropTypes.NumberArray, default: []} | num: number[] = [] |
String
: Stores text data surrounded by single quotation marks or double quotation marks.
Ex.: str: { type: hz.PropTypes.String, default: ‘Hello World’} | str: string = ‘Hello World’ |
StringArray
: Stores a list of text data.
Ex.: strList: { type: hz.PropTypes.StringArray, default: [‘Hello’, ‘World’]} | strList: string[] = [‘Hello’, ‘World’] |
Boolean
: Stores a true or false value.
Ex.: bool: { type: hz.PropTypes.Boolean, default: false} | bool: boolean = false |
BooleanArray
: Stores a list of true or false values.
Ex.: boolList: { type: hz.PropTypes.BooleanArray, default: [false]} | boolList: boolean[] = [false] |
Vec3
: Stores a 3D Vector.
Ex.: vec: { type: hz.PropTypes.Vec3, default: new hz.vec3(0,0,0) } | vec: hz.vec3 = new hz.vec3(0,0,0) |
Vec3Array
: Stores a list of 3D Vectors.
Ex.: vecList: { type: hz.PropTypes.Vec3Array, default: [new hz.vec3(0,0,0)]} | vecList: hz.vec3Array = [new hz.vec3(0,0,0)] |
Color
: Stores a RGB color.
Ex.: _color: { type: hz.PropTypes.Color, default: new hz.Color(0,0,0)} | _color: hz.Color = new hz.Color(0,0,0) |
ColorArray
: Stores a list of RGB Colors.
Ex.: colorList: { type: hz.PropTypes.ColorArray, default: [new hz.Color(0,0,0), new hz.Color(1,1,1)]} | colorList: hz.Color = [new hz.Color(0,0,0), new hz.Color(1,1,1)] |
Entity
: Stores an object.
Ex.: obj: { type: hz.PropTypes.Entity } | obj: hz.Entity \| null = null |
EntityArray
: Stores a list of objects.
Ex.: objList: { type: hz.PropTypes.EntityArray } | objList: hz.EntityArray = [] |
Quaternion
: Stores a rotation.
Ex.: rot: { type: hz.PropTypes.Quaternion, default: new hz.Quarterion(0,0,0,1) } | rot: hz.Quarterion = new hz.Quarterion(0,0,0,1) |
QuaternionArray
: Stores a list of rotations.
Ex.: rotList: { type: hz.PropTypes.QuaternionArray, default: [new hz.Quaternion(0,0,0,1)] } | rotList: hz.Quaternion = [new hz.Quaternion(0,0,0,1)] |
Player:
Stores a Player.
Ex.: p: { type: hz.PropTypes.Player, default: this.world.getServerPlayer()} | p: hz.Player \| null = null |
PlayerArray
: Stores a list of Players.
Ex.: N/A | pList: hz.Player[] = [] |
Asset
: Stores an Asset.
Ex.: ass: { type: hz.PropTypes.Asset } | ass: hz.Asset \|null = null |
AssetArray
: Stores a list of Assets.
Ex.: N/A | assList: hz.Asset[] = [] |
Other Array Data Types
: There are several other interesting data storage types to research.
Built-in CodeBlocks
: Used to connect events like TriggerEnter, GrabStart, and the rest.
this
.connectCodeBlockEvent(
this
.entity, hz.CodeBlockEvents.OnPlayerEnterWorld,
this
.onPlayerEnterWorld.bind(
this
))
CodeBlock Events
: Design like custom Meta Horizon Events and meant to communicate with CodeBlock scripts.
this
.connectCodeBlockEvent(
this
.entity,
new
hz.CodeBlockEvent(
'codeblockEventName'
,[]),
this
.onCodeblockEventName.bind(
this
))
this
.sendCodeBlockEvent(
this
.entity,
new
hz.CodeBlockEvent(
'codeblockEventName'
,[]))
Local Events
: Used to communicate with TypeScript on the same host.
this
.connectLocalEvent(
this
.entity,
new
hz.LocalEvent(
'eventName'
),
this
.onEventName.bind(
this
))
this
.sendLocalEvent(
this
.entity,
new
hz.LocalEvent(
'eventName'
), {})
Networked Events
: Used to communicate with TypeScript scripts on a different host.
this
.connectNetworkEvent(
this
.entity,
new
hz.NetworkEvent(
'networkEvent'
),
this
.onNetworkEvent.bind(
this
))
this
.sendNetworkEvent(
this
.props.exampleObject,
new
hz.NetworkEvent(
'networkEvent'
), {})
Local Broadcast Events
: Used to broadcast an event to all listeners on the same host.
this
.connectLocalBroadcastEvent(
new
hz.LocalEvent(
'localBroadcastEvent'
)),
this
.onLocalBroadcastEvent.bind(
this
))
this
.sendLocalBroadcastEvent(
new
hz.LocalEvent(
'localBroadcastEvent'
), {})
Networked Broadcast Events
: Used to broadcast an event to all listeners on different hosts.
this
.connectNetworkBroadcastEvent(
new
hz.NetworkEvent(
'networkBroadcastEvent'
),
this
.onNetworkBroadcastEvent.bind(
this
))
this
.sendNetworkBroadcastEvent(
new
hz.NetworkEvent(
'networkBroadcastEvent'
), {})
import * as hz from 'horizon/core'
I’m
//Extended to create new scripts that can be attached to entities in the world, and to create new behaviors in Horizon.
class basicScriptA extends hz.Component<typeof basicScriptA> {
//propsDefinition are read-only variables used to define the properties of the component.
static propsDefinition = {
exampleObject: {
type: hz.PropTypes.Entity
},
}
//I like to list my private variables here, ones I need to use or edit later in my script.
private exampleWriteableString: string = "Hello World! #3"
//preStart is guaranteed to run for all components before any component's start method is called.
//I typically use this to connect to events.
preStart(){
}
//Called when the component is started.
start() {
//Example of sending a Codeblock event
if(this.props.exampleObject){
this.sendCodeBlockEvent(this.props.exampleObject, new hz.CodeBlockEvent('codeblockEventName',[]))
//Example of sending a Codeblock event with parameters
this.sendCodeBlockEvent(this.props.exampleObject, new hz.CodeBlockEvent('codeblockEventNameParams',[hz.PropTypes.String]), "Hello World!")
//Example of sending a Local event
this.sendLocalEvent(this.props.exampleObject, new hz.LocalEvent('eventName'), {})
//Example of sending a Local event with parameters
this.sendLocalEvent(this.props.exampleObject, new hz.LocalEvent<{s: string}>('eventNameParams2'), {s: "Hello World! #2"})
this.sendLocalEvent(this.props.exampleObject, new hz.LocalEvent<{s: string}>('eventNameParams3'), {s: this.exampleWriteableString})
this.sendNetworkEvent(this.props.exampleObject, new hz.NetworkEvent('networkEvent'), {})
}
//Example of sending a Local broadcast event
this.sendLocalBroadcastEvent(new hz.LocalEvent('localBroadcastEvent'), {})
//Example of sending a Network broadcast event
this.sendNetworkBroadcastEvent(new hz.NetworkEvent('networkBroadcastEvent'), {})
}
}
hz.Component.register(basicScriptA)
import * as hz from 'horizon/core'
//Extended to create new scripts that can be attached to entities in the world, and to create new behaviors in Horizon.
class basicScriptB extends hz.Component<typeof basicScriptB> {
//preStart is guaranteed to run for all components before any component's start method is called.
//I typically use this to connect to events.
preStart(){
//Examples of connecting to built-in horizon events.
this.connectCodeBlockEvent(this.entity, hz.CodeBlockEvents.OnPlayerEnterWorld, this.onPlayerEnterWorld.bind(this))
this.connectCodeBlockEvent(this.entity, hz.CodeBlockEvents.OnPlayerExitWorld, this.onPlayerExitWorld.bind(this))
//Examples of connecting to custom codeblock events.
this.connectCodeBlockEvent(this.entity, new hz.CodeBlockEvent('codeblockEventName',[]), this.onCodeblockEventName.bind(this))
this.connectCodeBlockEvent(this.entity, new hz.CodeBlockEvent('codeblockEventNameParams',[hz.PropTypes.String]), this.onCodeblockEventNameParams.bind(this))
//Examples of connecting to TypeScript events.
this.connectLocalEvent(this.entity, new hz.LocalEvent('eventName'), this.onEventName.bind(this))
this.connectLocalEvent(this.entity, new hz.LocalEvent<{s: string}>('eventNameParams2'), (data: {s: string}) => this.eventNameParams2.bind(this
//In practical terms, if eventNameParams2 and eventNameParams3 methods don't use this inside them to refer to the class instance,
//there would be no difference between these two lines. However, if they do use this,
//then the first line ensures that this refers to the correct object,
//while the second line might lead to unexpected behavior if this doesn't refer to the class instance when the method is called.
this.connectLocalEvent(this.entity, new hz.LocalEvent<{s: string}>('eventNameParams3'), (data: {s: string}) => this.eventNameParams3(data.s))
this.connectNetworkEvent(this.entity, new hz.NetworkEvent('networkEvent'), this.onNetworkEvent.bind(this))
//Examples of connecting to local broadcast events.
this.connectLocalBroadcastEvent(new hz.LocalEvent('localBroadcastEvent'), this.onLocalBroadcastEvent.bind(this))
//Example of connecting to a networked broadcast event.
this.connectNetworkBroadcastEvent(new hz.NetworkEvent('networkBroadcastEvent'), this.onNetworkBroadcastEvent.bind(this))
}
//Called when the component is started.
start() {
}
onPlayerEnterWorld(p: hz.Player){
console.log(p.name.get() + " entered the world!")
}
onPlayerExitWorld(p: hz.Player){
console.log(p.name.get() + " exited the world!")
}
onEventName(){
console.log("eventName was triggered!")
}
onCodeblockEventName(){
console.log("codeblockEventName was triggered!")
onCodeblockEventNameParams(s: string){
console.log("codeblockEventNameParams was triggered with parameter: " + s)
eventNameParams2(s: string){
console.log("eventNameParams2 was triggered with parameter: " + s)
eventNameParams3(s: string){
console.log("eventNameParams3 was triggered with parameter: " + s)
}
onLocalBroadcastEvent(){
console.log("localBroadcastEvent was triggered!")
onNetworkBroadcastEvent(){
console.log("networkBroadcastEvent was triggered!")
}
onNetworkEvent(){
console.log("networkEvent was triggered!")
}
}
hz.Component.register(basicScriptB)
import * as hz from 'horizon/core';
class simpleRespawnScript extends hz.Component<typeof simpleRespawnScript> {
static propsDefinition = {
respawn: {
type: hz.PropTypes.Entity,
},
};
preStart() {
this.connectCodeBlockEvent(
this.entity,
hz.CodeBlockEvents.OnPlayerEnterTrigger,
this.OnPlayerEnterTrigger.bind(this),
);
}
start() {}
OnPlayerEnterTrigger(p: hz.Player) {
this.props.respawn?.as(hz.SpawnPointGizmo)?.teleportPlayer(p);
}
}
hz.Component.register(simpleRespawnScript);
import * as hz from
class SimpleObjectGrab extends hz.Component<typeof SimpleObjectGrab> {
static propsDefinition = {
}
preStart(){
//#region Built-in Event Handlers
this.connectCodeBlockEvent(
this.entity,
hz.CodeBlockEvents.OnGrabStart,
this.OnGrabStart.bind(this)
)
this.connectCodeBlockEvent(
this.entity,
hz.CodeBlockEvents.OnGrabEnd,
this.OnGrabEnd.bind(this)
)
//#endregion Built-in Event Handlers
}
start() {
//Set the original position and rotation of the object.
this.originalPosition = this.entity.position.get()
this.originalRotation = this.entity.rotation.get()
}
//#region Private Variables
private resetTimer: number = 0
private originalPosition: hz.Vec3 = new hz.Vec3(0, 0, 0)
private originalRotation: hz.Quaternion = new hz.Quaternion(0, 0, 0, 0
//#endregion Private Variables
OnGrabStart(r: boolean, p: hz.Player ) {
//cancel the reset timer if the object is grabbed.
this.async.clearTimeout(this.resetTimer)
}
OnGrabEnd(p: hz.Player) {
//reset the object to its original position and rotation after 5 seconds.
this.resetTimer = this.async.setTimeout(() => {
this.entity.position.set(this.originalPosition)
this.entity.rotation.set(this.originalRotation)
}, 5000)
}
}
hz.Component.register(SimpleObjectGrab)
import * as hz from 'horizon/core';
class VIPorStageScript extends hz.Component<typeof VIPorStageScript> {
static propsDefinition = {
respawn: {
type: hz.PropTypes.Entity,
},
vipList: {
type: hz.PropTypes.StringArray,
default: ['SeeingBlue', 'Mutts_Mutts_Mutts', 'burnbuns', 'gausroth'],
},
};
preStart() {
this.connectCodeBlockEvent(
this.entity,
hz.CodeBlockEvents.OnPlayerEnterTrigger,
this.OnPlayerEnterTrigger.bind(this),
);
}
start() {}
OnPlayerEnterTrigger(p: hz.Player) {
//only teleport the player if they are not on the vip list
if (!this.props.vipList.includes(p.name.get())) {
this.props.respawn?.as(hz.SpawnPointGizmo)?.teleportPlayer(p);
}
}
}
hz.Component.register(VIPorStageScript);