A matter of architecture

Setting up a network game requires at least two Scenes, if not more.

There is the scene to connect, the scene to have the list of current participants, maybe find your friend and finally the scene of the real game.

Basically you have to pass the objects of the Photon library from one scene to another through the scene composer.

As you pass them, you must also manage events.

Can anyone help me find documentation on how to do it? or give me a tip on how to set up architecture?

Thanks
Renato

Maybe this can help?

Ciao Juni,

I think you need to consider two aspects:

  1. how big they are
  2. must they be persistent or will they be lost at the end of the game?

I studied the mechanism of passing data between scenes:
https://docs.coronalabs.com/api/library/composer/index.html

if I understand correctly there are two aspects (also here :slight_smile: )

  • switch data between two scenes
  • passing data between a parent scene and an overlayed one: classic example a pause / resume window

not least you could put on main.lua a beautiful global variable with your map data inside

main.lua file

globalMap ={}
...

I’d like to do it too with a megavariable, but Photon is an object that must be called at least every second, otherwise the connection to the server drops; and all its data are event driven.

I don’t know how to handle events from another scene.

Hello, you might want to consider using modules to store your data in. This way they would be reacheable from all scenes. Here is basic article about it:
https://docs.coronalabs.com/tutorial/basics/globals/index.html

Scroll down to Data modules.

Maybe you could do module photon.lua and require it on each scene? Put all functions and variables into and just call functions from scene.

1 Like

I read the modules. I use a module to save and load the settings. I use one to get the real screen size.
I am not able to code a module that internally has events invoking each other without going through the main code.
Can you give me some docs about that?

Thanks
Renato

What I thought was this:

If you require modul in one scene and then require the same module in other scene, its variables etc. stay the same. Modul just runs on. I dont know if this is helpful for you but here is example what I think:

--in modul.lua
local M = {}
local storedData = {}

