Trending
Opinion: How will Project 2025 impact game developers?
The Heritage Foundation's manifesto for the possible next administration could do great harm to many, including large portions of the game development community.
This technical article presents an intriguing 'shared gaming' concept, using a Java/Flash framework to allow mobile Internet devices to control a big-screen game with participants in the same location - details, source code within.
May 6, 2008
Author: by Erik J. Johnson
Do portable games have to be small? What if multiple players were in the same physical space, all looking at one large shared screen? What if each player controlled his avatar through a laptop or a hand-held device with all the action visible on the big screen?
We decided to find out. Therefore, we built a prototype framework to test out this new gameplay model. We learned this new model is quite fun and not difficult to implement, or even add to existing games. We're giving away the framework and game code and encourage you to try it as well.
As part of an Intel team looking to push the limits of gaming, we decided to challenge the notion that games on small devices had to be small games. Instead, we set out to see what a "carry small, game large" framework might look like if we assumed:
The game clients will be mobile internet devices or small-form factor PCs connected to the internet.
The game is multiplayer -- we believe that most gaming is best done together.
The game framework should gracefully deal with groups of people as they gather and disperse. This means no installation of game software on game clients.
All players had access to a common, large, shared screen.
The supported games were not "twitch" games. While much of the responsiveness of the framework varies with network speed, the framework itself introduces some delay unsuitable for twitch games.
The result is a game framework on top of which we produced two games: a tanks game shown in Figure 1, and also a multiplayer jigsaw puzzle.
Figure 1 - (left) A client screen suitable for a small-form factor PC and (right) the large shared screen of the game.
The last assumption we made -- a shared screen -- is as intriguing as it is unorthodox. Requiring all game participants to be physically co-located restricts where this new game model can be used. We envision this game model being used in coffee shops, malls, theatres, conventions, and more. We also see this used in bars, where today group games are sometimes played, but with proprietary controllers as opposed to any internet-capable device.
While the shared screen assumption is restricting, it also frees the game designer to leverage the myriad of human-to-human communications. Because people can all see the same screen, they all can see and hear each other. When we tried playing this way with groups, they were able to strategize and laugh with one another because they we co-located. We also found the in-game taunting was good spirited -- nothing like a lack of anonymity to suppress some of the uglier side of multiplayer gaming.
Our usage model expects players to join and leave the game quickly and easily. To achieve this, we looked at the structure of web applications as our inspiration. Web applications place few software requirements on clients because they run inside a web browser. We decided to follow a similar model by implementing our usage model to run inside a web browser. This way the only requirement on the client is to have a modern graphical web browser.
To play the game, a player opens up a browser and goes to the game's URL, enters their name, and then their character appears on the big screen. Players are assigned a unique name and icon to keep track of their input and score. Players control their avatar using controls in the browser on their portable device. Players' input is transferred asynchronously using JavaScript/AJAX from the player's screen to a server database.
On the server side, we use well-known web technologies such as a web server, PHP, JavaScript/AJAX, and a relational database. The shared screen, which happens to also run in a web browser, is updated by new players' input found in the database. The database is used as a shared, synchronized, queue for players' input and to keep track of the current game instance. The current game instance is identified by a unique identifier that is saved in the database and is used to notify players of game restarts. When the saved game identifier changes, the database is updated and players automatically join the new game.
In all, the structure consists of two main components that we call a game client and a game server. The game client includes the players' interface to the game. The game server is made up of the UI that displays the playing field and the code that retrieves players' input from the database. The whole game is a variation of the producer-consumer problem. The players are the producers, the game is the consumer, and the database acts as the shared buffer. In our case, the database system takes care of the synchronization issues in the producer-consumer problem. This framework is illustrated in Figure 2.
Figure 2 - The main components of the game framework.
Although the game is displayed on the big screen, players interact with their local game client. The game client provides the players with the form they use to create their character. Once the player is logged in, the JavaScript code executing within the game client's browser intercepts input in the form of keystrokes or clicks of buttons found on screen.
The input is passed asynchronously using AJAX to the server side code (PHP) that places it into the database. As mentioned previously, the game client framework requires a web browser that supports JavaScript and creation of asynchronous objects.
Besides processing player input, the game client is in charge of player creation and destruction. Player creation internally creates a unique, session-based player ID that is used in the game to track corresponding player input -- each AJAX call and each entry in the database contains the player's unique ID.
In addition, the game client receives notification of game restarts. When such a notification is received, the game-specific code is expected to take the appropriate actions (e.g., joining the new game or providing the user with the initial screen to create a new player).
Figure 3. Flow of players' input into database.
The complement to the game client framework is the game server. The game server consists of the game UI and the server code that retrieves player input from the database. While the game server code operates much like the game client code, only in reverse, the main hurdle to overcome with the game server was processing user input and updating the game shared screen with minimal delay.
In web applications, a common way to retrieve updates from the server using AJAX is to poll the server on a set interval. In our case, we had to create an environment where the players' input would seem to flow directly from the players' side to the shared game view as quickly as possible. Using an asynchronous call to poll the server would be inefficient because the asynchronous object is created each time we make a call to the server.
Instead, we put a small twist on the asynchronous call to make better use of the existing object. An asynchronous object goes through five states when making a call to the server, results are processed on the last state, and the object is destroyed. In our case, we created collaboration between the server script and the asynchronous object to retrieve results continuously.
On the server side, we created a script that retrieves players' input in a loop and flushes its output buffer on each iteration. Flushing the output buffer makes the current results available to the asynchronous object without waiting until it reaches its last state. Once the server side loop is done, the asynchronous object changes to its last and complete state where it does nothing more than destroy and recreate the asynchronous object. With this setup, we are able to simulate multiple calls to the server in order to retrieve players' input with a single asynchronous object.
Another major function of the game server is to maintain the game instance. The game server deals with game creation and destruction. The game instance identifier used by players is created by the game server and made available to players via the database. In addition, the game server processes the players' input after retrieving it from the database.
We've built two simple game prototypes on top of the framework described in the previous section: a tanks game and a group jigsaw puzzle.
In this section, we describe how the tanks game was built. We hope that by showing how we built our prototype on this framework, we will show how you can build your game on top of the framework as well. The tanks game, the jigsaw puzzle, and the framework are available in source-code form at the Intel Software Network site.
The client-side code for the tanks game deals with player creation, player actions, and game restart.
When a player opens their browser to the player screen, they are presented with a simple HTML form as shown in Figure 4. You can download the HTML source code by clicking here.
Figure 4 - The player creation form.
When the player-create form is POSTed, PHP code extracts the player name and team color and then uses the game framework to both identify a unique number for the player and add a new player instance into the game database, as shown in the code in Figure 5.
public static function createPlayer( $name, $team ) {
// get number for player
$mates = $GLOBALS['db']->select(array(
'table' => 'players',
'fields' => array( 'id', 'teamNumber' ),
'condition' => array( 'team' => $team )
));
$number = 0;
if( !empty($mates) ) {
$next = $mates[0]['teamnumber'];
foreach( $mates as $mate ) {
if( $next < $mate['teamnumber'] ) {
$next = $mate['teamnumber']; } }
$number = ( $next + 1 ) % self::$NUM_TANKS; }
// create player
$_SESSION['me'] = new Player( $name, $team, $number );
// join the game
$_SESSION['me']->join( $GLOBALS['game'] );
}
Figure 5 - Adding a player to the game database.
At this point, the player is created and can begin to input actions (commands) into the game.
Player actions, or commands, are captured via JavaScript running in the client's browser after they have successfully created a player instance. This code, as show in Figure 6, first parses the input and then POSTs a message to the game server containing an indication of the player's command. (This code uses the jQuery JavaScript library to POST the message.)
// Player Controls:
// these are mappings to keyboard keys
var Control = {
Forward: 38, // arrow key up
Back: 40, // arrow key down
RotateLeft: 37, // arrow key left
RotateRight: 39, // arrow key right
Shoot: 32, // space bar
Quit: -1
};
// _execute is called when a user presses a key
var _execute = function( _opts ) {
switch( _opts.keyCode || _opts.which || _opts.other ) {
case Control.Forward: // move forward
_action.type = Command.Move;
_action.message = 'forward';
break;
case Control.Back: // move back
_action.type = Command.Move;
_action.message = 'back';
break;
…
default:
_action.message = '';
}
if( _action.message != '' ) { // send player command to server
$.post( _url, _action, function( gameID ) { … } }
Figure 6 - Handing Player commands in JavaScript.
At this point, the client code is nearly complete. We've created a player and passed the player's commands on to the game server. All that is left is to detect when the game has finished or restarted.
The game framework makes it easy to detect when a game has either ended or restarted. Each time a player command is entered, the response from the game server is the current game identifier. We check whether this identifier has changed, and if it has, we simply call createPlayer again (see Figure 5).
For both the tanks game as well as the jigsaw puzzle game server code, we used Adobe Flash* to render the images and animations on the shared screen. This section describes how we dealt with interfacing the game framework to Flash, followed by an example of accepting a player's request to move a tank forward.
It should be noted that while many games built on this framework may use Adobe Flash, the game framework code does not mandate the use of Flash.
While Flash afforded us many comforts in animating the game, it posed one primary challenge: the game framework provides a JavaScript/PHP interface, not a Flash interface. Therefore, our main challenge was how to get player creation and action commands from JavaScript/PHP into Flash. This trick here is to export a few Flash ActionScript functions and make those available to the game server's JavaScript. The game server's JavaScript interacts with the PHP code through HTTP POSTs/GETs. To make this concrete, in the game's action script code we exported calls to various functions as shown in Figure 7.
// set up all external calls
ExternalInterface.addCallback( "addTank", this, addTank );
ExternalInterface.addCallback( "removeTank", this, removeTank );
ExternalInterface.addCallback( "commandTank", this, commandTank );
ExternalInterface.addCallback( "newGame", this, newGame );
ExternalInterface.addCallback( "restartGame", this, restartGame );
Figure 7 - Exporting ActionScript Functions.
Once the ActionScript interfaces are exported, we can call them by packaging up an XML string representing the ActionScript function to call along with its arguments and calling the Flash object's “CallFunction” method, as show in Figure 8.
var _invoke = function( cmdName, args ) {
var _cmd_str = [
' '" returntype="javascript">',
'' + _toXML(args) +
'',
''].join('');
return _flashRef.CallFunction( _cmd_str );
}
Figure 8 - Calling ActionScript from JavaScript.
Once we can call ActionScript from JavaScript, we are left with the simple task of mapping player commands into ActionScript calls, as is shown in Figure 9 for moving a tank forward.
react: function( opts ) {
var cmd = '';
var params = '';
var _message = '';
switch( parseInt(opts.type) ) {
…
case 2: // move cmd = 'commandTank';
params = [ opts.source_id, 0,
opts.message ].join('_');
break;
…
}
if( cmd != '' ) {
var _ret = _invoke( cmd, params );
}
},
Figure 9 - JavaScript player action command parsing
We've presented a new usage model for multiplayer games that takes advantage of players being in a single location looking at a shared view of the game and controlling the game with mobile devices. We explained important aspects of the game framework we developed to implement this usage model borrowing ideas and technologies such as AJAX from the web development world. We presented a detailed walk through of a game built on this framework.
The last thing we'll do is to make our code available to the public and let you have a go at this usage model that we've applied to games but can be extended to the other areas. The next steps are yours - take the code and make your own games or applications. Again, the code is available for download via Intel's website (email address required) or via Gamasutra. There is also a video available here with more information.
Remember that games are just one example of the usage model. A number of future directions are possible for this work:
Porting existing games to use this framework and usage model
Developing new games -- or even new game genres -- based on this usage model
Focus on improving performance and response time
Focusing more on graphics capabilities of the server that are not possible on the client
Trying this out in more and more locations, with more and more players at a time
Trying this for non-game usages: audience polls, group creativity, and whatever else you can think of
We are excited to see and hear where this technology goes. We would love to hear from you about your uses of this code. Please contact us!
Read more about:
FeaturesYou May Also Like