Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

"enterFrame" Runtime listeners to update game state?
Started by nml2727 Oct 17 2019 09:31 AM

- - - - -
5 replies to this topic

Best Answer davebollinger , 17 October 2019 - 11:51 AM

imagine that this is in game.lua (doesn't actually matter), set up some listeners:

local game = {
  onPlayerInjure = function(self,event)
    print("game knows player was injured", event.health)
  end,
  onPlayerDeath = function(self,event)
    print("game knows player died", event.health)
  end
}
Runtime:addEventListener("onPlayerInjure", game)
Runtime:addEventListener("onPlayerDeath", game)

imagine this is in player.lua (doesn't actually matter), causing those above events:

local player = {
  health=3,
  takeDamage = function(self,damage)
    self.health = self.health - damage
    Runtime:dispatchEvent({name="onPlayerInjure", health=self.health})
    if (self.health <= 0) then
      Runtime:dispatchEvent({name="onPlayerDeath", health=self.health})
    end
  end
}

and then "somewhere" (as long as "player" is in scope) demo it with:

player:takeDamage(1) --> 2 injure
player:takeDamage(1) --> 1 injure
player:takeDamage(1) --> 0 injure AND death

[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

nml2727

[GLOBAL: userInfoPane.html]
nml2727
  • Enthusiast

  • 96 posts
  • Corona SDK

The majority of my gameplay code resides in game.lua and this is a Composer scene.  Then I also have a good amount of code in player_maker.lua which relates more specifically to the player( ex:  lives remaining,  movement speed, etc).

 

My question:   What's the best way to make my game.lua module aware that something happened to the player?  

 

For example, if the player lost a life and I updated that value in player_maker.lua, or if the player collided with some particular object and I want the game.lua module to know about, how should I be doing that?

 

Right now I am doing something like this in my game.lua:

-- INSIDE game.lua

local player = player_maker.create()

local function updatePlayerLives()
     lives = player.lives
     if(player.lives == 0) then
          --do some stuff
     end
end

Runtime:addEventListener("enterFrame", updatePlayerLives)

Is this the best way to make game.lua aware that something changed in player_maker.lua?  Or is there a better alternative I should be using?   

 

Since the events I'm checking for do not happen often, it feels like a waste to be using a listener on every frame, but I'm not sure of another easy way to do it.

 



[TOPIC: post.html]
#2

davebollinger

[GLOBAL: userInfoPane.html]
davebollinger
  • Corona Geek

  • 1,373 posts
  • Corona SDK

there are several patterns commonly used..

 

one is to give "player" a reference to game, (player.game=game, or some-such), then player can directly call into self.game.onPlayerDeath() (for example, where "self" in this context is "player") if/as needed.  works fine though some don't like such tight bonding between supposedly separate modules, so..

 

another is messaging (aka "events" in corona-speak), such that game "listens" to what player is "sending": self:dispatchEvent({ name="onPlayerDeath" }) for example.  if "game" is a scene instance, then this is easy, just add a listener for your own custom event; or if a lua table/class, then either wrap in a system.newEventListener() or use your own messaging system, in which case..

 

yet another is some higher-level "controller" class (which could also implement a messaging system) that is the "parent" of BOTH "game" and "player" as siblings, each child can call/message their parent/controller, but can't call/message the other "sibling" directly, parent/controller would be responsible for inter-sibling relaying as appropriate.



[TOPIC: post.html]
#3

nml2727

[GLOBAL: userInfoPane.html]
nml2727
  • Enthusiast

  • 96 posts
  • Corona SDK

Thanks for the quick reply, Dave.  

 

I'm trying to wrap my head around the 2nd method you mentioned, regarding self:dispatchEvent...  

 

I'm not real familiar with custom listeners, but do I add the listener in the game.lua and then call the dispatchEvent from the player module?   

 

Would you be able to include a code snippet from game.lua and player.lua just showing how that interaction happens?



[TOPIC: post.html]
#4

davebollinger

[GLOBAL: userInfoPane.html]
davebollinger
  • Corona Geek

  • 1,373 posts
  • Corona SDK

  Best Answer

imagine that this is in game.lua (doesn't actually matter), set up some listeners:

local game = {
  onPlayerInjure = function(self,event)
    print("game knows player was injured", event.health)
  end,
  onPlayerDeath = function(self,event)
    print("game knows player died", event.health)
  end
}
Runtime:addEventListener("onPlayerInjure", game)
Runtime:addEventListener("onPlayerDeath", game)

imagine this is in player.lua (doesn't actually matter), causing those above events:

local player = {
  health=3,
  takeDamage = function(self,damage)
    self.health = self.health - damage
    Runtime:dispatchEvent({name="onPlayerInjure", health=self.health})
    if (self.health <= 0) then
      Runtime:dispatchEvent({name="onPlayerDeath", health=self.health})
    end
  end
}

and then "somewhere" (as long as "player" is in scope) demo it with:

player:takeDamage(1) --> 2 injure
player:takeDamage(1) --> 1 injure
player:takeDamage(1) --> 0 injure AND death

  • Alan PlantPot likes this

[TOPIC: post.html]
#5

davebollinger

[GLOBAL: userInfoPane.html]
davebollinger
  • Corona Geek

  • 1,373 posts
  • Corona SDK

if you "buy into" the event approach, just be aware that it will probably lead you all over the place..

-- just food for thought:  in player:takeDamage()
Runtime:dispatchEvent({name="onPlaySound", sound="ouch"})
-- assuming there's an audio sub-system somewhere listening for this

-- just food for thought: in game:onPlayerInjure()
Runtime:dispatchEvent({name="onUpdateHUD", health=event.health})
-- assuming there's a hud sub-system somewhere listening for this

etc.  once you start "decoupling" modules via events like this, it tends to go nuts.  initially that's probably a GOOD THING, just be aware of crossing the line into absurdity.

 

consider the mythical audio sub-system:  you don't even have to implement your audio sub-system yet, but you can sketch out the code in player anyway - the dispatched message will just be ignored until such time as "someone" bothers to listen for it.

 

it's usually much more responsive than player.lua doing stuff like this:

-- typical hard-wired non-event approach:

-- AudioSubSystem.lua might not even exist yet!
local AudioSubSystem = require("framework.AudioSubSystem")

-- and even if the module exists, the playSound method might not exist!
-- or might have some other name, or exist with that name but used to hold a string (not fn), etc
AudioSubSystem:playSound("ouch")



[TOPIC: post.html]
#6

nml2727

[GLOBAL: userInfoPane.html]
nml2727
  • Enthusiast

  • 96 posts
  • Corona SDK

Thanks much for the great explanation!

 

Was able to get it working using your example.  




[topic_controls]
[/topic_controls]