function M.storeData ( data )
    storedData[#storedData + 1] = data
end

function M.getData ()
    return storedData
end

--in scene1.lua
local modul = require ( "modul" )
local myDataTable = { "customData" }
modul.storeData ( myDataTable )

--in scene2.lua
local modul = require ( "modul" )
local otherDataTable = modul.getData ()
--otherDataTable[1] in this case would contain { "customData" } string in table

What I thought was to put all event listener functions and variables you need to pass in modul and just call functions you need from different scenes…

My other thought was you could use just one scene for network setup, put everything in it and just hide UI components you dont need at the moment. display.newGroup () and isVisible property would be helpfull for this.

I hope this helps. Sorry if it is too basic for you or if it is not what you had in mind.

Jiri

Ciao Jiri,

I have to test what you tell me.

I thought a local variable was local. While you’re telling me that the data within a module is actually shared. this is interesting.

In fact the idea of calling an overlay scene seems to me the most credible.

The Photon library has a function that must be called repeatedly to keep the connection going. It’s a method of an object “client”. It should definitely be called with a separate timer.

If the connection to the server is successful, an event is received from the client object. If the game room is reached, another event is received. If you add a player another event. If data arrives another event. And so on.

Thanks,
I have two good ideas to work on!

Renato

Local variables are local for each lua file.
Once you “require” file, lua file is loaded. It is loaded only once so if you load it in another scene, it keeps its values. The article about global variables in the link I posted above was about this.

You can try this to perhaps make this more clear.

--in modul.lua
print ( "modul load" )
--in scene1.lua
local modul = require ( "modul" )
--in scene2.lua
local modul = require ( "modul" )
--> observe that "modul load" is printed only ONCE in simulator console
1 Like

Yes, I’m studing on “programmin in lua 4ed” from lua.org:

From the point of view of the user, a module is some code (either in Lua or in C) that can be loaded through the function require and that creates and returns a table. Everything that the module exports, such as functions and constants, it defines inside this table, which works as a kind of namespace.

and also

The first step of require is to check in the table package.loaded whether the module is already loaded. If so, require returns its corresponding value. Therefore, once a module is loaded, other calls requiring the same module simply return the same value, without running any code again.

thanks, I really didn’t understand!

Renato

@atanasovskyjiri’s suggestion to use modules is a good one, but if your only problem is that you don’t know how to pass functions between scenes, then why do you want to do that?

Couldn’t you just require and set up Photon within a single scene, e.g. your game scene?

Yes, I could do it all in a single scene but I don’t think of it as a good way of programming.

In one scene I would have to manage:

  • the setup to enter the network:
    look for any friends
    manage game choices (character, playing field or whatever)
    start with the game
    try to resolve any connection errors

  • the whole game itself

being able to extricate yourself with upgrades, debugging and anything else seems like a feat just to think about it!

In the game I would therefore keep only the management of sending and receiving data on the server and I tried to move the first piece to another scene.

How I can I solve the event handling between scenes?

if in the first setup scene I have for example:

netSetup.lua file - start ------------------------------------------- ------------------

photon = require “plugin.photon”
LoadBalancingClient = photon.loadbalancing.LoadBalancingClient

local client = LoadBalancingClient.new (appInfo.ServerAddress, appInfo.AppId, appInfo.AppVersion)

function client: onOperationResponse (errorCode, errorMsg, code, content)
...
end

function client: onStateChange (state)
...
end

function client: onError (errorCode, errorMsg)
...
end

function client: onEvent (code, content, actorNr)
...
end

function client: sendData ()
...
end

function client: timer (event)
- this one you have to call every 100 ms when connected to server
        self: update ()
end

...
- on start photon you have to set this timer
  timerId = timer.performWithDelay (100, client, 0)
netSetup.lua - end file ------------------------------------------- ------------------

how can I ‘migrate’ my client object on next gaming scene? with event and timer?

Timer I think to stop and start again: I found that the connection drop after 2 seconds that the function client: timer(event) doesn’t works.

But about to handle events on another scene ?

:frowning:

@renato.rolando, I’m going to give an overall perspective that will hopefully help you on this.

I’m not familiar at all with Photon, but network programming is just about the same.
One approach for this in your apps is to create these network connections outside of your Composer scene… in other words, your network module needs to be Global, so you initialize it only one-time when the app loads and then manage it accordingly throughout your app.

You can then access your network buffer from any scene you’re in, while maintaining the required network connections alive. The data you need to access can be part of your network module, or another module that acts as the middleman between your network module and each scene.

Yes, sure, could be.

But how can I handle the network events on the global object around the scene?

I had chosen Photon because it’s updated, there is assistance and it works on both android and ios.

Out of curiosity did you ever used another multiplayer manager?

Renato

If you created modul it would look something like this:

local modul = {}
modul.allClients = {}

local photon = require "plugin.photon"
LoadBalancingClient = photon.loadbalancing.LoadBalancingClient
modul.client = LoadBalancingClient.new (...)

function modul.client:onStageChange (state)
...
end

...

return modul

--in any scene
require "modul"
thisClient = modul.client
thisClient:onStateChange (state)
--"save" thisClient reference for use in other scene to reference table
modul.allClients[#modul.allClients + 1] = thisClient
1 Like

None.
Up to now all I have done is implement a server/client model for network connections using TCP sockets. :slightly_smiling_face:

thank you Atanasovsky
I quite understood. ; )
I’ll do some tests!

Renato

Dear All,
thank you for support. Thanks to you I got it !!
THE FINAL SOLUTION :wink:

Is so easy and simple to be really stupid.

on Main.lua define a global ‘variable’ (that represents a piece of code and data) with the ‘require’ module approach.

on other scene (lua’s files) I call the data and ‘overlay’ the function I want to trap with a function inside the scene.

That’s all folks. It works!

The example: I made a module that each 10 iteration call a function: myTest.
I have:
myTest:init() start iteration
myTest:service() add internal counter
myTest:onEvent() raised internal 10 counter

on each scenes I can overlay myTest:onEvent() with code inside the scene.

test.lua -- start -------------------------------------------------------
local M = {}
 
local myCounter = -1

function M:init()
  myCounter = 0
end

function M:debug(test)
  print ("Test : " .. test)
end

function M:onEvent() 
  self:debug("reach 10")
end

function M:service()
  myCounter = myCounter + 1
  self:debug("myCounter = " .. myCounter)
  
  if myCounter >= 10 then
    self:myEvent()
    myCounter=0
  end
end

return M
test.lua -- end -------------------------------------------------------

main.lua -- start -------------------------------------------------------
require("mobdebug").start()

local composer = require( "composer" )

myTest = require( "test" )

function myTest:onEvent()
  print("Hello world!")
end

for i=1 , 12 do
  myTest:service()
end

composer.gotoScene ( "welcome" )
main.lua -- end -------------------------------------------------------

welcome.lua -- start -------------------------------------------------------
local composer = require( "composer" )

--not necessary but just for clarity
myTest = require( "test" )

local scene = composer.newScene()

-- -----------------------------------------------------------------------------------
-- Code outside of the scene event functions below will only be executed ONCE unless
-- the scene is removed entirely (not recycled) via "composer.removeScene()"
-- -----------------------------------------------------------------------------------

function myTest:onEvent()
  print("Hello friends!")
end

-- -----------------------------------------------------------------------------------
-- Scene event functions
-- -----------------------------------------------------------------------------------

-- create()
function scene:create( event )

	local sceneGroup = self.view
	-- Code here runs when the scene is first created but has not yet appeared on screen
end


-- show()
function scene:show( event )

	local sceneGroup = self.view
	local phase = event.phase

	if ( phase == "will" ) then
		-- Code here runs when the scene is still off screen (but is about to come on screen)

	elseif ( phase == "did" ) then
		-- Code here runs when the scene is entirely on screen
    for i=1 , 12 do
      myTest:service()
    end

	end
end


-- hide()
function scene:hide( event )

	local sceneGroup = self.view
	local phase = event.phase

	if ( phase == "will" ) then
		-- Code here runs when the scene is on screen (but is about to go off screen)

	elseif ( phase == "did" ) then
		-- Code here runs immediately after the scene goes entirely off screen

	end
end


-- destroy()
function scene:destroy( event )

	local sceneGroup = self.view
	-- Code here runs prior to the removal of scene's view

end


-- -----------------------------------------------------------------------------------
-- Scene event function listeners
-- -----------------------------------------------------------------------------------
scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )
scene:addEventListener( "destroy", scene )
-- -----------------------------------------------------------------------------------

