Creating a multiplayer Flash game with Red5 and Robotlegs. Need advice on architecture

Paul Borawski's Avatar

Paul Borawski

21 Jun, 2012 06:31 PM

Hi Robotlegs community,

I am currently developing a multiplayer game for iOS, Android, and BlackBerry using Flex and Red5. The basic premise of the game is that a picture from our server is shown to all the players in the room (the room can have a min of 3 players and max of 7). This first part is the Caption state where the players have 50 seconds to write a caption. Either when all the players wrote a caption or the time runs out, the game moves into the Voting state. This phase all the players have 25 seconds to vote on their favorite caption and they cannot vote on their own. So when time runs out or all the players submit their vote, the Scoring state shows the winner of the round who got the most votes. Now there is tie breaker code and other intricacies of the game that I need not mention but that's the overall concept.

So I developed a working prototype that isn't using Robotlegs yet and while it works it's extremely rigid and very buggy, so I am looking to refactor it for Robotlegs. How I currently have it set up is that the client pushes their captions and votes to the server. The server is basically the mother brain of the whole operation. It determines to the clients when the round starts, how long each state is going to be, who won the round, and so forth. I do all of this by having a multi slot shared object on our Red5 server. This switch state is the heart of the game code on the client, as it tells the client what was updated and the client code sends out the corresponding events:

private function roomSyncChangeHandler($changeObjNameStr:String, $dataValue:*):void
{

        trace("roomSyncChangeHandler called!");
        trace("$changeObjNameStr = " + $changeObjNameStr);
        trace("$dataValue = " + $dataValue);

        //This switch statement needs to call methods on the RoomModel
        switch ($changeObjNameStr)
        {
            case IS_ROOM_READY:
            {
                dispatch(new ModelUpdateEvent(ModelUpdateEvent.IS_ROOM_READY, $dataValue));
                break;
            }

            case CURRENT_IMG_PATH:
            {
                dispatch(new ModelUpdateEvent(ModelUpdateEvent.CURRENT_IMG_PATH, $dataValue));
                break;
            }

            case CURRENT_ROUND:
            {

                dispatch(new ModelUpdateEvent(ModelUpdateEvent.CURRENT_ROUND, $dataValue));
                break;
            }

            case MIN_PLAYERS_READY:
            {
                dispatch(new ModelUpdateEvent(ModelUpdateEvent.MIN_PLAYERS_READY, $dataValue));
                break;
            }

            case UPDATE_USERS:
            {
                dispatch(new ModelUpdateEvent(ModelUpdateEvent.UPDATE_USERS, $dataValue));
                break;
            }

            case UPDATE_CAPTION_LIST:
            {
                dispatch(new ModelUpdateEvent(ModelUpdateEvent.UPDATE_CAPTION_LIST, $dataValue));
                break;
            }

            case UPDATE_VOTING_LIST:
            {
                dispatch(new ModelUpdateEvent(ModelUpdateEvent.UPDATE_VOTING_LIST, $dataValue));
                break;
            }

            case GAME_STATE:
            {
                dispatch(new ModelUpdateEvent(ModelUpdateEvent.UPDATE_GAME_STATE, $dataValue));
                break;
            }

            //this passes an array of integers for the room rules that the client is to abide by
            case ROOM_RULES:
            {
                dispatch(new ModelUpdateEvent(ModelUpdateEvent.ROOM_RULES, $dataValue));
                break;
            }

            case START_TIMER:
            {
                dispatch(new ModelUpdateEvent(ModelUpdateEvent.START_TIMER, $dataValue));
                trace("START_TIMER CALLED FROM SERVER!");
                break;
            }

            default:
            {
                break;
            }
        }
    }

I am total newbie to RobotLegs, but I have read much of the book and have gone through several tutorials, although none of them seem to have the setup that my game requires. Many of the projects I see seem to have the client always initiating the calls to the server, where as mine is mostly the server telling the client what to do. I created a RemoteSharedObjectService class to handle the connecting to Red5 and to handle the SyncEvent changes called when the server updates the shared object.

