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: JavaScript HTML5 Game  (Read 14648 times)
jrmorrill
Newbie
*
Posts: 6


View Profile Email
« on: October 26, 2012, 07:24:48 »

Hello All,

I have been creeping on this forum for the past couple weeks. I'm not a beginner to PureMVC, but I still have some more learning to do. Before I go into my questions, I should probably explain where I am coming from.

Over the past few six months or so i have been gradually iterating my side project, a HTML5 mobile game with PhoneGap. When I first setup the project, the NativeJS port wasn't available and it wasn't Multicore. I ended up using the PrototypeJS port since I was already familiar with classes and inheritance in PrototypeJS. Right now, my project is nearly at BETA. It utilizes the Canvas API in HTML5 and runs very nicely at 60 FPS.

I am looking to do some refactoring and utilize the Multicore NativeJS, and possibly a framework that supports namespacing. I have used Multicore in AS3, but not in Javascript. I also only have experience with using interfaces for Multicore communication, not pipes. OK on to the questions!

#1 - Should I abstract the view rendering of the application to a stand alone core so that I can switch it out as needed (for ex: different rendering cores for different platforms)? For this project my current target is iOS with future support for Android. Since I was using a single core, I ended up doing some dynamic view component loading. Basically I have a ViewProxy that will load in JS files dynamically as needed. For Android targets, I will provide different view components based upon the device resolution. With this approach I could create high-res iPad versions of the app as well that have a completely different layout than other versions.

#2 - Should I also move my game engine to a separate core? I envision this core containing all of the game simulation data and accepting input and other data from the user and pushing events to the display core. Currently the game display objects hold references to the game objects that they need to render and update the location every frame. I am not really using an Entity/Component based system and the scope of this game doesn't really necessitate it. However, if I WERE to use one down the road, I would hope that it would be fairly easy to plug it in when the game is encapsulated from the rest of the system. How the game simulation behaves internally should be of no consequence to the rest of the app.

I know I have more questions but I need to review my code to refresh my memory, so for now these will suffice. Thanks!
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #1 on: October 27, 2012, 02:03:34 »

#1 - Should I abstract the view rendering of the application to a stand alone core so that I can switch it out as needed (for ex: different rendering cores for different platforms)?
If you plan on having these varying view implementations, then certainly managing as much of that stuff in a separate core as possible would be good.

#2 - Should I also move my game engine to a separate core?
Well, if the answer to #1 is yes, then #2 is true by default, right? And if #2 were true, then #1 would be. The question that makes this more than a snarky observation, is: do you have other code that doesn't fall into category #1 or #2? For instance, if this were a multiplayer game and you talked to services a lot, then you might want to move your service communications into a separate core.

I think you're on the right track here, and hope to hear more about your experience as your project comes along.

-=Cliff>
Logged
jrmorrill
Newbie
*
Posts: 6


View Profile Email
« Reply #2 on: October 30, 2012, 10:35:17 »

Hey Cliff,

Thanks for the tips so far. I have already extracted most of my display code into a stand alone library kinda similar to flash. I have display objects and event dispatching that works nicely in canvas now.

My next step it extracting all the view code into a stand alone core. I am hung up a bit on the communication between cores. Are there any examples of communication between cores in JavaScript? I looked into pipes a little bit but I was unable to find any concrete examples.
Logged
Tekool
Sr. Member
****
Posts: 192


View Profile WWW Email
« Reply #3 on: October 31, 2012, 01:27:57 »

Bill White made recently a port to JavaScript of a demo for PureMVC Pipes I made for Flex a long time ago : http://www.billdwhite.com/wordpress/?p=450

Thanks to him, you will have a good entry point to start with Pipes in JavaScript compared to Flash.
Logged
jrmorrill
Newbie
*
Posts: 6


View Profile Email
« Reply #4 on: November 03, 2012, 11:51:33 »

Alright guys, I'm very close to getting this new "multicore" version up and running! Here are some details on my new implementation so far:

Shell Core:

The Shell Core behaves as the "mother brain" of the application. All modules are registered and piped in to the shell. The shell also handles the "Shell" view which is a basically a class that wraps a div element where the HTML5 application resides. The shell also manages most of the proxies. For example, it has a "DataProxy" which is used to retrieve level data from JSON files and user data from local storage. It also has a "ResourceProxy" which loads in sprite, animation and sound resources from a "ResourceManager".

Another feature I plan on adding to the shell is a transition system. The purpose of the transition system is to provide various ways to visually transition between module cores that have control over the display. The plan is to code several transitions such as "fade to black", "fade to white", "slide in" etc. These transitions will be called after a new display module has been initialized and is ready to take over.

Module Cores:

Module Cores can be any piece of the game that I want to isolate and modularize. For example, I am planning on modularizing my menu system, this includes the following views: "Title", "StageSelect", "LevelSelect". All of the business logic for these views will be contained in the "Menu Module". Any endpoints of the module will communicate with the shell core to transition the application to the next module. In the "Title" view, I could have a button that controls the application settings. If the user clicks on the settings button, I would then communicate with the shell that I wish to transition to the "Settings Module." The "Settings Module" will then be constructed, the transition applied and the old module will be destructed.

My current plan is to only allow one module to maintain control of the main display at a time. However, this doesn't mean that we can only have one module loaded at a time. It should be possible to have modules that do not have a main display to be loaded in as well. For example, I might want to implement a "Achievement Module" that does not require control over the display, but can inject view elements to a layer on top of the main display.

TBD:

So far this plan has been working out for me without much issue. I now have a basic understanding of how to construct and destruct pipes, however, I still might need some guidance on what constitutes a proper pipe message. I understand that requests for module creation, transition and destruction are definitely viable pipe messages, but what about requests for ProxyData? Due to the one way communication of pipes, I feel like requesting for level data or resources through the pipeline might not be the best way to go.

In my previous application design, requests for data and resources happened in the view construction process. I had a command for each view that would retrieve all of the data that the view needs. For example, the "LoadStageSelectCommand" requested stage/level VOs directly from the "DataProxy". Since the "StageSelect" view is now in it's own module (Menu Module) and the "DataProxy" is managed by the shell, what would be the best way to access the data without breaking encapsulation?

One solution I came up with was providing a way for each module to define the proxies it wants a reference to from the shell. When the shell creates the module, it can pass these proxies to the module. I could then treat these proxies almost as an external API that I could access from each module, perhaps having a proxy to abstract them from the module. I kinda feel like this type of a solution causes to much interdependence between a module and the shell. Any thoughts?
Logged
Tekool
Sr. Member
****
Posts: 192


View Profile WWW Email
« Reply #5 on: November 03, 2012, 03:56:56 »

Glad you're close to get your project working.

One solution I came up with was providing a way for each module to define the proxies it wants a reference to from the shell. When the shell creates the module, it can pass these proxies to the module. I could then treat these proxies almost as an external API that I could access from each module, perhaps having a proxy to abstract them from the module. I kinda feel like this type of a solution causes to much interdependence between a module and the shell. Any thoughts?

You're right, sharing a proxy reference between modules is not the good approach. But sharing data as you thought in the second part of your paragraph may be the right.

Your idea of asking via a notification a Proxy to send some data is the perfect one. To be sure to think modules and pipes communication the right way, just think modules as threads. If you share some data, this can be blocking, if you retrieve data synchronously it can be blocking, etc If we where in a multi-threaded environment this would be the solution of choice. It's really natural to think this way but as you supposed, requiring data of a Proxy, wait for it to send it to another one (even if it's hidden synchronous process in your game for the moment) can be quite long to write and somewhat quite long to process in a game environment that need speed.

A good intermediary solution to have something neat and at minimum cost is simply to use a common proxy class that each module will instantiate in its own environment (not the same instance shared). What you will share will be the reference to your data resource. Here in HTML 5 SQLite would be perfect, as it is thread safe (if I remember well). Then when some data is updated, the data module sends a notification to interested modules, interested modules so read the data. You can also use LocalStorage or even a simple reference to the same object in memory but you have to be careful with this solution, only the data module should have right to write to it. There's some smart things to do be sure to give write access only to the module that instantiate data first.

« Last Edit: November 03, 2012, 04:01:25 by Tekool » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #6 on: November 03, 2012, 06:01:27 »

You should definitely not pass MVC actors between cores. That defeats the concept of modularity entirely. No core/module should know anything about the contents of another.

However, you can always have a 'common' package that multiple cores share. Usually this is done to provide base classes that modules will sublclass and use internally. But you never have Core A referencing Core B's internal MVC actors.

What you generally pass between cores are view components and value objects.

Passing View Components
The Shell might host the main display, and various modules might contribute view components to the Shell. So, for instance, you might have a core that creates and mediates a view component that allows editing a user's profile. The Shell could take this component, insert it into its main display component, and that's it. The shell displays the component, but the core that created it mediates it.

In this case the view component might extend a common view component class that the shell can take and insert into its view hierarchy.

Passing Value Objects
Just as with the MVC separation, at the modular level, it's often a good idea to separate the service interactions into a separate core/module. A request object might be passed to such a module, which would interpret and act on the request, sending back a message with a value object returned from the service.

In this case the request and response might both be be value objects that just carry information. In both cases, the classes would be defined in a common library used by both cores.

So the cores can share typed objects that are defined in a separate library, but they should never refer to actors defined within another core.
« Last Edit: November 03, 2012, 06:13:21 by puremvc » Logged
jrmorrill
Newbie
*
Posts: 6


