打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
FLASH网游通过XMLSocket与VB后台通信教程
FLASH网游通过XMLSocket与VB后台通信教程
转自闪吧论坛 陈策(作者)

前段时间用Flash做了个网游的Demo,通讯用的是Socket。曾承诺写个教程,现在有空就把它写写吧。
先从FLASH说起。我要达到的效果是点击地面,人物就走到点击的地点。思路:一个鼠标监听器监听鼠标的点击事件,把X座标和Y座标传到角色,做为角色的目的地。角色每一帧都向这个目的地移动一点点。
role_mc为场景里的一个MovieClip

  1. role_mc.x = role_mc._x;
  2. role_mc.y = role_mc._y;
  3. var mouseListener:Object = new Object();
  4. mouseListener.onMouseDown = function() {
  5. moveRole(role_mc, _xmouse, _ymouse);
  6. };
  7. Mouse.addListener(mouseListener);
  8. function moveRole(role:MovieClip, x:Number, y:Number) {
  9. role.x = x;
  10. role.y = y;
  11. role.onEnterFrame = function() {
  12.   if (this.x != this._x) {
  13.    this._x += this.x-this._x>0 ? 1 : -1;
  14.   }
  15.   if (this.y != this._y) {
  16.    this._y += this.y-this._y>0 ? 1 : -1;
  17.   }
  18.   if (this.x == this._x && this.y == this._y) {
  19.    delete this.onEnterFrame;
  20.   }
  21. };
  22. }
复制代码
试一下效果,发现角色会斜45度角移动到与目的地垂直或者水平后再垂直或水平运动。这是move函数里的算法没写好。我们现在来想想我想需要的是怎么样的移动。
[1.gif]
如图,角色在A点,要移动到B点去,方向就是AB。C点是下一帧角色将会出现的点,那向量AC就相当于角色的速度。将向量AC分解到两轴就得到x方向上的向量AE和y方向上的向量AD,这就是角色在这帧里需要移动的xy值了。角色的速度是已知的,要得到两个分解的向量,就只需要知道角度就行了。角度也可以根据A点和B点得到。我把角色面向右边时定为0度,则向上时为-90度,向下为90度,向左为180度。之所以这么定是为了计算方便。如Math.atan2(role_mc.y-role_mc._y, role_mc.x-role_mc._x)就可以直接到得角色面向的方向了(注意,Math.atan2得到的是以弧度为单位的数,不是角度)。所以把AS改写成:
  1. role_mc.x = role_mc._x;
  2. role_mc.y = role_mc._y;
  3. role_mc.speed = 5;
  4. role_mc.angle = 0;
  5. var mouseListener:Object = new Object();
  6. mouseListener.onMouseDown = function() {
  7. moveRole(role_mc, _xmouse, _ymouse);
  8. };
  9. Mouse.addListener(mouseListener);
  10. function moveRole(role:MovieClip, x:Number, y:Number) {
  11. role.x = x;
  12. role.y = y;
  13. role.angle = Math.atan2(role.y-role._y, role.x-role._x);
  14. role.onEnterFrame = function() {
  15.   if (this.x != this._x) {
  16.    this._x += Math.abs(this.x-this._x)>Math.abs(this.speed*Math.cos(this.angle)) ? this.speed*Math.cos(this.angle) : this.x-this._x; //当角色和目的地的距离小于角色的速度时,就不能再以速度计算出的位移,而直接移动到目的地,Y方向同理
  17.   }
  18.   if (this.y != this._y) {
  19.    this._y += Math.abs(this.y-this._y)>Math.abs(this.speed*Math.sin(this.angle)) ? this.speed*Math.sin(this.angle) : this.y-this._y;
  20.   }
  21.   if (this.x == this._x && this.y == this._y) {
  22.    delete this.onEnterFrame;
  23.   }
  24. };
  25. }
复制代码
移动看起来应该没什么大问题了。现在来做人物。把自己画的人物,或者是从游戏里抓图弄出来的人物处理好,我有两张从RO里弄出来的图。
[role.png][head.png]
将两张图导入到FLASH的role_mc里。因为我是把身体和头部所有方向都做成一张图,所以要用遮照来只显示需要的那个。将第一帧做成第一个方向的站立,给帧起名stand_1,加AS:stop();后边若干帧做成行走的动画,给帧起名run_1,加AS:play();在行走动画的后边加上一帧空白关健帧,加AS:gotoAndPlay("run_1")。这就完成了一个方向。在这一段后边加上其他几个方向。我做的是方向1为向下,2为左下,3为左,4为左上,5为上。其他三个方向可以之后用AS将234方向做水平翻转达到。也许我说得不是很明白,看我的这个文件(teach1.fla)就知道了。做好这一步之后,就可以在moveRole函数里加些东西,让角色做出相应的动作。我们先画个图来看一看角色的angle值分别代表角色面向哪个方向。见下图
[2.gif]
图中的红线就是每个方向的分隔线,把角度也列出来了,用弧度为单位是为了方便以后的计算。把AS也修改了一下就达到行走效果了。

  1. role_mc.x = role_mc._x;
  2. role_mc.y = role_mc._y;
  3. role_mc.speed = 5;
  4. role_mc.angle = 0;
  5. var mouseListener:Object = new Object();
  6. mouseListener.onMouseDown = function() {
  7. moveRole(role_mc, _xmouse, _ymouse);
  8. };
  9. Mouse.addListener(mouseListener);
  10. function moveRole(role:MovieClip, x:Number, y:Number) {
  11. role.x = x;
  12. role.y = y;
  13. role.angle = Math.atan2(role.y-role._y, role.x-role._x);
  14. role.dire = 1+Math.round((role.angle+Math.PI)/(Math.PI/4)); //把角色面向的角度的值从-Math.PI到Math.PI的范围变为1到8的自然数,分别代码八个方向
  15. role.dire = role.dire>6 ? role.dire-6 : role.dire+2; //把八个方向处理一下,和图上代表的方向符合
  16. if (role.dire>5) {
  17.   //如果方向为789中的一个,就水平翻转MC
  18.   role.dire = role.dire == 6 ? 4 : role.dire == 7 ? 3 : 2; //方向6对应方向4,7对应3,8对应2
  19.   role._xscale = -100;
  20. } else {
  21.   role._xscale = 100;
  22. }
  23. role.gotoAndPlay("run_"+role.dire);
  24. role.onEnterFrame = function() {
  25.   if (this.x != this._x) {
  26.    this._x += Math.abs(this.x-this._x)>Math.abs(this.speed*Math.cos(this.angle)) ? this.speed*Math.cos(this.angle) : this.x-this._x;
  27.   }
  28.   if (this.y != this._y) {
  29.    this._y += Math.abs(this.y-this._y)>Math.abs(this.speed*Math.sin(this.angle)) ? this.speed*Math.sin(this.angle) : this.y-this._y;
  30.   }
  31.   if (this.x == this._x && this.y == this._y) {
  32.    delete this.onEnterFrame;
  33.    this.gotoAndStop("stand_"+this.dire);
  34.   }
  35. };
  36. }
