Skip to content

Sign Entity

This is an advanced example that uses a lot of different features.

Global Script, manages the UI

function OnTemplate()
    -- Here we'll call our create UI function
    CreateUI()

    -- Since we'll be using this UI from entities we'll register some global functions
    -- so our entities can interact with this global script.

    -- These two will be used to open the UI and close the UI.
    self.RegisterGlobalFunction("SignOpenUI",OpenUI)
    self.RegisterGlobalFunction("SignCloseUI",CloseUI)

    -- These will be used to retrieve references to our input fields and save button.
    self.RegisterGlobalFunction("GetSignTitle",GetSignTitle)
    self.RegisterGlobalFunction("GetSignText",GetSignText)
    self.RegisterGlobalFunction("GetSaveSignButton",GetSaveButton)
end

-- Function to be called from our entities, returns the save button reference.
function GetSaveButton()
    return saveButton
end

-- Function to be called from our entities, Unhides our UI.
function OpenUI()
    myCanvas.gameObject.SetActive(true)
end

-- Function to be called from our entities, Hides our UI.
function CloseUI()
    myCanvas.gameObject.SetActive(false)
end

-- Function to be called from our entities, returns the title input reference.
function GetSignTitle()
    return signTitleInput
end

-- Function to be called from our entities, returns the text input reference.
function GetSignText()
    return signTextInput
end

function CreateUI()
    -- Creates a new UI Canvas to hold our UI.
    -- The true value means the game will free the mouse when this canvas is active.
    myCanvas = UI.CreateCanvas(true)
    -- Creates a main panel in our new canvas.
    mainPanel = UI.CreatePanel(myCanvas).SetAnchors(0.3, 0.7, 0.1, 0.9)
    -- Adds an image to the main panel.
    UI.CreateImage(mainPanel,1,1,1,0.8)
    -- Creates a new title panel in the main panel.
    titlePanel = UI.CreatePanel(mainPanel).SetAnchors(0.1,0.9,0.80,0.95)
    -- Adds a text to the title panel.
    titleText = UI.CreateTextMesh(titlePanel, "Sign",76,0,0.6,0.9,1,"center","titletext").SetFont("TitleShadow")

    -- We'll create a panel for our Sign Title.
    signTitlePanel = UI.CreatePanel(mainPanel).SetAnchors(0.1,0.9,0.75,0.8)
    -- We'll add an input field to our signTitlePanel
    signTitleInput = UI.CreateInputField(signTitlePanel)
    -- We'll add some placeholder text to our sign title.
    signTitleInput.placeholderText = "Type your sign title here"

    -- We'll create a panel for our Sign Text.
    signTextPanel = UI.CreatePanel(mainPanel).SetAnchors(0.1,0.9,0.15,0.7)
    -- We'll add an input field to our signTextPanel
    signTextInput = UI.CreateInputField(signTextPanel,true)
    -- We'll add some placeholder text to our sign text.
    signTextInput.placeholderText = "Type your sign message here"

    -- Creates a panel to hold our button
    buttonsPanel = UI.CreatePanel(mainPanel).SetAnchors(0.1,0.9,0.05,0.12)
    -- Creates a new button in the buttons panel without any callback since it's going to be set by our entity.
    saveButton = UI.AddBlueButton(buttonsPanel,"Save Sign", "buttons")
    -- Makes our button the size of our panel.
    saveButton.rectTransform.SetAnchors(0,1,0,1)

    -- Adds a close button to the main panel which will call our CloseUI function.
    closeButton = UI.AddCloseButton(mainPanel, "closeButton", CloseUI)
    -- Sets the anchors of the close button's rect transform to the right corner.
    closeButton.rectTransform.SetAnchors(0.9,1,0.9,1)

    -- Hides our canvas.
    myCanvas.gameObject.SetActive(false)
end

Entity code

function OnTemplate()
    -- Add your own model here.
    self.AddModel('bToast_Sign')
    -- Creates collisions for this entity.
    self.CreateSphereCollisions()
    -- This makes it possible to place this entity as a buildable piece.
    self.MakeBuildable()
end