View Profile Email
« Reply #7 on: November 04, 2012, 03:30:16 »

You're right, sharing a proxy reference between modules is not the good approach. But sharing data as you thought in the second part of your paragraph may be the right.

You should definitely not pass MVC actors between cores. That defeats the concept of modularity entirely. No core/module should know anything about the contents of another.

Yea, I began to realize that almost immediately after I posted, not a very good idea at all.

A good intermediary solution to have something neat and at minimum cost is simply to use a common proxy class that each module will instantiate in its own environment (not the same instance shared).

Yes!!! So I began reading up more on Proxies and I realized I had been thinking of them all wrong. I have been doing a lot of data management INSIDE the proxies. So, in effect, they had become heavy and data centric when in reality they simply need to expose common methods to access and manipulate data that is managed and stored elsewhere. I don't know how this fact was not realized until now, even the name PROXY should convey the image of a middleman who simply routes the data to and from it's source and destination and doesn't store the data locally.

I have begun converting my ResourceProxy into a common Proxy class that can be instantiated in any module and the ResourceManager is now following the multiton pattern (previously it was just a common class) so that I can retrieve the correct instance of it in every ResourceProxy I create. No need to send requests outside of a module, the module now can have everything it needs internally to retrieve sounds, animations and data.

However, you can always have a 'common' package that multiple cores share. Usually this is done to provide base classes that modules will sublclass and use internally. But you never have Core A referencing Core B's internal MVC actors.

I do have a "common" package for all of my VOs and shared view components. However, is my plan to place the ResourceProxy and DataProxy in the "common" package acceptable architecturally? The shell app will be responsible for initializing the ResourceManager and DataManager and then the two proxies will simply be used by any module that needs to retrieve data or resources.

Passing Value Objects
Just as with the MVC separation, at the modular level, it's often a good idea to separate the service interactions into a separate core/module. A request object might be passed to such a module, which would interpret and act on the request, sending back a message with a value object returned from the service.

I feel like using the pipeline to send requests for resources and data might be a bit to much for this application (it's really just a single player puzzle game for mobile devices). I can totally see how isolating services to a module adds another layer of portability to the application. With the asynchronous behavior of pipes, you can easily begin to add modules for server communication and the modules will have no idea whether they are being used in a multiplayer game or a local game.

I do plan on implementing the passing of ViewComponents to the shell, thanks for helping me clarify how that is done properly. It makes sense that the module informs the shell when and how it wishes to be displayed. I was kinda stuck envisioning how to retrieve the correct view component from the module and how to tell if a module needs display. So here's a basic step-by-step procedure for adding a new module and having it update the shell display, please let me know if it makes sense.

#1 - The shell is told to add a new module. (this could be coming as a pipe message from a different module for exmaple)
#2 - The shell creates the module instance.
#3 - The shell calls the startup function on the module's facade, this preps the modules models and views.
#4 - The shell connects the module to the standard input and output pipes.
#5 - The shell sends the module a message to inform it that it's ready for communication.
#6 - The module then decides if it wants to take control of the main display. If it does, it sends a message to the shell passing itself as a view component. (not the facade, but the main view component of the module).
#7 - The shell then performs the necessary transition (perhaps specified in the previous message) removing the old view component and inserting the new one.


Tekool and Cliff, you guys rock! If either of you have iOS devices, I would absolutely love to have you included in my BETA. I will PM you both with a link to signup for my TestFlight team. Thanks!

Oh and here's a link to the Facebook site for the game:

http://www.facebook.com/CutieCrush
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #8 on: November 10, 2012, 03:08:40 »

Sounds cool, and let us know when the game is released.

Also, just remember if you are in a situation where you are wondering how to share a Proxy between modules, it is an indication that you really need to refactor that proxy out into a core of its own and talk to it via messages.

Ideally, modules know nothing more than a protocol for communications with other modules and only data and view components are shared or passed between modules.

Why is that?

Imagine a Facebook API Proxy. Lets say you have one module that fetches media from the user's album and does something with it. Also, you have another module that can make posts to the user's timeline. So, they both need either a reference to the FacebookProxy, or separate instances, right? NO!

Lets say the FacebookProxy has some changes with regard to the way functions have to be called, perhaps as a result of a change at Facebook, or perhaps just because the FacebookProxy is in flux as required features of the API are added.

When the FacebookProxy changes in such a way that its callers have to be changed, now you have more than one affected module that uses it. The more callers, the larger the potential impact of any given change.

However, if you put that FacebookProxy into a separate core, and create a protocol for talking to it via messages, you limit the impact of changes. JavaScript doesn't have interfaces, but a message protocol can serve the same goal.
Logged
Pages: [1]
Print