return scene
welcome.lua -- end -------------------------------------------------------

You will have as output:
“Test : myCounter = 0”
“Test : myCounter = 1”
“Test : myCounter = 2”
“Test : myCounter = 3”
“Test : myCounter = 4”
“Test : myCounter = 5”
“Test : myCounter = 6”
“Test : myCounter = 7”
“Test : myCounter = 8”
“Test : myCounter = 9”
“Test : myCounter = 10”
“Hello world!”
“Test : myCounter = 1”
“Test : myCounter = 2”
“Test : myCounter = 3”
“Test : myCounter = 4”
“Test : myCounter = 5”
“Test : myCounter = 6”
“Test : myCounter = 7”
“Test : myCounter = 8”
“Test : myCounter = 9”
“Test : myCounter = 10”
“Hello friends!”
“Test : myCounter = 1”
“Test : myCounter = 2”
“Test : myCounter = 3”

myTest:onEvent()
was changed without problems.
The internal counter worked without problem.

Note that you can add on top of the scene a ‘recall’ to external global variable and module, just for clarity. Nothing change.

On welcome.lua

--not necessary but just for clarity
myTest = require( "test" )

I’m very happy :slight_smile: :herb:

Renato

Glad to see you worked it out and didn’t give up. :slightly_smiling_face:

I will give up next time with the next problem.
But not today.

:slight_smile: