Jump to content
Rick

Event system

Recommended Posts

We used to have something like this in LE 2 if I recall. It would be nice to have an event system in the Lua scripts. Somewhere where I can register to an event from another script and when that script fires said event my function that I registered will be raised.

Share this post


Link to post

I think this is the same idea they've got in GameMaker, and it's very successful - you would have a Create Event for variable initialization, Step Event for the main application loop, Draw Event for graphics and others but those 3 are the main ones used.

Share this post


Link to post

I was more thinking about having a system that makes it easy for us to make our own events for our gameplay scripts. An example could be creating an "onDead" event in one of my AI scripts. This script would trigger this event when the AI dies but we would code that triggering. Then from the editor we would be able to subscribe to that entities event from other entities so they can be informed of the event when it happens. Ideally by being able to specify a script function instead of one generic function to catch all events.

Share this post


Link to post

Here is an example of what I use:

 

Event.lua (the main event system)

 

if Event ~= nil then return end

Event = {}

function Event:Create()
  local obj = {}

  obj.handlers = {}

  for k, v in pairs(Event) do
     obj[k] = via
  end

  return obj
end

function Event:Subscribe(owner, method)
  table.insert(self.handlers, { owner = owner, method = method })
end

function Event:Raise()
  for i = 1, #self.handlers do
     self.handlers[i].method(self.handlers[i].owner)
  end
end

 

 

Here is an example usage:

 

Zombie.lua

import "Scripts/Systems/Event.lua"

function Script:Start()
  self.onDead = Event:Create()
end

function Script:Hurt(dmg)
  self.health = self.health - dmg

  if self.health <= 0 then
     self.onDead:Raise()
  end
end

 

 

Player.lua

Script.zombieEntity = nil --entity "Zombie"

function Script:Start()
  -- subscribe to an event from another script
  self.zombieEntity.script.onDead:Subscribe(self, self.ZombieDead)
end

-- this would be called via an event from another script
function Script:ZombieDead()
  System:Print("The zombie has died!")
end

Share this post


Link to post

What I suggest with this kind of stuff is to develop it first based on Lua and then it becomes a possible candidate for inclusion into the SDK or CPP source code. This is how I developed the animation system. That way if it needs to be changed or it runs out to be a bad idea it can be modified without breaking existing code. People's old games will still work and we haven't polluted the engine with a feature that gets replaced or creates breaking changes.

Share this post


Link to post

What if there was a command to programmatically add a flowgraph connection?:

Entity::AddOutput( std::string outputname, Entity* target, std::string functionname)

Share this post


Link to post

I'm intrigued. How would it be used in my simple example above? Can you show some code as an example?

Share this post


Link to post

One script calls something like this:

self.component:CallOutputs("Open")

 

The flowgraph system then just calls all connected functions on all entities, like in your event system. This all works right now, it just isn't set up to be created in code.

Share this post


Link to post

So in my example with this idea the zombie script would call self.component:CallOutputs("onDead") when it dies and the player would call self.entity:AddOuput("onDead", self.zombieEntity, "ZombiDead") inside its Start() to subscribe to that output? Also I assume this would called Script:ZombieDead() and not a global function named ZombieDead(),

 

The name AddOutput seems wrong. You're really connecting to an output.

 

This does seem promising.

 

Share this post


Link to post

The only reason you would not do this in the flowgraph would be if the entity did not exist in the map. Are you using the flowgraph already?

Share this post


Link to post

I'm not using the flowgraph no. These are dynamically created entities so this style would work perfect as I have a manager entity that is spawning these entities so that manager entity has details it can pass to the dynamic entities.

Share this post


Link to post

I was giving an example by calling this "Event". When I try to implement this it tells me Create() is nil. However Event gets highlighted blue. I'm guessing it's an LE table that you're exposing and just don't have it documented anywhere?

Share this post


Link to post

I have done something similar. I had a script that registered players to a playermanager.

 

 