So now I am finally getting to my questions.
1) Is having the server control all of the logic with the clients basically being views for the game logic the best way to go about this?
2) If so, I don't get how the service layer should be handled. Do I just have my service class make direct calls on the models and the model sends events to update the view or do I use commands from the service to the model or directly to the view?

Any guidance in any way is greatly appreciated!

  1. 1 Posted by Abel de Beer on 21 Jun, 2012 08:52 PM

    Abel de Beer's Avatar

    Hey Paul,

    Sounds like a fun project! Let me try and answer your questions.

    1) Yes, this is the appropriate way, because you're creating a multiplayer game. The server should decide who is allowed to do what and when something should happen, so it is the obvious choice for a 'game controller'.

    2) I'll give you a push into the right direction about Robotlegs's MVCS implementation (going from most to least obvious):

    • View: renders the photo and the 'caption editor' and any other necessary audiovisual feedback that is part of the game. Make sure that is its only function: it shouldn't care about the communication with the server. In this scenario, it would probably be preferred to have Mediators only listen to events from the Model(s) and other Views.

    • Service: connects to your Red5 server, listens for the required events and dispatches its own events in response, with the necessary data. This data is allowed to be 'raw' - Arrays, simple Objects, etc. This way you'll keep your "Red5ServerService" clean, which increases reusability (and maintainability, flexibility, and other MVCS-bilities).

    • Model: keeps track of the current game's state - the currently connected users, a highscore list, the current player's ID / name / score, etc. When these values are updated it sends its own events in response.

    • Controller: commands handle the events that need more processing. For example, the Red5ServerService might dispatch a PLAYERS_UPDATED event when someone joins or leaves the room, carrying a simple Object with the current players' properties. A command could then create typed value objects (VO) of this data, so it is easier to add to your Model and/or to be interpreted by your Mediators. Another example, explaining view-to-server communication: the current player enters a caption and presses a 'send' button in the CaptionView, its corresponding CaptionMediator dispatches a SEND_CAPTION event in response along with the actual text, a CheckAndSendCaptionCommand is mapped to this event and verifies and formats the text and then calls the 'sendCaption' method of the injected Red5ServerService, after which the service sends the message to the server in the right data format.

    I hope this has given you a clearer view of the different Robotlegs elements and their corresponding functions.

    I'm sure you'll have more questions, so don't hesitate to ask!

    Cheers,

    Abel

  2. 2 Posted by Paul Borawski on 21 Jun, 2012 09:31 PM

    Paul Borawski's Avatar

    Thanks! That's all great info. Very helpful. I will be plugging away at it more this weekend so I'll post any questions back here if you don't mind. Thanks again!

  3. 3 Posted by Paul Borawski on 22 Jun, 2012 05:25 PM

    Paul Borawski's Avatar

    Hi Abel,

    I got another question for you. So I am working on the CheckAndSendCaption command like you mentioned. Right now that just cleans up the string and sends it along to the RemoteSharedOBjectService. The service has a method called addCaptionFromUser which sends this call to the Red5Server

    nc.call("addCaptionFromUser", $roomIDStr, $userIdStr, $textStr);

    So as you can see I need to send a user ID and a room ID to the server as well.
    My question is at what point do I get the userID and room ID that are housed in their respective vo's? Do I inject my model into the command to get the room and user IDs and send that along to the service or does the service get the IDs from the models through injection or a series of events back and forth? I hope this makes sense. Thanks again for any help you can give!

  4. 4 Posted by Paul Borawski on 22 Jun, 2012 07:50 PM

    Paul Borawski's Avatar

    Actually I was looking at an example on the Flex Mobile in Action book, and he injects his model at the mediator level and sends the info that way. I am going to try that but not sure if that's the most effective way of doing things

  5. Ondina D.F. closed this discussion on 27 Aug, 2012 10:37 AM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac