Red5作做服务器的玩家移动信息同步例子

http://www.sujun.org/feed.asp?cateID=15

以前的旧文章,归下类而已.....目前也在用red5做服务器开发一款比较小的flash网络游戏,呵呵...期待...

玩家移动信息同步例子,我已经写过了两个版本的啦,一个java的,一个是fms的,现在又写了个red5的,其实这些的原理都是差不多的。以前好象没怎么讲解原理,这些就写得详细点吧。用red5做服务器,其实客户端基本是fms一样的。(事实上就是一样,哈哈)。无非就是客户端呼叫服务端的方法,服务端呼叫客户端的方法。(这是同步是没有采用ShareObject的,过阵可能会写吧)
先看下图片吧


首先先来看看最基本的(具体的内容我就不写了,代码里有详细的解释,在这里我只说说思路和逻辑)
程序代码 程序代码

var mync:NetConnection = new NetConnection();   mync.connect("rtmp://localhost/game");连接到服务器
mync.onStatus = function(info)
{
if (info.code == "NetConnection.Connect.Success")
{
  trace("接通");
  //通知服务器,有新用户登陆了
  this.call("userLogin",null,userName);
}
};


看这段代码。当客户端连接服务器成功后,马上呼叫服务端的用户登陆方法,并把新登陆的用户名传了过去。那么我们再看服务端

程序代码 程序代码

/**
  * 用户登陆
  * @param userName:用户名
  */
public void userLogin(String userName)
{
  System.out.println("新用户登陆:" + userName);
  //检查是否已经有用户登陆,有登陆,则呼叫其他用户接受新登陆用户的信息
  if(map.size() > 0)
  {
   for(Iterator<IServiceCapableConnection> it = map.values().iterator(); it.hasNext();)
   {
    IServiceCapableConnection ic = it.next();
    //发送用户名过去
    ic.invoke("userLogin", new Object[]{userName});
   }
  }
  //放进map对象中保存
  map.put(userName,getCurrentConn());
}


当客户端call的时候,服务器就执行userLogin里的代码。在这里个方法里服务器只做了两件事,一是把map对象里的所有的客户端连接对象进行遍历,把新登陆用户的信息发送给所有已经登陆的客户端。然后再把当前的客户端连接对象保存在服务端的map对象中。接着来看ic.invoke ("userLogin", new Object[]{userName})这句代码,他是呼叫客户端方法;既然服务端呼叫客户端的userLogin方法,那么我们可以过来客户端的 userLogin方法。

程序代码 程序代码

//当有新用户登陆时,被服务器呼叫
mync.userLogin = function(name:String)
{
//根据名字复制一个新的mc,最近登陆的用户
var mc:MovieClip = _root.attachMovie("personMC","personMC" + name,depth++);
userSet.put(name,mc);
mc.setName(name);
//马上呼叫客户端,把自己的位置告诉新登陆的客户端
mync.call("userInfo",null,userName,name,personMC._x,personMC._y);
};


在客户端里,该userLogin方法也是做了两件事,一是马上根据传过来用户名,生成了有一个新的mc(在实际中就是玩家,而且真正应用中,传的还不止一个参数),接着又呼叫服务端的一个方法userInfo,因为它必须把自己的信息通知给刚刚登陆的用户,包括自己的名字,位置等等。  接下来我们就看服务端的userInfo方法啦

程序代码 程序代码

/**
  * 已经存在的用户的信息
  * @param userName:用户名
  * @param x:x坐标
  * @param y:y坐标
  */
public void userInfo(String selfName, String userName,double x,double y)
{
  Object[] ōbject = new Object[3];
  object[0] = selfName;
  object[1] = new Double(x);
  object[2] = new Double(y);
  map.get(userName).invoke("createUser",object);
}
服务端的这个方法就简单啦,只做了一件非常简单的时,就是把当前的传过来的用户信息,转发一个指定的用户就行了(其实就是最新登陆的那个用户) map.get(userName).invoke("createUser",object),呼叫了客户端的createUser方法。客户端:
//更新已经登陆的用户
mync.createUser = function(userName,x,y)
{
//根据名字复制一个新的mc
var mc:MovieClip = _root.attachMovie("personMC","personMC" + userName,depth++);
userSet.put(userName,mc);
mc.setName(userName);
mc._x = x;
mc._y = y;
}


客户端的这个方法也很简单,就是根据服务端转发过来的信息,生成一个新的mc(玩家),同时还有位置。
好啦,到了,一个用户登陆到服务器,在所有客户端同步显示的步骤就完成啦。
接下来就把最后的功能完成,就是当一个客户端移动时,在其他客户端的也做对应的动作。呵~~不用我说什么也应该想了吧。恩,其实也是很简单,就是当前用户操作时,做自己的操作命令通过服务端转发其他所有的客户端,就达到同步的目的了。例如这一句代码:if( Key.isDown( Key.UP ) )
{
  personMC.up();
  mync.call("userAction",null,userName,"up");
}

当按下键盘的UP时,客户端就呼叫服务起的userAction的方法,同时把自己的名字(才知道哪个用户的动作)和动作(具体哪个动作)传给了服务器,下面是服务端的代码

程序代码 程序代码

public void userAction(String userName, String action)
{
  Object[] ōbject = new Object[2];
  object[0] = userName;
  object[1] = action;
  //对所有的用户进行遍历
  if(map.size() > 1)
  {
   //取出当前用户的conn
   IServiceCapableConnection temp = getCurrentConn();
   for(Iterator<IServiceCapableConnection> it = map.values().iterator(); it.hasNext();)
   {
    IServiceCapableConnection iconn = it.next();
    //如果不是当前用户,则发送信息
    if(temp != iconn)
    {
     iconn.invoke("userAction", object);
    }
   }
  }
}