The player manager is added to a pivot


function Script:Start()

--= self.entity.script:overwatch_registerplayer(playerEntity)

--[[ REQUIRE A CERTIAN OVERWATCH VERSION AND ABOVE. OVERWATCH VERSION SHOULD ALSO STATE HOW FAR BACK IT STAYS COMPATIBLE ]]

-- Would prefer that the manager finds the entities itself, but thats not a very easy task without ahead of time preperations before this script is even loaded

-- so we have the players self register

-- Register it's existance

if overwatch ~= nil then

if overwatch.playermanager == nil then

overwatch.playermanager = {}

overwatch.playermanager.players = {}

overwatch.playermanager.enabled = true

overwatch.playermanager.entity = self.entity

overwatch.playermanager.instances = 0

end

else

Debug:Error("Overwatch System Not Loaded")

end

overwatch.playermanager.instances = overwatch.playermanager.instances + 1 -- i thought it would be intresting to know how many times an overwatch unit is placed in the map

-- If the same script that saet the entity first is not the same one doing the test, we have too many entities

if overwatch.playermanager.entity ~= self.entity then

Debug:Error("Multiple inscances of Overwatch Player Manager: " .. tostring(overwatch.playermanager.instances) .. " instances")

-- it wont even get past 2

end

end

 

function Script:overwatch_registerplayer (playerEntity) -- Adds player to the list of forces to be acted apon

local i

for i =0, #overwatch.playermanager.players, 1 do

if overwatch.playermanager.players == playerEntity then

return false -- its already in it

end

end

table.insert(overwatch.playermanager.players,playerEntity)

return true

end

function Script:overwatch_unRegisterplayer (playerEntity) -- Remove player from the list of forces to be acted apon

local i

for i =0, #overwatch.playermanager.players, 1 do

if overwatch.playermanager.players == playerEntity then

table.remove(overwatch.playermanager.players,i)

return true

end

end

return false -- its already removed/never added

end

 

function overwatch_registerplayer (playerEntity) -- global function: points to local function

overwatch.playermanager.entity.script:overwatch_registerplayer(playerEntity)

end

 

function overwatch_unRegisterplayer (playerEntity) -- global function: points to local function

overwatch.playermanager.entity.script:overwatch_unRegisterplayer(playerEntity)

end

 

--[[

function Script:UpdateWorld()

 

end

--]]

 

--[[

function Script:UpdatePhysics()

 

end

--]]

 

--[[

function Script:Collision(entity, position, normal, speed)

 

end

--]]

 

--[[

function Script:Draw()

 

end

--]]

 

--[[

function Script:DrawEach(camera)

 

end

--]]

 

 

--This function will be called after the world is rendered, before the screen is refreshed.

--Use this to perform any 2D drawing you want the entity to display.

function Script:PostRender(context)

context:SetBlendMode(Blend.Alpha)

context:SetColor(1,1,1,1)

context:DrawText("PlayerManager Player Count:" .. tostring(#overwatch.playermanager.players),2,200)

context:SetBlendMode(1)

context:SetColor(0,0,0,0.5)

end

 

 

--[[

--This function will be called when the entity is deleted.

function Script:Detach()

 

end

--]]

 

--[[

--This function will be called when the last instance of this script is deleted.

function Script:Cleanup()

 

end

--]]

 

 

 

And in the Fps player script we register it.

 

function Script:Start()
overwatch_registerplayer(self.entity)
end

 

I basically created a global function that pointed to a local function.

 

If I wanted I could have the player manager poll in the Script:UpdateWorld() and do things to the players. That was the goal, but I never had enough time to do what I envisioned and dropped the project.

 

Edit--

This is the base system that everything loads into. Also added into a pivot

 

if overwatch == nil then -- Create the base table that all Overwatch systems use.
overwatch = {}
end

 

it loads a global table for all the other modules to find.

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...