复制代码
大体样子已经出来了。现在我们来想想,其他的玩家要怎么办?当收到服务器有新玩家登陆这里的时候,FLASH要添加一个新的角色在画面上。我们可以做一个创造角色的函数,收到有新人登陆时就添加一个。而自己登陆的时候也可以用这个函数来创建自己。其他玩家移动,也是从服务器收到是谁要移动到哪的信息,FLASH只要调用moveRole函数就可以了。现在先做一个创建角色的函数。role_mc不需要再放在场景里,在库里给他一个链接名role,就可以方便用attachMovie命令调用了。

  1. role_mc.x = role_mc._x;
  2. role_mc.y = role_mc._y;
  3. role_mc.speed = 5;
  4. role_mc.angle = 0;
  5. var mouseListener:Object = new Object();
  6. mouseListener.onMouseDown = function() {
  7. moveRole(role_mc, _xmouse, _ymouse);
  8. };
  9. Mouse.addListener(mouseListener);
  10. function moveRole(role:MovieClip, x:Number, y:Number) {
  11. role.x = x;
  12. role.y = y;
  13. role.angle = Math.atan2(role.y-role._y, role.x-role._x);
  14. role.dire = 1+Math.round((role.angle+Math.PI)/(Math.PI/4)); //把角色面向的角度的值从-Math.PI到Math.PI的范围变为1到8的自然数,分别代码八个方向
  15. role.dire = role.dire>6 ? role.dire-6 : role.dire+2; //把八个方向处理一下,和图上代表的方向符合
  16. if (role.dire>5) {
  17.   //如果方向为789中的一个,就水平翻转MC
  18.   role.dire = role.dire == 6 ? 4 : role.dire == 7 ? 3 : 2; //方向6对应方向4,7对应3,8对应2
  19.   role._xscale = -100;
  20. } else {
  21.   role._xscale = 100;
  22. }
  23. role.gotoAndPlay("run_"+role.dire);
  24. role.onEnterFrame = function() {
  25.   if (this.x != this._x) {
  26.    this._x += Math.abs(this.x-this._x)>Math.abs(this.speed*Math.cos(this.angle)) ? this.speed*Math.cos(this.angle) : this.x-this._x;
  27.   }
  28.   if (this.y != this._y) {
  29.    this._y += Math.abs(this.y-this._y)>Math.abs(this.speed*Math.sin(this.angle)) ? this.speed*Math.sin(this.angle) : this.y-this._y;
  30.   }
  31.   if (this.x == this._x && this.y == this._y) {
  32.    delete this.onEnterFrame;
  33.    this.gotoAndStop("stand_"+this.dire);
  34.   }
  35. };
  36. }
  37. 大体样子已经出来了。现在我们来想想,其他的玩家要怎么办?当收到服务器有新玩家登陆这里的时候,FLASH要添加一个新的角色在画面上。我们可以做一个创造角色的函数,收到有新人登陆时就添加一个。而自己登陆的时候也可以用这个函数来创建自己。其他玩家移动,也是从服务器收到是谁要移动到哪的信息,FLASH只要调用moveRole函数就可以了。现在先做一个创建角色的函数。role_mc不需要再放在场景里,在库里给他一个链接名role,就可以方便用attachMovie命令调用了。
  38. //创建鼠标监听器
  39. var mouseListener:Object = new Object();
  40. mouseListener.onMouseDown = function() {
  41. for (var i = 0; i<allRoles.length; i++) {
  42.   if (allRoles[i].ctrl) {
  43.    moveRole(allRoles[i], _xmouse, _ymouse);
  44.    break;
  45.   }
  46. }
  47. };
  48. Mouse.addListener(mouseListener);
  49. //创建角色
  50. var allRoles:Array = new Array();
  51. allRoles[allRoles.length] = createRole(Math.random(), true, 5, Stage.width/2, Stage.height/2);
  52. function createRole() {
  53. var roleObj:MovieClip = this.attachMovie("role", "role_mc", this.getNextHighestDepth());
  54. roleObj.id = arguments[0]; //区别每一个角色的ID,可以从数据库中得到值。在这个教程里就直接用一个随机数代替
  55. roleObj.ctrl = arguments[1]; //标识该角色是否为由玩家控制的角色
  56. roleObj.speed = arguments[2];
  57. roleObj._x = arguments[3];
  58. roleObj._y = arguments[4];
  59. roleObj.x = roleObj._x;
  60. roleObj.y = roleObj._y;
  61. return roleObj;
  62. }
  63. //角色移动
  64. function moveRole(role:MovieClip, x:Number, y:Number) {
  65. role.x = x;
  66. role.y = y;
  67. role.angle = Math.atan2(role.y-role._y, role.x-role._x);
  68. role.dire = 1+Math.round((role.angle+Math.PI)/(Math.PI/4));
  69. role.dire = role.dire>6 ? role.dire-6 : role.dire+2;
  70. if (role.dire>5) {
  71.   role.dire = role.dire == 6 ? 4 : role.dire == 7 ? 3 : 2;
  72.   role._xscale = -100;
  73. } else {
  74.   role._xscale = 100;
  75. }
  76. role.gotoAndPlay("run_"+role.dire);
  77. role.onEnterFrame = function() {
  78.   if (this.x != this._x) {
  79.    this._x += Math.abs(this.x-this._x)>Math.abs(this.speed*Math.cos(this.angle)) ? this.speed*Math.cos(this.angle) : this.x-this._x;
  80.   }
  81.   if (this.y != this._y) {
  82.    this._y += Math.abs(this.y-this._y)>Math.abs(this.speed*Math.sin(this.angle)) ? this.speed*Math.sin(this.angle) : this.y-this._y;
  83.   }
  84.   if (this.x == this._x && this.y == this._y) {
  85.    delete this.onEnterFrame;
  86.    this.gotoAndStop("stand_"+this.dire);
  87.   }
  88. };
  89. }
