FLASH网游通过XMLSocket与VB后台通信教程
转自闪吧论坛 陈策(作者)
前段时间用Flash做了个网游的Demo,通讯用的是Socket。曾承诺写个教程,现在有空就把它写写吧。 先从FLASH说起。我要达到的效果是点击地面,人物就走到点击的地点。思路:一个鼠标监听器监听鼠标的点击事件,把X座标和Y座标传到角色,做为角色的目的地。角色每一帧都向这个目的地移动一点点。 role_mc为场景里的一个MovieClip
- role_mc.x = role_mc._x;
- role_mc.y = role_mc._y;
- var mouseListener:Object = new Object();
- mouseListener.onMouseDown = function() {
- moveRole(role_mc, _xmouse, _ymouse);
- };
- Mouse.addListener(mouseListener);
- function moveRole(role:MovieClip, x:Number, y:Number) {
- role.x = x;
- role.y = y;
- role.onEnterFrame = function() {
- if (this.x != this._x) {
- this._x += this.x-this._x>0 ? 1 : -1;
- }
- if (this.y != this._y) {
- this._y += this.y-this._y>0 ? 1 : -1;
- }
- if (this.x == this._x && this.y == this._y) {
- delete this.onEnterFrame;
- }
- };
- }
复制代码 试一下效果,发现角色会斜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改写成:- role_mc.x = role_mc._x;
- role_mc.y = role_mc._y;
- role_mc.speed = 5;
- role_mc.angle = 0;
- var mouseListener:Object = new Object();
- mouseListener.onMouseDown = function() {
- moveRole(role_mc, _xmouse, _ymouse);
- };
- Mouse.addListener(mouseListener);
- function moveRole(role:MovieClip, x:Number, y:Number) {
- role.x = x;
- role.y = y;
- role.angle = Math.atan2(role.y-role._y, role.x-role._x);
- role.onEnterFrame = function() {
- if (this.x != this._x) {
- 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方向同理
- }
- if (this.y != this._y) {
- 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;
- }
- if (this.x == this._x && this.y == this._y) {
- delete this.onEnterFrame;
- }
- };
- }
复制代码 移动看起来应该没什么大问题了。现在来做人物。把自己画的人物,或者是从游戏里抓图弄出来的人物处理好,我有两张从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也修改了一下就达到行走效果了。
- role_mc.x = role_mc._x;
- role_mc.y = role_mc._y;
- role_mc.speed = 5;
- role_mc.angle = 0;
- var mouseListener:Object = new Object();
- mouseListener.onMouseDown = function() {
- moveRole(role_mc, _xmouse, _ymouse);
- };
- Mouse.addListener(mouseListener);
- function moveRole(role:MovieClip, x:Number, y:Number) {
- role.x = x;
- role.y = y;
- role.angle = Math.atan2(role.y-role._y, role.x-role._x);
- role.dire = 1+Math.round((role.angle+Math.PI)/(Math.PI/4)); //把角色面向的角度的值从-Math.PI到Math.PI的范围变为1到8的自然数,分别代码八个方向
- role.dire = role.dire>6 ? role.dire-6 : role.dire+2; //把八个方向处理一下,和图上代表的方向符合
- if (role.dire>5) {
- //如果方向为789中的一个,就水平翻转MC
- role.dire = role.dire == 6 ? 4 : role.dire == 7 ? 3 : 2; //方向6对应方向4,7对应3,8对应2
- role._xscale = -100;
- } else {
- role._xscale = 100;
- }
- role.gotoAndPlay("run_"+role.dire);
- role.onEnterFrame = function() {
- if (this.x != this._x) {
- 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;
- }
- if (this.y != this._y) {
- 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;
- }
- if (this.x == this._x && this.y == this._y) {
- delete this.onEnterFrame;
- this.gotoAndStop("stand_"+this.dire);
- }
- };
- }
复制代码 大体样子已经出来了。现在我们来想想,其他的玩家要怎么办?当收到服务器有新玩家登陆这里的时候,FLASH要添加一个新的角色在画面上。我们可以做一个创造角色的函数,收到有新人登陆时就添加一个。而自己登陆的时候也可以用这个函数来创建自己。其他玩家移动,也是从服务器收到是谁要移动到哪的信息,FLASH只要调用moveRole函数就可以了。现在先做一个创建角色的函数。role_mc不需要再放在场景里,在库里给他一个链接名role,就可以方便用attachMovie命令调用了。
- role_mc.x = role_mc._x;
- role_mc.y = role_mc._y;
- role_mc.speed = 5;
- role_mc.angle = 0;
- var mouseListener:Object = new Object();
- mouseListener.onMouseDown = function() {
- moveRole(role_mc, _xmouse, _ymouse);
- };
- Mouse.addListener(mouseListener);
- function moveRole(role:MovieClip, x:Number, y:Number) {
- role.x = x;
- role.y = y;
- role.angle = Math.atan2(role.y-role._y, role.x-role._x);
- role.dire = 1+Math.round((role.angle+Math.PI)/(Math.PI/4)); //把角色面向的角度的值从-Math.PI到Math.PI的范围变为1到8的自然数,分别代码八个方向
- role.dire = role.dire>6 ? role.dire-6 : role.dire+2; //把八个方向处理一下,和图上代表的方向符合
- if (role.dire>5) {
- //如果方向为789中的一个,就水平翻转MC
- role.dire = role.dire == 6 ? 4 : role.dire == 7 ? 3 : 2; //方向6对应方向4,7对应3,8对应2
- role._xscale = -100;
- } else {
- role._xscale = 100;
- }
- role.gotoAndPlay("run_"+role.dire);
- role.onEnterFrame = function() {
- if (this.x != this._x) {
- 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;
- }
- if (this.y != this._y) {
- 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;
- }
- if (this.x == this._x && this.y == this._y) {
- delete this.onEnterFrame;
- this.gotoAndStop("stand_"+this.dire);
- }
- };
- }
- 大体样子已经出来了。现在我们来想想,其他的玩家要怎么办?当收到服务器有新玩家登陆这里的时候,FLASH要添加一个新的角色在画面上。我们可以做一个创造角色的函数,收到有新人登陆时就添加一个。而自己登陆的时候也可以用这个函数来创建自己。其他玩家移动,也是从服务器收到是谁要移动到哪的信息,FLASH只要调用moveRole函数就可以了。现在先做一个创建角色的函数。role_mc不需要再放在场景里,在库里给他一个链接名role,就可以方便用attachMovie命令调用了。
- //创建鼠标监听器
- var mouseListener:Object = new Object();
- mouseListener.onMouseDown = function() {
- for (var i = 0; i<allRoles.length; i++) {
- if (allRoles[i].ctrl) {
- moveRole(allRoles[i], _xmouse, _ymouse);
- break;
- }
- }
- };
- Mouse.addListener(mouseListener);
- //创建角色
- var allRoles:Array = new Array();
- allRoles[allRoles.length] = createRole(Math.random(), true, 5, Stage.width/2, Stage.height/2);
- function createRole() {
- var roleObj:MovieClip = this.attachMovie("role", "role_mc", this.getNextHighestDepth());
- roleObj.id = arguments[0]; //区别每一个角色的ID,可以从数据库中得到值。在这个教程里就直接用一个随机数代替
- roleObj.ctrl = arguments[1]; //标识该角色是否为由玩家控制的角色
- roleObj.speed = arguments[2];
- roleObj._x = arguments[3];
- roleObj._y = arguments[4];
- roleObj.x = roleObj._x;
- roleObj.y = roleObj._y;
- return roleObj;
- }
- //角色移动
- function moveRole(role:MovieClip, x:Number, y:Number) {
- role.x = x;
- role.y = y;
- role.angle = Math.atan2(role.y-role._y, role.x-role._x);
- role.dire = 1+Math.round((role.angle+Math.PI)/(Math.PI/4));
- role.dire = role.dire>6 ? role.dire-6 : role.dire+2;
- if (role.dire>5) {
- role.dire = role.dire == 6 ? 4 : role.dire == 7 ? 3 : 2;
- role._xscale = -100;
- } else {
- role._xscale = 100;
- }
- role.gotoAndPlay("run_"+role.dire);
- role.onEnterFrame = function() {
- if (this.x != this._x) {
- 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;
- }
- if (this.y != this._y) {
- 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;
- }
- if (this.x == this._x && this.y == this._y) {
- delete this.onEnterFrame;
- this.gotoAndStop("stand_"+this.dire);
- }
- };
- }
复制代码 [ 本帖最后由 陈策 于 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的代码。我是从微软件的网站上的例子上修改来的,也没什么可说的。
- Imports System.Net
- Imports System.Net.Sockets
- Namespace ibaiy
- Public Class Server
- Private lisenSocket As Socket
- Private allRoles As New Hashtable
- Private rolesPosition As New Hashtable
- '在这个例子中我不打算用数据库了,所以建一个hashtable来存在线用户的资料。如果要存入数据库,只需要加上登陆后验证用户名密码,读数据库资料,再存到这个hashtable里。用户做了操作时再把hashtable里的数据处理后再写入数据库就可以了。这里的操作不难,但比较麻烦,所以我偷下懒
- '启动服务的主函数
- Public Sub startServer(ByVal port As Integer)
- lisenSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
- Dim ipen As IPHostEntry = Dns.Resolve(Dns.GetHostName)
- Dim endpoint = New IPEndPoint(ipen.AddressList(0).Any, port)
- lisenSocket.Bind(endpoint)
- lisenSocket.Listen(1000)
- lisenSocket.BeginAccept(AddressOf Me.Listen_Callback, lisenSocket)
- End Sub
- Public Sub Listen_Callback(ByVal result As IAsyncResult)
- Dim s As Socket = CType(result.AsyncState, Socket)
- Dim so2 As New StateObject
- so2.workSocket = s.EndAccept(result)
- so2.workSocket.BeginReceive(so2.buffer, 0, so2.buffer.Length, 0, AddressOf Me.Read_Callback, so2)
- s.BeginAccept(AddressOf Me.Listen_Callback, s)
- End Sub
- Public Sub Read_Callback(ByVal result As IAsyncResult)
- Dim so As StateObject = CType(result.AsyncState, StateObject)
- so.len = so.workSocket.EndReceive(result)
- opMsg(so)
- so.buffer.Clear(so.buffer, 0, so.buffer.Length)
- Try
- so.workSocket.BeginReceive(so.buffer, 0, so.buffer.Length, SocketFlags.None, AddressOf Me.Read_Callback, so)
- Catch
- End Try
- End Sub
- '这个函数就是处理服务器收到客户端消息的处理函数,一会详细说明
- Public Sub opMsg(ByVal so As StateObject)
- End Sub
- End Class
- End Namespace
复制代码 在server项目里像添加server.vb一样再添加一个StateObject.vb。这是为每个联接的SOCKET一定的buffer,索性做了一个新的类。写以下代码:
- Imports System.Net.Sockets
- Namespace ibaiy
- Public Class StateObject
- Public buffer(1024) As Byte
- Public workSocket As Socket
- Public len As Integer
- End Class
- 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函数如下:
- '处理收到的数据
- Public Sub opMsg(ByVal so As StateObject)
- Dim username As String
- Dim sendmsg As String
- Dim keys As IDictionaryEnumerator
- '如果发送消息长度为0,断开客户端
- If so.len < 1 Then
- keys = Me.allRoles.Values().GetEnumerator
- While keys.MoveNext
- If keys.Current.Equals(so.workSocket) Then
- username = CType(keys.Key, String)
- End If
- End While
- so.workSocket.Close()
- sendmsg = "03u=" + username + Chr(0)
- keys.Reset()
- While keys.MoveNext
- If Not keys.Current.Equals(so.workSocket) Then
- Me.send(keys.Key, sendmsg)
- End If
- End While
- Me.allRoles.Remove(username)
- Me.rolesPosition.Remove(username)
- Exit Sub
- End If
- Dim msg As String = System.Text.Encoding.UTF8.GetString(so.buffer, 0, so.len - 1)
- Dim msgtype As String = Left(msg, 2)
- Select Case msgtype
- Case "01" '登陆
- Dim newMsg As String = "00"
- Dim isIn As Boolean = False
- username = Right(msg, msg.Length - 4)
- keys = Me.allRoles.Keys().GetEnumerator
- While keys.MoveNext
- If keys.Key <> username Then
- If newMsg <> "00" Then
- newMsg += "&"
- End If
- newMsg += "u=" + keys.Key + Me.rolesPosition.Item(keys.Key)
- Else
- isIn = True
- End If
- End While
- newMsg += Chr(0) '考虑到FLASH里接收SOCKET是用XMLSocket,每个 XML 消息都是一个完整的 XML 文档,以一个零 (0) 字节结束。所以以chr(0)结束。
- If Not (isIn) Then
- Me.allRoles.Add(username, so.workSocket)
- Me.rolesPosition.Add(username, "&x=275&y=200") '这里我给角色初位置是(275,200),正好是在FLASH场景的中心。
- sendmsg = msgtype + "u=" + username + "&x=275&y=200" + Chr(0)
- keys = Me.allRoles.Keys().GetEnumerator
- While keys.MoveNext
- If keys.Key = username Then
- Me.send(keys.Current, newMsg)
- Else
- Me.send(keys.Current, sendmsg)
- End If
- End While
- End If
- Case "02" '移动
- username = Right(msg.Split("&")(0), msg.Split("&")(0).Length - 4)
- If CType(Me.allRoles.Item(username), Socket).Equals(so.workSocket) Then
- Dim xy As String = Right(msg, msg.Length - msg.Split("&")(0).Length)
- Me.rolesPosition.Item(username) = xy
- keys = Me.allRoles.Keys().GetEnumerator
- While keys.MoveNext
- If keys.Key <> username Then
- Me.send(keys.Current, msg + Chr(0))
- End If
- End While
- End If
- Case "03" '下线
- username = Right(msg, msg.Length - 4)
- If CType(Me.allRoles.Item(username), Socket).Equals(so.workSocket) Then
- keys = Me.allRoles.Values().GetEnumerator
- While keys.MoveNext
- If Not keys.Current.Equals(so.workSocket) Then
- Me.send(keys.Key, msg + Chr(0))
- End If
- End While
- Me.allRoles.Remove(username)
- Me.rolesPosition.Remove(username)
- so.workSocket.Close()
- End If
- Case "04" '聊天
- username = Right(msg.Split("&")(0), msg.Split("&")(0).Length - 4)
- If CType(Me.allRoles.Item(username), Socket).Equals(so.workSocket) Then
- keys = Me.allRoles.Keys().GetEnumerator
- While keys.MoveNext
- Me.send(keys.Current, msg + Chr(0))
- End While
- End If
- End Select
- End Sub
复制代码 要注意的是,发送的消息要以chr(0)结尾,这样FLASH才知道这是消息的尾,否则FLASH会以为还没完,还在等后边不存在的数据传过来。因为我懒,所以不打算在这个教程里做与数据库相关联的例子,如果要加的话,就在这个函数里的case里加就可以了。正确的做法应该是把每个case里的代码整理成一个个的功能块,方便以后调用。我懒-_- 还要写一个从服务器发消息给客户端的函数:
- '向一个用户主动发信息
- Public Sub send(ByVal user As Object, ByVal msg As String)
- Dim sends As Socket
- sends = CType(allRoles.Item(user), Socket)
- Dim buffer() As Byte
- buffer = System.Text.Encoding.UTF8.GetBytes(msg)
- sends.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, AddressOf Me.Send_Callback, sends)
- End Sub
- Public Sub Send_Callback(ByVal result As IAsyncResult)
- CType(result.AsyncState, Socket).EndSend(result)
- 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的面板上添加一个按钮,加上以下程序:
- Private isStarted As Boolean
- Private rpgServer As server.ibaiy.Server
- Private Sub ServerForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
- Me.isStarted = False
- End Sub
- Private Sub Button_start_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_start.Click
- If Not Me.isStarted Then
- Me.rpgServer = New server.ibaiy.Server
- Me.rpgServer.startServer(9999)
- Me.isStarted = True
- End If
- 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的代码:
- //数据链接
- var conects:String = "127.0.0.1";
- var socket:XMLSocket = new XMLSocket();
- socket.connect(conects, 9999);
- this.socket.onData = function(str:String) {
- var type:String = str.substr(0, 2);
- var tmparr:Array = str.substr(2).split("&");
- //所有在线角色和位置
- if (type == "00") {
- if (tmparr.length>1) {
- for (var i:Number = 0; i<tmparr.length; i += 3) {
- tmpName = tmparr[i].split("=");
- tmpx = tmparr[(i+1)].split("=");
- tmpy = tmparr[(i+2)].split("=");
- allRoles[allRoles.length] = createRole(tmpName[1], false, 5, Number(tmpx[1]), Number(tmpy[1]));
- }
- }
- }
- //有新用户登陆
- if (type == "01") {
- tmpName = tmparr[0].split("=");
- allRoles[allRoles.length] = createRole(tmpName[1], false, 5, Stage.width/2, Stage.height/2);
- }
- //有用户移动
- if (type == "02") {
- tmpName = tmparr[0].split("=");
- tmpx = tmparr[1].split("=");
- tmpy = tmparr[2].split("=");
- for (var i = 0; i<allRoles.length; i++) {
- if (allRoles[i].id == tmpName[1]) {
- moveRole(allRoles[i], Number(tmpx[1]), Number(tmpy[1]));
- break;
- }
- }
- }
- //用户下线
- if (type == "03") {
- tmpName = tmparr[0].split("=");
- for (var i = 0; i<allRoles.length; i++) {
- if (allRoles[i].id == tmpName[1]) {
- trace(allRoles[i])
- removeMovieClip(allRoles[i]);
- allRoles[i].splice(i, 1);
- break;
- }
- }
- }
- };
复制代码 当然,原来的代码里还要加上一些东西,比如在创造角色的时候,要判断是否是自己控制的角色,是的话就要告诉服务器我登陆了。比如在鼠标点击的时候,也要告诉服务器我移动了。下边我把完整的AS代码再贴一遍。- //数据链接
- var conects:String = "127.0.0.1";
- var socket:XMLSocket = new XMLSocket();
- socket.connect(conects, 9999);
- this.socket.onData = function(str:String) {
- var type:String = str.substr(0, 2);
- var tmparr:Array = str.substr(2).split("&");
- if (type == "00") {
- if (tmparr.length>1) {
- for (var i:Number = 0; i<tmparr.length; i += 3) {
- tmpName = tmparr[i].split("=");
- tmpx = tmparr[(i+1)].split("=");
- tmpy = tmparr[(i+2)].split("=");
- allRoles[allRoles.length] = createRole(tmpName[1], false, 5, Number(tmpx[1]), Number(tmpy[1]));
- }
- }
- }
- if (type == "01") {
- tmpName = tmparr[0].split("=");
- allRoles[allRoles.length] = createRole(tmpName[1], false, 5, Stage.width/2, Stage.height/2);
- }
- if (type == "02") {
- tmpName = tmparr[0].split("=");
- tmpx = tmparr[1].split("=");
- tmpy = tmparr[2].split("=");
- for (var i = 0; i<allRoles.length; i++) {
- if (allRoles[i].id == tmpName[1]) {
- moveRole(allRoles[i], Number(tmpx[1]), Number(tmpy[1]));
- break;
- }
- }
- }
- if (type == "03") {
- tmpName = tmparr[0].split("=");
- for (var i = 0; i<allRoles.length; i++) {
- if (allRoles[i].id == tmpName[1]) {
- trace(allRoles[i]);
- removeMovieClip(allRoles[i]);
- allRoles[i].splice(i, 1);
- break;
- }
- }
- }
- };
- //创建鼠标监听器
- var mouseListener:Object = new Object();
- mouseListener.onMouseDown = function() {
- for (var i = 0; i<allRoles.length; i++) {
- if (allRoles[i].ctrl) {
- moveRole(allRoles[i], _xmouse, _ymouse);
- socket.send("02u="+allRoles[i].id+"&x="+_xmouse+"&y="+_ymouse);
- break;
- }
- }
- };
- Mouse.addListener(mouseListener);
- //创建角色
- var allRoles:Array = new Array();
- allRoles[allRoles.length] = createRole(Math.random(), true, 5, Stage.width/2, Stage.height/2);
- function createRole() {
- var roleObj:MovieClip = this.attachMovie("role", "role"+allRoles.length+"_mc", this.getNextHighestDepth());
- roleObj.id = arguments[0];
- roleObj.ctrl = arguments[1];
- roleObj.speed = arguments[2];
- roleObj._x = arguments[3];
- roleObj._y = arguments[4];
- roleObj.x = roleObj._x;
- roleObj.y = roleObj._y;
- //如果是创造了玩家自己,就要向告诉服务器“我登陆了”
- if (arguments[1]) {
- socket.send("01u="+arguments[0]);
- }
- return roleObj;
- }
- //角色移动
- function moveRole(role:MovieClip, x:Number, y:Number) {
- role.x = x;
- role.y = y;
- role.angle = Math.atan2(role.y-role._y, role.x-role._x);
- role.dire = 1+Math.round((role.angle+Math.PI)/(Math.PI/4));
- role.dire = role.dire>6 ? role.dire-6 : role.dire+2;
- if (role.dire>5) {
- role.dire = role.dire == 6 ? 4 : role.dire == 7 ? 3 : 2;
- role._xscale = -100;
- } else {
- role._xscale = 100;
- }
- role.gotoAndPlay("run_"+role.dire);
- role.sta;
- role.onEnterFrame = function() {
- if (this.x != this._x) {
- 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;
- }
- if (this.y != this._y) {
- 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;
- }
- if (this.x == this._x && this.y == this._y) {
- delete this.onEnterFrame;
- this.gotoAndStop("stand_"+this.dire);
- }
- };
- }
复制代码 以下是做好的所有文件,包括FLASH源文件和VB源文件。 |
因为后台是用VS2003写的,所以在没有装VS的电脑上好象运行不了服务器。这个教程写了好几天,终于完成了。原来还想把聊天功能,换头发功能都做上去的,懒了。都是上班时候偷着做的。改天有时间想做个完整的游戏出来玩玩:D:lol
我在教程里做的服务器是一个软件,要在服务器安装才可以,但后来我把server.dll文件做成.net页面下的一个插件,在aspx的页面就可以启动这个服务了。我放在我服务器上的地址就是http://www.ibaiy.com/rpg.aspx 只是我不明白为什么有时候服务器可以运行,就可以完美支持这个网游,但有时候又不行,连FLASH都显示不出来。我把文件修改了一下,把聊天和换头发都做上去了。还把页面做成全屏的。试着点点吧,兴许运气好就可以看到^_^
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报。