In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Digital Wrestling V1

This is my first attempt to a multiplayer game using Union Reactor platform.

Just wait until an opponent comes in the room and then click the faster you can to win to the other player. Each point any user does, increases the game level, so it should be harder to win as rounds going by :)

Still having some UI Bugs, but i think it is going pretty nice so far. I'll be updating it.

As i'm still developing the idea, i will leave the output visible, so you can see a pseudo log from the application (i mean, not the full Union Reactor Log).

NOTE: IF NO ONES JOINS THE GAME YOU CAN PLAY WITH YOURSELF OPENING ANOTHER INSTANCE OF THIS URL.
Yeah... i know, it sounds bad... :)
/**
 * Copyright JorgeBraccini ( http://wonderfl.net/user/JorgeBraccini )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/50mX
 */

package {
    
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.events.TimerEvent;
    import flash.geom.ColorTransform;
    import flash.text.Font;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;
    import flash.utils.Timer;
    
    import net.user1.reactor.ClientEvent;
    import net.user1.reactor.ClientManagerEvent;
    import net.user1.reactor.IClient;
    import net.user1.reactor.Reactor;
    import net.user1.reactor.ReactorEvent;
    import net.user1.reactor.Room;
    import net.user1.reactor.RoomEvent;
    import net.user1.reactor.RoomManagerEvent;
    import net.user1.reactor.snapshot.RoomListSnapshot;
    import net.user1.reactor.snapshot.SnapshotEvent;

    public class DigitalWrestlingV1 extends Sprite {
        
        [Embed(systemFont="serif", fontName="font", unicodeRange="U+0041-U+005A", mimeType="application/x-font")]
        private var EmbeddedFont:Class;
        
        private var _client                   :Reactor;
        private var _room                      :Room;
        private var _room_list                :Array;
        private var _clickit_room_list        :Array;
        private var _room_count                :Number;
        private var _checkForExistentRooms    :Boolean = true;
        private var _running                :Boolean = false;
        
        private var _user_local                :ClickItUser;
        private var _user_remote               :ClickItUser;
        
        private var _container_ui            :Sprite;
        private var _ui_a                    :Sprite;
        private var _ui_b                    :Sprite;
        
        private var _match_result            :Number = 0;
        private var _match_level            :Number = 10;
        
        private var _score_txt_a            :TextField;
        private var _score_txt_b            :TextField;
        private var _match_txt                :TextField;
        
        private var _renderer                :Timer;
        
        public function DigitalWrestlingV1() {
            inittrace(this);
            init();
        }
        
        /*
          Let's create the main objects of the application.
         */
        private function init():void {
            
            drawUI();
            
            _user_local     = new ClickItUser();
            _user_remote     = new ClickItUser();
            _user_local.width = stage.stageWidth / 2;
            _user_remote.width = stage.stageWidth / 2;
            
            _renderer        = new Timer(33);
            _renderer.addEventListener(TimerEvent.TIMER, handleRenderTick);
            
            stage.addEventListener(MouseEvent.CLICK, userInvokesClick);
            
            _client = new Reactor();
            _client.addEventListener(ReactorEvent.READY, handleClientReady);
            _client.connect("tryunion.com", 80);
            //_client.connect("localhost", 9100);            //And now to wait until this client can connect with the Union Server.
            
            trace("Trying to connect Union Server...");
            writeUITextField(_match_txt, "Trying to connect Union Server...");
        }
        
        /*
              Once that connection has been made, we'll take a snapshot of the server's roomlist.
              We do this, because i have to know which rooms are available to play, and if no room is found, we have to create it.
            We have to do it, because for some reason (we think, server side processing improvings) the RoomManager only can access
            rooms that the client knows. We do not know really what that really means (meaning: if the user joins into some room,
            that means the RoomManager knows it. And if then, the user leaves the room and joins another one, i don't know if the
            RoomManager will recognize the old room, as sometime in that session was joined)... Anyway, to get a COMPLETE list
            of Rooms ID on the actually server, we have to take a Snapshot (in this case, a RoomListSnapshot); a Snapshot is basically
            an object that holds information about the properties of the server, not meaning that once you get it the server will keep it updated, 
            but just the server information in that point in time. If you want to update it, you have to request it again. Very understandable.
            Imagine how this improves the server performance.
         */
        private function handleClientReady(e:ReactorEvent):void {
            
            _user_local.id = Number(_client.self().getClientID());
            
            var roomlist_snapshot:RoomListSnapshot = new RoomListSnapshot(null, true);
            roomlist_snapshot.addEventListener(SnapshotEvent.LOAD, handleRoomListLoaded);        //Now getting ready to receive the snapshot...
            
            _client.updateSnapshot(roomlist_snapshot);    //Requesting it to the server...
            
            trace("Connected.");
        }
        
        /*
          Once the Snapshot is loaded, we have to filter the rooms created for this game and others, so let's make a little serach here...
        
          PS. We do not know if this is the best thing i can do to search rooms, we have been reading about qualifiers
          and we think the solution is in there, but since this is our first Union multi user application, we think it is ok. May be when we discover
          how to make it work in a better way, we'll update the program.
         */
        private function handleRoomListLoaded(e:SnapshotEvent):void {
            trace("Room List Loaded.");
            _room_count = 0;
            _room_list = RoomListSnapshot(e.target).getRoomList();
            
            _clickit_room_list = [];
            
            for each(var room_id:String in _room_list){
                if(room_id.search("DigitalWrestling") != -1){
                    _clickit_room_list.push(room_id);
                }
            }
            
            /*     Once we have listed all the rooms for the game in the server
                we have to check them out until we find an existent room with
                a player waiting for game. The possible results are two:
                    1 - The room has one player waiting.
                    2 - The room is full.
                This is because, since we have created the room to die when no
                one is left, every room with zero clients will be deleted.
            
                This is important, because this is a 2 players game, and what i
                wanted to do is something like a Room Manager (adjusting the platform 
                to the game logics), wich function will    be to search in every room 
                created for the game, look up for some room with one waiting to join,
                or if there's no room available upon that condition the program tells
                the Reactor RoomManager to create a new room, to join in and then 
                wait until a new user comes to play.
            */
            lookupRooms();
        }
        
        
        private function lookupRooms():void {
            
            var room_id:String;
            var room:Room;
            
            //Do the client have to lookup for the rooms on the server?
            if(_checkForExistentRooms){
                
                //If do, let's checkout if the room list is empty...
                if(_clickit_room_list.length != 0){
                    
                    /*
                        And now this will works like a basic loop, but instead of looping it on a for each loop
                        we'll command the RoomManager to observe a room and wait until the observed data is loaded.
                        This is because the only way to get the information about a specific room, as we said before,
                        the RoomManager has to "know" the room to access the information, and the only ways to actually
                        make it "know" about the room is to:
                            1 - Join a room.
                            2 - Observe a room.
                        To "observe" a room its like to be in the room but unabled to speak or interact in any way with
                        the room occupants. To the RoomManager, a client observing a room is an Observer (duh!).
                    
                        So, let's look inside our room list, one by one until its done...
                    */
                    if(_room_count < _clickit_room_list.length) {
                        room = _client.getRoomManager().observeRoom(_clickit_room_list[_room_count]);
                        room.addEventListener(RoomEvent.OBSERVE, handleRoomObserved);        //Wait until the observed data is fully loaded.
                        trace("Room found", room.getRoomID());
                        trace("Looking for opponents in",_clickit_room_list.length,"rooms...");
                        writeUITextField(_match_txt, "Looking for opponents in "+_clickit_room_list.length.toString()+" rooms...");
                    }else{
                        _checkForExistentRooms = false;
                        lookupRooms();
                    }
                    
                }else{
                    _checkForExistentRooms = false;
                    lookupRooms();
                }
            }else{
                /*
                    If the client don't have to look on the room list is because one of two things happened:
                        1 - A room was found.
                        2 - No room was found.
                */
                
                if(_room == null){
                    //If no room was found, then we create one.
                    trace("No rooms found.");
                    _room = _client.getRoomManager().createRoom("DigitalWrestling{"+Math.round(Math.random()*10000)+"}");
                    trace("Creating room", _room.getRoomID());
                    writeUITextField(_match_txt, "Creating room " + _room.getRoomID().toString());
                }else{
                    //If a room was found (meaning that another user is waiting) we check the clients connected to the room
                    //And set as a remote client the one's id is different of the local (Understanding that only 2 players can join the room).
                    var clients:Array = _client.getClientManager().getClients();
                    for each(var client:IClient in clients){
                        if(Number(client.getClientID()) != _user_local.id){
                            _user_remote.id = Number(client.getClientID());
                            break;
                        }
                    }
                    
                    setupClientsWithUI();
                }
                
                _room.addEventListener(RoomEvent.JOIN, handleRoomJoin);
                _room.join(null);        //And finally join in the room.
            }
        }
        
        private function handleRoomObserved(e:RoomEvent):void {
            var room:Room = Room(e.target);
            trace("Room Occupants:", room.getNumOccupants());
            
            if(room.getNumOccupants() < 2){
                _room = room;
                _checkForExistentRooms = false;
                lookupRooms();
            }else{
                _room_count ++;
                lookupRooms();
            }
            
        }
        
        /*
            When the client is joined succesfully to a room, well have to decide if the game starts or 
            if the game has to be setted in waiting mode.
        */
        private function handleRoomJoin(e:RoomEvent):void {
            trace("Joined in room", _room.getRoomID());
            
            _room.addEventListener(RoomEvent.ADD_OCCUPANT,         handleAddOccupant);
            _room.addEventListener(RoomEvent.REMOVE_OCCUPANT,    handleRemoveOccupant);
            
            _room.getNumOccupants() == 2 ?     start() : wait();
            
        }
        
        /*
            If the client was waiting, it will be able to "hear" when other client joins in the room. In that case,
            we have to set the remote client id and of course, switch the UI.
            After that, we can start the game.
        */
        private function handleAddOccupant(e:RoomEvent):void {
            trace("An opponent has joined.", e.getClientID());
            _user_remote.id = Number(e.getClientID());
            setupClientsWithUI();
            start();
        }
        
        private function setupClientsWithUI():void {
            if(_user_remote.id > _user_local.id){
                _user_local.ui         = _ui_b;
                _user_remote.ui     = _ui_a;
                _user_local.field     = _score_txt_b;
                _user_remote.field    = _score_txt_a;
                _user_local.side    = "right";
                _user_remote.side    = "left";
            } else {
                _user_local.ui         = _ui_a;
                _user_remote.ui     = _ui_b;
                _user_local.field     = _score_txt_a;
                _user_remote.field    = _score_txt_b;
                _user_local.side    = "left";
                _user_remote.side    = "right";
            }
        }
        
        private function writeUITextField(tf:TextField, value:*):void {
            tf.htmlText = "<font face='Arial' size='30' color='#FFFFFF'>"+String(value)+"</font>";
        }
        
        private function updateUI():void {
            writeUITextField(_user_local.field, _user_local.score);
            writeUITextField(_user_remote.field, _user_remote.score);
            writeUITextField(_match_txt, _match_result);
            _match_txt.x = _ui_a.width - _match_txt.width / 2;
        }
        
        //If some of the players leaves, stop the game.
        private function handleRemoveOccupant(e:RoomEvent):void {
            trace("Your opponent has left.");
            stop();
        }
        
        //Starts the game.
        private function start():void {
            _running = true;
            _room.addMessageListener("wrestling",                        handleScore);        //Listen to any incoming Message with "score" id.
            
            updateUI();
            _renderer.start();
            trace("DigitalWrestling has started...");
        }
        
        private function stop():void {
            _running = false;
            _room.removeMessageListener("wrestling",                    handleScore);        //Stop listening to incoming Messages.
            _renderer.stop();
            
            reset();
            wait();
            
            trace("ClickIt has stopped...");
        }
        
        private function reset():void {
            _match_level = 10;
            _match_result = 0;
            _user_local.width = stage.stageWidth / 2;
            _user_remote.width = stage.stageWidth / 2;
            _user_local.score = 0;
            _user_remote.score = 0;
            _ui_a.width = stage.stageWidth / 2;
            _ui_b.width = stage.stageWidth / 2;
            _match_txt.x = (stage.stageWidth / 2) - _match_txt.width / 2; 
            
            updateUI();
            trace("ClickIt was resetted...");
        }
        
        private function nextLevel():void {
            _match_level += 2;
            
            _match_result = 0;
            _user_local.width = stage.stageWidth / 2;
            _user_remote.width = stage.stageWidth / 2;
            
            _ui_a.width = stage.stageWidth / 2;
            _ui_b.width = stage.stageWidth / 2;
            _match_txt.x = (stage.stageWidth / 2) - _match_txt.width / 2; 
            
            updateUI();
        }
        
        private function wait():void {
            writeUITextField(_match_txt, "Waiting for an opponent...");
            trace("Waiting for an opponent...");
        }
        
        private function userInvokesClick(e:MouseEvent):void {
            if(_running) _room.sendMessage("wrestling", true, null);    //If game is running, send a Message with "score" id.
        }
        
        private function handleRenderTick(e:TimerEvent):void {
            _user_local.ui.width += Math.round((_user_local.width - _user_local.ui.width) / 10);
            _user_remote.ui.width += Math.round((_user_remote.width - _user_remote.ui.width) / 10);
            _match_txt.x += Math.round(((_ui_a.width - _match_txt.width / 2) - _match_txt.x) / 10);
        }
        
        private function win():void {
            
            if(_match_result < 0){
                if(_user_local.side == "right"){
                    _user_local.score++;
                }else if(_user_remote.side == "right"){
                    _user_remote.score++;
                }
            }else if(_match_result > 0){
                if(_user_local.side == "left"){
                    _user_local.score++;
                }else if(_user_remote.side == "left"){
                    _user_remote.score++;
                }
            }
            
            nextLevel();
        }
        
        /*
            This is how the score logic works. There is no too many logic, actually =).
            When an incoming Message with "score" id comes in, we have to decide if we have to add points
            to the local user and subtract from the remote user or viceversa.
            We have to update the UI, also.
        */
        private function handleScore(from:IClient):void {
            
            var scoreValue:Number = (stage.stageWidth / 2) / _match_level;
            
            if(from.getClientID() == _client.self().getClientID()){
                _user_local.width     += scoreValue;
                _user_remote.width     -= scoreValue;
                _match_result++;
            }else{
                _user_local.width    -=scoreValue;
                _user_remote.width    +=scoreValue;
                _match_result--;
            }
            
            if(Math.abs(_match_result) > _match_level){
                win();
            }else{
                updateUI();
            }
            
            trace("Match result:", _match_result);
        }
        
        private function drawUI():void {
            
            _container_ui = new Sprite();
            
            _score_txt_a = new TextField();
            _score_txt_b = new TextField();
            _score_txt_a.width = 50;
            _score_txt_b.width = 50;
            _score_txt_a.autoSize = TextFieldAutoSize.LEFT;
            _score_txt_b.autoSize = TextFieldAutoSize.RIGHT;
            _score_txt_a.selectable = false;
            _score_txt_b.selectable = false;
            _score_txt_a.x = 50;
            _score_txt_a.y = 50;
            _score_txt_b.x = stage.stageWidth - 50 - _score_txt_b.width;
            _score_txt_b.y = 50;
            
            _match_txt = new TextField();
            _match_txt.width = 100;
            _match_txt.autoSize = TextFieldAutoSize.CENTER;
            _match_txt.selectable = false;
            _match_txt.x = (stage.stageWidth / 2) - (_match_txt.width / 2);
            _match_txt.y = 200;
            
            _ui_a = new Sprite();
            _ui_b = new Sprite();
            
            _ui_a.graphics.beginFill(0xFF0000);
            _ui_a.graphics.drawRect(0, 0, stage.stageWidth/2, (stage.stageHeight / 3) * 2);
            _ui_a.graphics.endFill();
            
            _ui_b.graphics.beginFill(0x0000FF);
            _ui_b.graphics.drawRect(-(stage.stageWidth/2), 0, stage.stageWidth/2, (stage.stageHeight / 3) * 2);
            _ui_b.graphics.endFill();
            
            _ui_b.x = stage.stageWidth;
            
            _container_ui.addChild(_ui_a);
            _container_ui.addChild(_ui_b);
            _container_ui.addChild(_score_txt_a);
            _container_ui.addChild(_score_txt_b);
            _container_ui.addChild(_match_txt);
            addChild(_container_ui);
        }
        
    }
}

import flash.text.TextField;

class ClickItUser {
    public var score:Number = 0;
    public var id:Number;
    public var ui:Sprite;
    public var field:TextField;
    public var width:Number;
    public var side:String;
}

import com.bit101.components.TextArea;

import flash.display.Sprite;
var textarea:TextArea;

function inittrace(mainRef:Sprite):void {
    textarea = new TextArea();
    textarea.editable = false;
    textarea.width = mainRef.stage.stageWidth;
    textarea.height = mainRef.stage.stageHeight / 3;
    textarea.y = mainRef.stage.stageHeight - textarea.height;
    
    mainRef.addChild(textarea);
}
function doTrace(...args):void {
    var s:String = ""; 
    try { for each(var field:* in args) s += field.toString()+" ";
    s+="\n";    
    textarea.text = s + textarea.text;}catch (e:Error){ textarea.text = "Existe un argumento nulo.\n" + textarea.text; }
}
var trace:Function = doTrace;