复制代码
[ 本帖最后由 陈策 于 2007-6-20 17:03 编辑 ]

1.gif (3.71 KB)

1.gif

role.png (63.94 KB)

role.png

head.png (27.74 KB)

head.png

2.gif (12.98 KB)

2.gif

teach1.fla (143.5 KB)



图和相关文字不能放在一起-_- 大家麻烦点,上下对着看吧。

接下来是后台服务器的制作。我用的是Microsoft Visual Studio .NET 2003。语言为VB。
首先建一个空项目,命名为server(图3)。在这个项目的“解决方案资源管理器”上右击项目,选择“添加(D)”-“添加新项(W)”,添加一个类,命名为server.vb(图4)。在server.vb里写上socket的代码。我是从微软件的网站上的例子上修改来的,也没什么可说的。

  1. Imports System.Net
  2. Imports System.Net.Sockets
  3. Namespace ibaiy
  4.     Public Class Server
  5.         Private lisenSocket As Socket
  6.         Private allRoles As New Hashtable 
  7. Private rolesPosition As New Hashtable
  8. '在这个例子中我不打算用数据库了,所以建一个hashtable来存在线用户的资料。如果要存入数据库,只需要加上登陆后验证用户名密码,读数据库资料,再存到这个hashtable里。用户做了操作时再把hashtable里的数据处理后再写入数据库就可以了。这里的操作不难,但比较麻烦,所以我偷下懒
  9.         '启动服务的主函数
  10.         Public Sub startServer(ByVal port As Integer)
  11.             lisenSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
  12.             Dim ipen As IPHostEntry = Dns.Resolve(Dns.GetHostName)
  13.             Dim endpoint = New IPEndPoint(ipen.AddressList(0).Any, port)
  14.             lisenSocket.Bind(endpoint)
  15.             lisenSocket.Listen(1000)
  16.             lisenSocket.BeginAccept(AddressOf Me.Listen_Callback, lisenSocket)
  17.         End Sub
  18.         Public Sub Listen_Callback(ByVal result As IAsyncResult)
  19.             Dim s As Socket = CType(result.AsyncState, Socket)
  20.             Dim so2 As New StateObject
  21.             so2.workSocket = s.EndAccept(result)
  22.             so2.workSocket.BeginReceive(so2.buffer, 0, so2.buffer.Length, 0, AddressOf Me.Read_Callback, so2)
  23.             s.BeginAccept(AddressOf Me.Listen_Callback, s)
  24.         End Sub
  25.         Public Sub Read_Callback(ByVal result As IAsyncResult)
  26.             Dim so As StateObject = CType(result.AsyncState, StateObject)
  27.             so.len = so.workSocket.EndReceive(result)
  28.             opMsg(so)
  29.             so.buffer.Clear(so.buffer, 0, so.buffer.Length)
  30.             Try
  31.                 so.workSocket.BeginReceive(so.buffer, 0, so.buffer.Length, SocketFlags.None, AddressOf Me.Read_Callback, so)
  32.             Catch
  33.             End Try
  34.         End Sub
  35. '这个函数就是处理服务器收到客户端消息的处理函数,一会详细说明
  36.         Public Sub opMsg(ByVal so As StateObject)
  37.         End Sub
  38.     End Class
  39. End Namespace
复制代码
在server项目里像添加server.vb一样再添加一个StateObject.vb。这是为每个联接的SOCKET一定的buffer,索性做了一个新的类。写以下代码:

  1. Imports System.Net.Sockets
  2. Namespace ibaiy
  3.     Public Class StateObject
  4.         Public buffer(1024) As Byte
  5.         Public workSocket As Socket
  6.         Public len As Integer
  7.     End Class
  8. End Namespace
复制代码

3.gif (14.77 KB)

4.gif (13.5 KB)



我们要先想好客户端和服务器端有什么资料要通讯的,定好通讯的格式。我是这样设计的:通讯的资料我就不加密了,格式是01u=aa&xxxx 。前两位是代表了是做什么。u=aa是用户aa 做的操作。xxxx是操作的内容。
00 由服务器提供给客户端(简称S2C,下同),返回当前在线的所有用户。如:00u=a&x=0&y=0&u=b&x=54&y=78
01 C2S 用户登陆 如:01u=a
   S2C 告诉其他在线用户有新用户登陆 如:01u=a

02 C2S 用户移动 如:02u=a&x=100&y=50
   S2C 告诉其他在线用户某个用户在移动 如:02u=a&x=100&y=50

03 C2S 用户下线 如:03u=a
   S2C 告诉其他在线用户某个用户下线了 如:03u=a

04 C2S 用户发言 如:04u=a&内容
   S2C 告诉其他在线用户某个用户的发言 如:04u=a&内容

这里要说一下用户下线,用户下线是由用户在客户端点击“下线”完成,也可以是点击关闭FLASH的窗口完成。如果是点“下线”,那就由FLASH发送03过来就可以了。如果是点击关闭窗口的话,那只能由服务器端判断。当收到客户端发送的数据长度为零时,就可以判断客户端下线了。opMsg函数如下:

  1.         '处理收到的数据
  2.         Public Sub opMsg(ByVal so As StateObject)
  3.             Dim username As String
  4.             Dim sendmsg As String
  5.             Dim keys As IDictionaryEnumerator
  6.             '如果发送消息长度为0,断开客户端
  7.             If so.len < 1 Then
  8.                 keys = Me.allRoles.Values().GetEnumerator
  9.                 While keys.MoveNext
  10.                     If keys.Current.Equals(so.workSocket) Then
  11.                         username = CType(keys.Key, String)
  12.                     End If
  13.                 End While
  14.                 so.workSocket.Close()
  15.                 sendmsg = "03u=" + username + Chr(0)
  16.                 keys.Reset()
  17.                 While keys.MoveNext
  18.                     If Not keys.Current.Equals(so.workSocket) Then
  19.                         Me.send(keys.Key, sendmsg)
  20.                     End If
  21.                 End While
  22.                 Me.allRoles.Remove(username)
  23.                 Me.rolesPosition.Remove(username)
  24.                 Exit Sub
  25.             End If
  26.             Dim msg As String = System.Text.Encoding.UTF8.GetString(so.buffer, 0, so.len - 1)
  27.             Dim msgtype As String = Left(msg, 2)
  28.             Select Case msgtype
  29.                 Case "01"   '登陆
  30.                     Dim newMsg As String = "00"
  31.                     Dim isIn As Boolean = False
  32.                     username = Right(msg, msg.Length - 4)
  33.                     keys = Me.allRoles.Keys().GetEnumerator
  34.                     While keys.MoveNext
  35.                         If keys.Key <> username Then
  36.                             If newMsg <> "00" Then
  37.                                 newMsg += "&"
  38.                             End If
  39.                             newMsg += "u=" + keys.Key + Me.rolesPosition.Item(keys.Key)
  40.                         Else
  41.                             isIn = True
  42.                         End If
  43.                     End While
  44.                     newMsg += Chr(0)    '考虑到FLASH里接收SOCKET是用XMLSocket,每个 XML 消息都是一个完整的 XML 文档,以一个零 (0) 字节结束。所以以chr(0)结束。
  45.                     If Not (isIn) Then
  46.                         Me.allRoles.Add(username, so.workSocket)
  47.                         Me.rolesPosition.Add(username, "&x=275&y=200") '这里我给角色初位置是(275,200),正好是在FLASH场景的中心。
  48.                         sendmsg = msgtype + "u=" + username + "&x=275&y=200" + Chr(0)
  49.                         keys = Me.allRoles.Keys().GetEnumerator
  50.                         While keys.MoveNext
  51.                             If keys.Key = username Then
  52.                                 Me.send(keys.Current, newMsg)
  53.                             Else
  54.                                 Me.send(keys.Current, sendmsg)
  55.                             End If
  56.                         End While
  57.                     End If
  58.                 Case "02"   '移动
  59.                     username = Right(msg.Split("&")(0), msg.Split("&")(0).Length - 4)
  60.                     If CType(Me.allRoles.Item(username), Socket).Equals(so.workSocket) Then
  61.                         Dim xy As String = Right(msg, msg.Length - msg.Split("&")(0).Length)
  62.                         Me.rolesPosition.Item(username) = xy
  63.                         keys = Me.allRoles.Keys().GetEnumerator
  64.                         While keys.MoveNext
  65.                             If keys.Key <> username Then
  66.                                 Me.send(keys.Current, msg + Chr(0))
  67.                             End If
  68.                         End While
  69.                     End If
  70.                 Case "03"   '下线
  71.                     username = Right(msg, msg.Length - 4)
  72.                     If CType(Me.allRoles.Item(username), Socket).Equals(so.workSocket) Then
  73.                         keys = Me.allRoles.Values().GetEnumerator
  74.                         While keys.MoveNext
  75.                             If Not keys.Current.Equals(so.workSocket) Then
  76.                                 Me.send(keys.Key, msg + Chr(0))
  77.                             End If
  78.                         End While
  79.                         Me.allRoles.Remove(username)
  80.                         Me.rolesPosition.Remove(username)
  81.                         so.workSocket.Close()
  82.                     End If
  83.                 Case "04"   '聊天
  84.                     username = Right(msg.Split("&")(0), msg.Split("&")(0).Length - 4)
  85.                     If CType(Me.allRoles.Item(username), Socket).Equals(so.workSocket) Then
  86.                         keys = Me.allRoles.Keys().GetEnumerator
  87.                         While keys.MoveNext
  88.                             Me.send(keys.Current, msg + Chr(0))
  89.                         End While
  90.                     End If
  91.             End Select
  92.         End Sub
