|
YOUR FEEDBACK Did you read today's front page stories & breaking news?
SYS-CON.TV |
TOP THREE LINKS YOU MUST CLICK ON General Java Developing Collaborative Games Using Active Objects
Developing Collaborative Games Using Active Objects
Jan. 1, 1998 12:00 AM
Abstract
Review of the Active Object
Architecture
Simulating Client/Server Interaction To begin, we define the blackjack server and blackjack client as active objects by extending ActiveObject.
class BJServer extends ActiveObject { Recall that our example active object architecture does not include networking capabilities. Therefore, for this example we will simulate multiple blackjack clients and one server all within one Java application as shown in Figure 1. This is accomplished by instantiating the server and all clients within a single application and calling each active object's start() methods. We will call this main application class Blackjack. As shown in Listing 2b, the Blackjack application instantiates the Blackjack server and four Blackjack clients. The Blackjack server also represents the dealer, which we will designate as seat number 0. The four clients represent four players occupying seats 1 through 4. Besides simplifying our example, this technique of running a group of interacting active objects within one application is a very useful technique to verify the correctness of a collaborative client/server protocol without the hassles of repeatedly restarting servers and clients during debugging.
Determining the Communication Protocol Following the active object design philosophy, the client and server will communicate through event passing between active objects. To design our blackjack client/server protocol, we will consider the mechanics of one session; that is, a client/server interaction between one server and up to four clients. Recall that in our active object framework an active object may handle events from other active objects in two ways - using the active event handler or the passive callback handler. For blackjack we will use the active event handler to handle game control flow, and the passive callback handler to handle status update events (events that are used only for displaying status on the screen and has no effect on the game flow). We'll first specify the events that are required to control one game (hand) of blackjack for a particular player. First, the dealer needs to deal two cards to the player, so let's define a deal_card event. Since this is a multi-player game, the player needs to wait until it is his turn to hit or stand. The dealer needs to notify the client with a request_action event. The player then chooses to hit or stand, so we need a hit and a stand event to reply to the server. During a sequence of hits, the player may bust, so the dealer needs to notify the client with a you_bust event. Finally, to conclude the game, the server needs to send a game_result event to notify the client that the current game is over. In addition to control flow events, other events pertaining to the status of other players may occur during a game. These events will be handled by a separate entity, the passive callback handler, which is responsible for displaying information (or graphics) about all players during game play. In our simplified blackjack game, we only need two status events. First, the server needs to notify every client whenever a card is dealt to anyone, so that the card may be shown on the screen. This notification is represented by the show_card message. Note that the show_card message is used in addition to the deal_card control flow message because show_card is handled by the passive event handler while the deal_card message is handled by the active handler. We need another event to notify everyone that some player has bust. This is represented by the bust message. See Table 1 for a summary of the event definitions. All events are defined by first defining a unique integer constant for each event type, which we define in class Blackjack:
public static final int hit = 1;
class deal_card extends Object The complete listing of event class definitions is given in Listing 2a. We are now ready to code the server and client active objects, which will use the events we have defined to communicate.
Blackjack Server Logic
class BJServer extends ActiveObject Though an active object may handle events in both the run() or handleEvent() methods depending on the nature of the events, in this case the blackjack server only requires the run() method to control game flow. Note that blackjack server's run() method may generate status events directed toward the passive handler on the client (BJClient.handleEvent()) in addition to control flow events directed at the client active handler (BJClient.run()), as shown in Figure 2. BJServer.handleEvent() is not used and is empty. As shown in Listing 2c, BJServer.run() is encased in an outermost while(true) loop so that the server may continuously serve games one after another. To begin a game, BJServer deals each player a card face up and a card face down.
for (int player=1; This is accomplished in the dealCardTo() method by multicasting the status update event show_card to all clients and sending the deal_card to the client representing the player actually receiving the card.
session.mcast(new show_card The dealCardTo() method also tracks the cards that each player has received so that the server may detect any player who has bust and the winner may be computed at the end of the game. See Listing 2c for details. Next, it is required to serve each player. This involves sending a request_action event and waiting for a hit or stand event from the client. If a hit event is received, then a card is dealt and a check for a bust is performed. If a bust occurs, then a status event bust is multicast to all players using mcast() and a control event you_bust is sent to the player that has bust. This step is repeated until all of the players have properly been "served"; that is, until all players have requested to stand or have bust. Finally, the server determines the winners and sends each player's game result using the event game_result.
Blackjack Client Logic
class BJClient extends ActiveObject We also need to register all of the status update events that are to be handled by handleEvent(). This is done using ActiveObject's registerCallback() method.
int[] evts = {BlackJack.show_card, Both active control logic and status update logic events are required to be handled by the client; thus, both the run() method and handleEvent() method must be implemented. Let's first look at the handleEvent() method. There are only two status update events that we need to be concerned with for this example: show_card and bust. These can be handled by handleEvent() by checking the event's hashCode() in a switch statement, similar to this:
switch (evt.hashCode()) In our example, we are just going to print out the status events that are received and their contents, since we are not implementing a graphical interface. Now let's implement the game control flow in BJClient.run(). Like BJServer.run(), we encase the run() method in an outermost while(true) loop so that multiple games may be played continuously. During a particular game, the first step is to wait for two cards to be dealt. This is done by performing two waitFor() methods, each like this: waitFor(BlackJack.deal_card); Then we need to wait for the control event, request_action, to start the client's turn. This is where the player is prompted whether he wants to hit or stand. A hit action by the player generates the control event hit and a stand action generates stand. If the player hits then BJClient continues in a loop (which we call the ActionLoop), waiting for either request_action or you_bust. The client stays in the ActionLoop until either the player busts or the player requests to stand. In Listing 2d, we implement prompting for hit or stand by reading characters from the keyboard, so when a "stand" command is received, the thread needs to break out of the action loop. Since the action loop is not the immediate innermost loop at this point, we use break ActionLoop; to break out of the loop labeled with the ActionLoop label. Upon exiting the ActionLoop, all that's left to do is to wait for the control event game_result, which informs the client that the game is over and whether the player won or lost. The client then continues to wait for the start of the next game by restarting the outermost while loop.
Funtopia: A Real-World
Implementation Avanteer, Inc., a company dedicated to Java-based collaborative solutions, has developed a full-scale multi-player game site called Funtopia using the active object design philosophy. Funtopia, at http://www.funtopia.com, includes a fully-featured multi-player blackjack game (Figure 3) which includes the networking and graphics aspects of a collaborative game that we have omitted in this article. All of the source code listings given in this two part article is available on the Avanteer web site, at http://www.avanteer.com. LATEST JAVA STORIES & POSTS
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
|
SYS-CON FEATURED WHITEPAPERS MOST READ THIS WEEK SPONSORED BY INFRAGISTICS
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||