-- The function OnClone() gets called by the engine whenever this entity is cloned.
-- Anything that needs to be unique to this entity's instance should go on the OnClone function.
-- As an example, if I had put the OnEnable listener OnTemplate instead it would get called on DelayCall
-- clones of this entity whenever any of them is enabled.
function OnClone()
    -- Registers a listener to call back the function "Enabled" when this clone gets enabled on the scene.
    self.RegisterListener(Messager.OnEnable,Enabled)
    -- If I'm the host I want to listen for messages of players connecting so we can send them the sign info.
    if(Game.IsHost) then
        self.RegisterListener(Messager.PlayerConnected,SendSignInfoToOthers)
    end

    -- Since our UI inputs are in a global script we'll call some global functions we set to retrieve them. 
    signTitleInput = Game.CallGlobalFunction("GetSignTitle")
    signTextInput = Game.CallGlobalFunction("GetSignText")

    -- We would like to listen for networked calls on this clone so other players can receive our sign info.
    self.ListenForNetworkCalls()
    -- Adds a Lua Trigger to this clone with the name "Sign" and a radius of 3.
    -- Triggers are interactable positions in the game where you can press the Interact button to run some code.
    actionLua = self.AddLuaTrigger("Sign",3);
    -- We're going to override the StartAction of our new trigger with the OpenUI function.
    -- StartAction gets called when we first press the Interact button on our trigger's radius.
    -- Our OpenUI function will open our Sign's UI.
    actionLua.OverrideStartAction(OpenUI)
end


function Enabled()
    -- When the object is enabled if we're the host we want to call the LoadSignInfo method in 5 seconds.
    -- We're doing this to give enough time for the other players to have finished loading our sign.
    -- Also make sure when you're creating the item json for this to set it to always load.
    -- Otherwise other players that are far away from the sign might have it not loaded and not get sign changes.
    if Game.IsHost() then 
        self.DelayCall(5,LoadSignInfo)
    end
end

-- We'll use this table to hold our sign title and text.
signInfo = {}

-- We'll use these function to concatenate a unique id for our title and text using the entity's spatialID.
-- Spatial ID gets set based on the entity's position in the world. 
-- So if this position changes (Item shifter?) we'll lose our sign's saved info which is not ideal.
-- Later on I'll have to add a listener for item shifter changes so we can save again when position changes.
function SignInfoTitleKey() 
    return "signTitle".. self.spatialID
end

function SignInfoTextKey()
    return "signText".. self.spatialID
end

-- This function gets called by my Enabled callback with a 5 second delay.
function LoadSignInfo()
    --Calls the change sign info function with loaded data for the title and text
    ChangeSignInfo(Data.LoadString(SignInfoTitleKey()),Data.LoadString(SignInfoTextKey()))
    -- This function sends the sign info to others in the room.
    SendSignInfoToOthers()
end

function SaveSignInfo()
    -- Since our UI is in a global script we'll call this global script to close it when we save the sign info.
    Game.CallGlobalFunction("SignCloseUI")
    -- This method calls a function across the network for all players in the room including yourself.
    -- We'll use this to call the ChangeSignInfo for everyone.
    self.CallFunctionOnEveryone("ChangeSignInfo",signTitleInput.text,signTextInput.text)
end

function SendSignInfoToOthers()
    -- This method calls a function across the network for other players in the room (not yourself).
    -- We'll use this to call the ChangeSignInfo for all other players.
    self.CallFunctionOnOthers("ChangeSignInfo",signInfo[SignInfoTitleKey()],signInfo[SignInfoTextKey()])
end

function ChangeSignInfo(title,text)
    -- Here we'll set the interaction name of our trigger to be our sign's title,
    -- or Sign if we don't have a title.
    if (self.actionLua ~= nil) then
        if (title ~= nil and title ~= "") then
            self.actionLua.SetInteractionName(title)
        else
            self.actionLua.SetInteractionName("Sign")
        end
    end

    -- We'll set our info in our signInfo table.
    signInfo[SignInfoTextKey()] = text
    signInfo[SignInfoTitleKey()] = title

    -- Then if we're host we'll save our info using the Data.SaveString methods
    if Game.IsHost() then
        Data.SaveString(SignInfoTitleKey(),signInfo[SignInfoTitleKey()])
        Data.SaveString(SignInfoTextKey(),signInfo[SignInfoTextKey()])
    end
end

-- We'll use this function to open our UI
function OpenUI()
    -- We'll update our title and text input to use our saved info and call our Open UI on the Sign UI script.
    signTitleInput.text = signInfo[SignInfoTitleKey()]
    signTextInput.text = signInfo[SignInfoTextKey()]

    -- Since our UI is in a global script we'll call a global function to open it.
    Game.CallGlobalFunction("SignOpenUI")

    -- Here we'll retrieve the save button from our global UI script
    saveButton = Game.CallGlobalFunction("GetSaveSignButton")

    -- If the save button is not nil it has been retrieved sucessfully.
    -- We will then unregister all callbacks and register a new one, to make sure we're only saving
    -- the info on our own sign and not on other clones of it.
    if (saveButton ~= nil) then
        saveButton.UnregisterAllCallbacks()
        saveButton.RegisterCallback(SaveSignInfo)
    end

    -- And here we'll tell the trigger that we're done with our trigger action.
    actionLua.StopTrigger()
end

Comments