复制代码
要注意的是,发送的消息要以chr(0)结尾,这样FLASH才知道这是消息的尾,否则FLASH会以为还没完,还在等后边不存在的数据传过来。因为我懒,所以不打算在这个教程里做与数据库相关联的例子,如果要加的话,就在这个函数里的case里加就可以了。正确的做法应该是把每个case里的代码整理成一个个的功能块,方便以后调用。我懒-_-
还要写一个从服务器发消息给客户端的函数:

  1.         '向一个用户主动发信息
  2.         Public Sub send(ByVal user As Object, ByVal msg As String)
  3.             Dim sends As Socket
  4.             sends = CType(allRoles.Item(user), Socket)
  5.             Dim buffer() As Byte
  6.             buffer = System.Text.Encoding.UTF8.GetBytes(msg)
  7.             sends.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, AddressOf Me.Send_Callback, sends)
  8.         End Sub
  9.         Public Sub Send_Callback(ByVal result As IAsyncResult)
  10.             CType(result.AsyncState, Socket).EndSend(result)
  11.         End Sub
复制代码
做好这个DLL文件了,做一个面板吧。其时这是在开始写server.vb的时候就应该做的事,刚才给忘了。现在加上。在右边的“解决方案资源管理器”里右击“解决方案”,选择“添加(D)”“添加新项目(N)...”“visual Basic 项目”“Windows 应用程序”,命名为rpg。如图5[5.gif]。在“解决方案资源管理器”里右击“rpg”,选择“项目依赖项”,在弹出窗口里勾选server(刚才做的那个文件的名字)。在“rpg”下一行的“引用”上右击,选择“添加引用”,“浏览”找到用server.vb(server文件夹下有个bin文件夹,如果里边没有,你就先按F5调试生成它)生成的server.dll文件,选中之。在rpg上右击,再选择“设为启动项目(A)”。在rpg的面板上添加一个按钮,加上以下程序:

  1.     Private isStarted As Boolean
  2.     Private rpgServer As server.ibaiy.Server
  3.     Private Sub ServerForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  4.         Me.isStarted = False
  5.     End Sub
  6.     Private Sub Button_start_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_start.Click
  7.         If Not Me.isStarted Then
  8.             Me.rpgServer = New server.ibaiy.Server
  9.             Me.rpgServer.startServer(9999)
  10.             Me.isStarted = True
  11.         End If
  12.     End Sub
复制代码
现在可以调试一下VB的程序了。我做了一个简单的FLASH来测试的。这个FLASH就不说明怎么做了。我在下边有提供。[socket.swf],有兴趣的朋友可以自己看看。使用方法:服务器启动后,点击socket.swf上边的connect按钮,成功或者失败都会在中间显示出来。如果成功,就可以在下边输入要传输入的文字,格式就是上边我们定义好的“01u=a”之类的,当收到服务器传过来的文字也会在中间显示出来。可以开几个看看效果。

5.gif (15.09 KB)

socket.swf (42.01 KB)



