Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Over 10 years of community discussion and knowledge are maintained here as a read-only archive.

New discussions should be taken up in issues on the appropriate projects at https://github.com/PureMVC

Pages: [1]
Print
Author Topic: Mediator structure  (Read 12406 times)
shanestevens
Jr. Member
**
Posts: 17


View Profile Email
« on: August 30, 2011, 07:28:16 »

Hi,

Ok, getting to the end of my first week with PureMVC, and I have run into another question around architecture.  This time, my question is around Mediators for logic

In my previous, non-PureMVC, projects (games), I would create a task (my Controller layer) which would be long living, receiving all sorts of  'tick' messages and such.  That task, upon creation, would create a set of views (View layer) to display my content with it being the ViewDelegate, then sit there handling all sorts of messages until it was done.  At which point, it would kill itself, or be killed by another task/manager somewhere else.

For example, imagine a simplified 'GameTask'.  It is created after the player has left the front-end and is starting the actual game.

GameTask:
- onCreate:
  - Load assets (Model layer)
  - Create GameHUD View.
  - Create GameCanvas View.

- onTick
  - Update physics, player control, etc...

- onRender()
  - Render directly into the Game View.

- onDestroy:
  - Kill Game View
  - Kill HUD View
  - Kill assets

Ok, pretty standard stuff.

Now, when porting this to PureMVC, I'm trying to work out what goes where.  Because there is no such thing as a long running task/process (PureMVC Commands are transient), I'm not sure exactly where to put the game logic.  I could just pull it all out of PureMVC and have it running alongside, but that feels like it completely defeats the purpose of using PureMVC to begin with.

So because Notifications in PureMVC are sent through the View layer (i.e only Mediators can receive Notifications), I decided to make a State class that derives Mediator.  These states are sort of like my 'tasks'.  They can register, send and receive Notifications.  Still feels wrong though... I'm essentially putting logic in the View layer.

I then have a GameState (which 'isa' Mediator).  This is like my GameTask: long living, can access the Model layer via Proxies, can send/receive Notifications/Commands to do various things, can be registered and de/unregistered, and generally be the main man.

Here is cut down example of what I mean:
:
public class GameStateMediator extends State implements ITick
{
override public function onRegister():void
{
facade.registerMediator(new GameHUDMediator);
facade.registerMediator(new GameCanvasMediator);
// Register any Commands I need to talk to the rest of the system.
// Register itself with my game library to receive ticks.
}

override public function onRemove():void
{
facade.removeMediator(GameCanvasMediator.NAME);
facade.removeMediator(GameHUDMediator.NAME);
// Deregister any Commands.
// Deregister itself from my game library.
}

public function onTick():void
{
// Update physics, player control, etc...
// Anything that might be interesting to rest of the system, like the HUD, will cause a sendNotification(). e.g. COMMAND_PLAYER_HEALTH_UPDATED.
}

override public function handleNotification(n:INotification):void
{
// Respond to any other parts of the system sending Notifications.
}
}

public class GameHUDMediator extends Mediator implements IViewDelegate
{
override public function onRegister():void
{
// Create my custom library views, with 'this' as a delegate.
}

override public function onRemove():void
{
// Destroy my custom library views.
}

// From IViewDelegate
public function onViewRender(v:View):void
{
var gsp:GameStateProxy = facade.retrieveProxy(GameStateProxy.NAME) as GameStateProxy;
// render anything anything the view needs from data retrieved from the GameStateProxy.
}
}


Now, this all works, and seems ok, however I've got a niggling feeling the GameState could be a Proxy object, so all logic sits in the Model layer.  Also, should Mediators be registering other Mediators? Surely that's a job for a Command, but I want a persistent Command, not a transient one.

But even that feels odd, because it feels weird to say that any logic like gameplay, should reside in the Controller layer.

I'd love to hear what other people are doing here.

Cheers,
Shane
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #1 on: August 31, 2011, 02:30:27 »

Perhaps you should investigate the StateMachine utility. It's really a good answer for managing application state.

Here's a brief intro to the StateMachine: http://puremvc.tv/#P003/
-=Cliff>
Logged
shanestevens
Jr. Member
**
Posts: 17


View Profile Email
« Reply #2 on: September 01, 2011, 05:20:18 »

Actually, I am using the State Machine library, but it ultimately just emits notifications.  It doesn't address the structure questions I asked.

Shane
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #3 on: September 01, 2011, 08:05:20 »

Actually, I am using the State Machine library, but it ultimately just emits notifications.  It doesn't address the structure questions I asked.
Sorry, it sounded as if you were homebrewing the management of state from this:
I decided to make a State class that derives Mediator.  These states are sort of like my 'tasks'.  They can register, send and receive Notifications.  Still feels wrong though... I'm essentially putting logic in the View layer.

The State Machine does more than emit notifications. It listens for actions that trigger state transitions. From your above description it sounds like what you're missing is a fully fleshed out FSM. Can you show me your FSM?

The thing is you don't want a God Object actor that controls time and space and everything in between. You need a well-conceived FSM and something that sends action notes to the StateMachine on a regular basis (to perhaps break the 'gameloop' into phases), and commands and mediators that respond to the notifications of state change that it is orchestrating. The state machine is like a conductor waggling his little stick. He's not making the music, but he's directing everyone in the orchestra to make their notes based on his motions.