恩,这个方法也简单,就是把收到的信息发送给所有的客户端,注意这句代码
IServiceCapableConnection iconn = it.next();
    //如果不是当前用户,则发送信息
    if(temp != iconn)
    {
     iconn.invoke("userAction", object);
    }
这是为了防止把该信息发送给自己,因为服务器是做遍历的,也就是说会对所有登陆该服务器的用户进行遍历,所以应该排除发送该命令的用户。接下来就看客户端的userAction方法啦
//当其他用户有动作时,被服务器呼叫
mync.userAction = function(name:String,action:String)
{
var mc:MovieClip = userSet.get(name);
//执行对应的方法
mc[action]();
};
它也只做了一件事,就是找出该用户对应的mc(玩家),然后执行相应的动作
OK~~~代码解释就到这里啦。光看我写的这个还是不行,大家还有把源代码提供去看看,大家有什么问题,就到red5的专有论坛去讨论吧。www.openred5.com. 这个网站。那里也有red5的配置教什么的。这里所以这里我就不在讲述啦。呵~本来想弄些漂亮的人物进去。不过没什么时间啦,今天是牺牲中午睡眠时间写的,大概花了一个小时,呵呵。如果很多人喜欢的话,往后会继续发布该系列的东西,例如用户说话,攻击,自己的名字是红色的等等,呵呵。

下载文件 Red5源代码下载

AS3与Red5之间的参数传递

2008年2月20日,14:30:47 | sujun10@21cn.com(弃天笑)转到全文
差不大一年没去动red5了,现在因为项目需要又开始使用red5,呵呵,先写些基本应用吧
参数传递是最基本的,之前是as2,现在用as3与red5 0.63了,几乎没什么变化.不过flash这边的可以传递的参数也就多了一些.就基本的是
String,int,Number,Boolean,Array,对应到red5这边是String,int,double,boolean,List
下面看基本的代码吧:
Flash:
程序代码 程序代码

/**
 * @(#)ParamRed5.as
 * @author soda.C
 * @version  1.0
 * <br>Copyright (C), 2007 soda.C
 * <br>This program is protected by copyright laws.
 * <br>Program Name:GameHall
 * @data 2008-2-19
 */
package org.sujun.red5.test 
{
    import flash.display.Sprite;
    import flash.net.NetConnection;
    import flash.events.NetStatusEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.Responder;
    /**
     * 测试flash与red5之间参数的传递
     */
    public class ParamRed5 extends Sprite 
    {
        private var netConnection:NetConnection;
        
        public function ParamRed5():void
        {
            netConnection    = new NetConnection();
            
            netConnection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
            netConnection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
            
           netConnection.connect("rtmp://localhost/paramtest");

        }
        
         private function netStatusHandler(event:NetStatusEvent):void 
         {
             trace("连接状态:" + event.info["code"]);
             
            switch (event.info["code"]) 
            {
                case "NetConnection.Connect.Success":
                    trace("连接成功.....");
                    //呼叫服务器的baseParam方法,传递基本参数,string,int,number,Boolean
                    netConnection.call("baseParam", new Responder(baseParamResult),"soda.C",24,1000.1,false);
                    //封装数组,int
                    var ary:Array = new Array();
                    ary.push(1);
                    ary.push(2);
                    ary.push(3);
                    //封装数组,String
                    var ary1:Array = new Array();
                    ary1.push("a");
                    ary1.push("b");
                    ary1.push("c");
                    netConnection.call("receiveArray", new Responder(baseParamResult),ary,ary1);
                    break;
                case "NetStream.Play.StreamNotFound":
                    trace("Stream not found: ");
                    break;
            }
        }
        
        private function baseParamResult(obj:Object):void
        {
            trace(obj);
            trace("响应了.....");
        }
        private function securityErrorHandler(event:SecurityErrorEvent):void 
        {
            trace("securityErrorHandler: " + event);
        }
    }
}

接下来看java代码
ParamRed5App.java,该类继承了ApplicationAdapt
程序代码 程序代码

package org.sujun.red5.test;

import java.util.List;

import org.red5.server.adapter.ApplicationAdapter;

/**
 * 存放被flash客户端调用的方法
 */
public class ParamRed5App extends ApplicationAdapter
{
    public ParamRed5App()
    {
        System.out.println("被初始化了......");
    }
    /**
     * 接受服务器传过来的基本参数
     */
    public void baseParam(String name, int age, double value, boolean flag)
    {
        System.out.println("----name----" + name);
        System.out.println("----age----" + age);
        System.out.println("----value----" + value);
        System.out.println("----flag----" + flag);
    }
    /**
     * 接受客户端传递过来的数组
     */
    public void receiveArray(List<Integer> intArray, List<String> strArray)
    {
        for(int i = 0; i < intArray.size(); i++)
        {
            System.out.println("----intArray----" + intArray.get(i).intValue());
        }
        for(int i = 0; i < intArray.size(); i++)
        {
            System.out.println("----strArray----" + strArray.get(i));
        }
    }
}

代码很简单.......直接复制过去,建立一个red5应用就可以使用了
看结果...


不过,还是我是传上源代码
下载文件 点击下载此源代码
posted @ 2008-06-20 21:00  winnerlan  阅读(1014)  评论(0编辑  收藏  举报