接下来是在有人物的FLASH里加入与服务器通讯的功能了。我在FLASH的AS里加入XMLSocket的代码:

  1. //数据链接
  2. var conects:String = "127.0.0.1";
  3. var socket:XMLSocket = new XMLSocket();
  4. socket.connect(conects, 9999);
  5. this.socket.onData = function(str:String) {
  6. var type:String = str.substr(0, 2);
  7. var tmparr:Array = str.substr(2).split("&");
  8. //所有在线角色和位置
  9. if (type == "00") {
  10.   if (tmparr.length>1) {
  11.    for (var i:Number = 0; i<tmparr.length; i += 3) {
  12.     tmpName = tmparr[i].split("=");
  13.     tmpx = tmparr[(i+1)].split("=");
  14.     tmpy = tmparr[(i+2)].split("=");
  15.     allRoles[allRoles.length] = createRole(tmpName[1], false, 5, Number(tmpx[1]), Number(tmpy[1]));
  16.    }
  17.   }
  18. }
  19. //有新用户登陆
  20. if (type == "01") {
  21.   tmpName = tmparr[0].split("=");
  22.   allRoles[allRoles.length] = createRole(tmpName[1], false, 5, Stage.width/2, Stage.height/2);
  23. }
  24. //有用户移动
  25. if (type == "02") {
  26.   tmpName = tmparr[0].split("=");
  27.   tmpx = tmparr[1].split("=");
  28.   tmpy = tmparr[2].split("=");
  29.   for (var i = 0; i<allRoles.length; i++) {
  30.    if (allRoles[i].id == tmpName[1]) {
  31.     moveRole(allRoles[i], Number(tmpx[1]), Number(tmpy[1]));
  32.     break;
  33.    }
  34.   }
  35. }
  36. //用户下线
  37. if (type == "03") {
  38.   tmpName = tmparr[0].split("=");
  39.   for (var i = 0; i<allRoles.length; i++) {
  40.    if (allRoles[i].id == tmpName[1]) {
  41.     trace(allRoles[i])
  42.     removeMovieClip(allRoles[i]);
  43.     allRoles[i].splice(i, 1);
  44.     break;
  45.    }
  46.   }
  47. }
  48. };