-=Cliff>
Logged
Deril
Full Member
***
Posts: 22


View Profile Email
« Reply #4 on: September 02, 2011, 11:05:14 »

Hi,

 you mentioned that you need persistent command. Why?


 some of my thoughts...

Imagine TimerMediator that would send ViewNote.GAME_TICK notices.
Then command (most likely macro) picks it up.. change proxy data if needed..
Then mediators react if needed.

 This fits well for top layer game logic, "macro world" how I call it...

For "micro world" (lets say you have 1000 items that needs to animate, and maybe change every tick) the trick I use is to have mediator that manages ALL those 1000 animations as components, and single note to update it with some clever/convenient data object.. (maybe array of object that must change only.) The state of those 100 could be still handled by command, using proxy, doing some math magic and stuff.

 Another strategy that could be used, is looking at that View with 1000 animations as a "black box" that has inner world of its own, interaction, tick engine and everything could be done inside of it (I don't suggest doing it in one class... :) just looking to view as very complex subsystem), and interacts with PureMVC at very high level. Mediator for that view could be only as bridge, that cares little what happens inside of that black box.
 You will not cover that subsystem in PureMVC, but if you decouple WHOLE subsystem from PureMVC - it's not a problem.


 What is your arguments on having persistent command?

Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #5 on: September 02, 2011, 02:30:22 »

Or you could also give the the command some protected static class variables, such that if a command needs to remember some trivial internal information like how many times it has executed before, you store them there. Only instances of the given command could access this information, so it isn't a bad use of static.

Maybe call it the Shirley McClain pattern: Instances have memories of past lives. :)

-=Cliff>
Logged
shanestevens
Jr. Member
**
Posts: 17


View Profile Email
« Reply #6 on: September 03, 2011, 03:55:20 »

Thanks to Cliff and Deril for responding.

Deril, with the TimerMediator you describe, you're starting to get at the question I was initially asking.  The issue being that non-view logic is being placed in the view layer, due to TimerMediator deriving Mediator.

This is heart of my issue.  Notifications float around the view layer, in that the view layer is the only layer that can respond to notifications.  In this case the TimerMediator could, and probably should, be a TimerProxy.  The TimerProxy (or maybe AppProxy is a better name) could listen for events from my own game library (game tick), and emit them for the rest of the system to consume.

In this scenario, I could mimic a traditional game loop by having a AppProxy that perhaps emits a macro command that sends the appropriate notifications in order, such as:

1. Tick.
2. Physics.
3. Begin Render.
4. Render.
5. End Render

However, creating and sending a notification, then having the GC destruct said message at 60fps stresses me out (I'm from a C++ background remember, where per-frame allocation is a disaster).  I guess I'll have to get over this.

Anyway, the main issue for me is putting too much logic in the view layer, when I think it should probably shift to the model layer, with the command layer used simply to coordinate the notification sending.  The trouble is that because the view layer is the only layer that can listen for notifications, it more or less guarantees that anything long running (i.e. something that needs to respond to notifications, such as a game state) needs to be a mediator.

In short: Mediators are the only class that can send/receive notifications, therefore anything that needs to know about a notification (such as onTick, or onRender, etc), has to be a mediator.  Hence, logic which isn't related to rendering (onTick for instance), ends up in the view layer.

I feel I'm close to having a model of what to do in my head, however I'm worried I'm trying to push a square peg into a round hole.  Has anyone else had experience in developing a real-time (i.e. continuous > 30fps update) game/app using PureMVC?

Shane
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #7 on: September 06, 2011, 07:47:23 »

Take a look at the HelloFlash demo. Self-directed, mediated objects. Maybe a centralized game loop isn't really the answer for an event driven environment?

http://trac.puremvc.org/Demo_AS3_Flash_HelloFlash

-=Cliff>
Logged
Deril
Full Member
***
Posts: 22


View Profile Email
« Reply #8 on: September 07, 2011, 01:55:23 »

In short: Mediators are the only class that can send/receive notifications....

well.. no.  Commands can do it also.

 logic should not be in mediator or proxy, they must be in commands.
Mediators generally listen for note to tell them what to show, and it is best that they should do it ignoring any sort of logic.
Logged
shanestevens
Jr. Member
**
Posts: 17


View Profile Email
« Reply #9 on: September 11, 2011, 09:43:38 »

In short: Mediators are the only class that can send/receive notifications....

well.. no.  Commands can do it also.

 logic should not be in mediator or proxy, they must be in commands.
Mediators generally listen for note to tell them what to show, and it is best that they should do it ignoring any sort of logic.


Actually Mediators are the only classes that can send AND receive notifications.  Commands can't.
Logged
shanestevens
Jr. Member
**
Posts: 17


View Profile Email
« Reply #10 on: September 11, 2011, 09:46:38 »

Take a look at the HelloFlash demo. Self-directed, mediated objects. Maybe a centralized game loop isn't really the answer for an event driven environment?

http://trac.puremvc.org/Demo_AS3_Flash_HelloFlash

-=Cliff>

I actually started to think the same thing, which is quite a shift away from a traditional game loop-orientated architecture, and have started on a framework around PureMVC to test a decoupled/notification-based main loop out.

- Shane
Logged
Pages: [1]
Print