复制代码
当然,原来的代码里还要加上一些东西,比如在创造角色的时候,要判断是否是自己控制的角色,是的话就要告诉服务器我登陆了。比如在鼠标点击的时候,也要告诉服务器我移动了。下边我把完整的AS代码再贴一遍。
  1. //数据链接
  2. var conects:String = "127.0.0.1";
  3. var socket:XMLSocket = new XMLSocket();
  4. socket.connect(conects, 9999);
  5. this.socket.onData = function(str:String) {
  6. var type:String = str.substr(0, 2);
  7. var tmparr:Array = str.substr(2).split("&");
  8. if (type == "00") {
  9.   if (tmparr.length>1) {
  10.    for (var i:Number = 0; i<tmparr.length; i += 3) {
  11.     tmpName = tmparr[i].split("=");
  12.     tmpx = tmparr[(i+1)].split("=");
  13.     tmpy = tmparr[(i+2)].split("=");
  14.     allRoles[allRoles.length] = createRole(tmpName[1], false, 5, Number(tmpx[1]), Number(tmpy[1]));
  15.    }
  16.   }
  17. }
  18. if (type == "01") {
  19.   tmpName = tmparr[0].split("=");
  20.   allRoles[allRoles.length] = createRole(tmpName[1], false, 5, Stage.width/2, Stage.height/2);
  21. }
  22. if (type == "02") {
  23.   tmpName = tmparr[0].split("=");
  24.   tmpx = tmparr[1].split("=");
  25.   tmpy = tmparr[2].split("=");
  26.   for (var i = 0; i<allRoles.length; i++) {
  27.    if (allRoles[i].id == tmpName[1]) {
  28.     moveRole(allRoles[i], Number(tmpx[1]), Number(tmpy[1]));
  29.     break;
  30.    }
  31.   }
  32. }
  33. if (type == "03") {
  34.   tmpName = tmparr[0].split("=");
  35.   for (var i = 0; i<allRoles.length; i++) {
  36.    if (allRoles[i].id == tmpName[1]) {
  37.     trace(allRoles[i]);
  38.     removeMovieClip(allRoles[i]);
  39.     allRoles[i].splice(i, 1);
  40.     break;
  41.    }
  42.   }
  43. }
  44. };
  45. //创建鼠标监听器
  46. var mouseListener:Object = new Object();
  47. mouseListener.onMouseDown = function() {
  48. for (var i = 0; i<allRoles.length; i++) {
  49.   if (allRoles[i].ctrl) {
  50.    moveRole(allRoles[i], _xmouse, _ymouse);
  51.    socket.send("02u="+allRoles[i].id+"&x="+_xmouse+"&y="+_ymouse);
  52.    break;
  53.   }
  54. }
  55. };
  56. Mouse.addListener(mouseListener);
  57. //创建角色
  58. var allRoles:Array = new Array();
  59. allRoles[allRoles.length] = createRole(Math.random(), true, 5, Stage.width/2, Stage.height/2);
  60. function createRole() {
  61. var roleObj:MovieClip = this.attachMovie("role", "role"+allRoles.length+"_mc", this.getNextHighestDepth());
  62. roleObj.id = arguments[0];
  63. roleObj.ctrl = arguments[1];
  64. roleObj.speed = arguments[2];
  65. roleObj._x = arguments[3];
  66. roleObj._y = arguments[4];
  67. roleObj.x = roleObj._x;
  68. roleObj.y = roleObj._y;
  69. //如果是创造了玩家自己,就要向告诉服务器“我登陆了”
  70. if (arguments[1]) {
  71.   socket.send("01u="+arguments[0]);
  72. }
  73. return roleObj;
  74. }
  75. //角色移动
  76. function moveRole(role:MovieClip, x:Number, y:Number) {
  77. role.x = x;
  78. role.y = y;
  79. role.angle = Math.atan2(role.y-role._y, role.x-role._x);
  80. role.dire = 1+Math.round((role.angle+Math.PI)/(Math.PI/4));
  81. role.dire = role.dire>6 ? role.dire-6 : role.dire+2;
  82. if (role.dire>5) {
  83.   role.dire = role.dire == 6 ? 4 : role.dire == 7 ? 3 : 2;
  84.   role._xscale = -100;
  85. } else {
  86.   role._xscale = 100;
  87. }
  88. role.gotoAndPlay("run_"+role.dire);
  89. role.sta;
  90. role.onEnterFrame = function() {
  91.   if (this.x != this._x) {
  92.    this._x += Math.abs(this.x-this._x)>Math.abs(this.speed*Math.cos(this.angle)) ? this.speed*Math.cos(this.angle) : this.x-this._x;
  93.   }
  94.   if (this.y != this._y) {
  95.    this._y += Math.abs(this.y-this._y)>Math.abs(this.speed*Math.sin(this.angle)) ? this.speed*Math.sin(this.angle) : this.y-this._y;
  96.   }
  97.   if (this.x == this._x && this.y == this._y) {
  98.    delete this.onEnterFrame;
  99.    this.gotoAndStop("stand_"+this.dire);
  100.   }
  101. };
  102. }
复制代码
以下是做好的所有文件,包括FLASH源文件和VB源文件。

game.rar (183.74 KB)


因为后台是用VS2003写的,所以在没有装VS的电脑上好象运行不了服务器。这个教程写了好几天,终于完成了。原来还想把聊天功能,换头发功能都做上去的,懒了。都是上班时候偷着做的。改天有时间想做个完整的游戏出来玩玩:D:lol

:'( 没人顶,自己支持一下。谁知道哪有支持ASP.net和Socket的空间呀?我的空间上放FLASH网游不行:Q ,时断时续的。
http://www.ibaiy.com/rpg.aspx




我在教程里做的服务器是一个软件,要在服务器安装才可以,但后来我把server.dll文件做成.net页面下的一个插件,在aspx的页面就可以启动这个服务了。我放在我服务器上的地址就是http://www.ibaiy.com/rpg.aspx 只是我不明白为什么有时候服务器可以运行,就可以完美支持这个网游,但有时候又不行,连FLASH都显示不出来。
我把文件修改了一下,把聊天和换头发都做上去了。还把页面做成全屏的。试着点点吧,兴许运气好就可以看到^_^


















































本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
利用Flash的AS3.0代码制作3D旋转动画效果
AS3.0百条实用小知识
FLASH中用纯脚本制作雪花效果
用flash制作雪花飘飘的动画
进阶教程—as打造实例无限循环旋转的超酷效果
自由风实用编程——旋转相册
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服