作为一个下棋游戏,其最基本的一点内容就是登陆。这个登陆看似简单,其实不然,因为登陆是一个游戏的入口,它完成下面几个功能:
这些功能是一个登陆页面要具备的功能,登陆页面如图7-2所示。
在这里设置一个服务器IP是为了方便调试程序,其实在真正的登陆页中应该不出现,代之出现的应该是密码、性别等其他内容,从图7-2中明显可以看出它有两个输入框和一个按钮。

图7-2
登陆MC中初始化部分的程序代码如下:
//这个server就是前面说的服务器IP地址,127.0.0.1是代表本地服务
server = "127.0.0.1";
//把输入的光标移到服务器IP的文本框中
Selection.setFocus( "server" );
function trim(strin)
{
//去字符串两边空格命令
var i,j;
for(i=0; i < strin.length; i++)
if(strin.charAt(i) != ' ')
break;
if(i == strin.length)
return "";
for(j=strin.length-1; j >= i; j--)
if(strin.charAt(j) != ' ')
break;
return strin.substring(i,j+1);
}
其实也没有什么,就是一个简单的初始化的部分,一个去除字符串头尾空格的函数。Flash已经发展到MX版本了,去空格的函数都没有,还要程序员自己写,真是怪事。其实Flash MX不但没有这个函数,也没有子串替代的函数(replace)。好了,言归正传,这个函数没有什么好讲的,看看登陆按钮的代码吧。
login.onPress = function () {
var port = 1120;
if (trim(nickname) == "" || nickname == null) {
status = "名字不能为空";
} else if (nickname.indexOf(",") != -1 || nickname.indexOf(":") != -1 || nickname.indexOf(" ") != -1) {
status = "姓名中不可以包含','、':'及空格字符";
} else {
_root.nickname = trim(nickname);
_root.chatSocket.connect(server, port);
status = "正在连接服务器 "+server+":"+port;
}
}
在这里,这个登陆用的按钮被命名为login,如图7-3所示。

图7-3
这里仅支持按钮,并没有支持键盘的回车操作。如果需要支持回车操作,则第一行的程序应做如下修改:
login.onPress = login_in;
Key.addListener(this);
this.onKeyDown = function() {
if (Key.isDown(Key.ENTER)) login_in();
}
function login_in() {
……
从这个代码来看,Flash MX如果要同时支持按钮与键盘甚至鼠标的话,操作就变得麻烦了,不像以前一个语句on (press, keyPress "<Enter>")便可。不过想想也应该,MX把各种事件响应拆开,这样对每个事件程序方便了,但是代码就增长了。这个按钮响应事件中有一个文本显示框status,还有一个非常重要的Socket实例名_root.chatSocket,这个实例是在主场景被创建的。
下面是主场景的程序:
//创建一个XML Socket连接
chatSocket = new XMLSocket();
//这个onConnect是用来定义当连接成功所调用的函数
chatSocket.onXML = onXML;
sys = "[公告] ";
chatSocket.onConnect = onConnect;
function onConnect (success) {
trace("connect = "+success);
if (success == false) {
this.close();
objLogin.status = " 在连接服务器 "+objLogin.server+" 时出错";
} else {
objLogin.status = " 您已成功的连到 "+objLogin.server;
//如果成功连接就发送一条连接命令
var xmlMsg = new XML();
var ack = xmlMsg.createElement("CMD");
//登陆命令
ack.attributes.VALUE = "LGIN";
//我的用户名
ack.attributes.NICK = objLogin.nickname;
//我的密码
ack.attributes.PASS = "nothing";
xmlMsg.appendChild(ack);
trace ("第一次连接的内容:"+xmlMsg);
//送出这个XML串
this.send(xmlMsg);
//命令发出后连接完成,进入通信阶段
}
}
调试窗口output输出内容如下:
connect = true
第一次连接的内容:<CMD PASS="nothing" NICK="dongua" VALUE="LGIN" />
很明显,这是成功连接的输出提示。至此,登陆部分完成。从前面所列的代码可以看出登陆过程就是先实例化一个Socket对象(new语句),然后发出一个联机请求,等待后台程序返回一个值,如果返回true则表示成功连接,返回false表示连接失败。
在上面的代码中
chatSocket.onConnect = onConnect;
function onConnect (success) {……
这两句代码也可以合起来写成一句代码:
chatSocket.onConnect = function (success) {……
现在让我们来看看后台的Java代码:
if(this.cmd_LOGIN.equals(cmd)) {
//如果是登陆请求就把用户的名字、密码存起来
String nickname = (String)root.attributes.get("NICK");
String password = (String)root.attributes.get("PASS");
if( nickname != null && user.manager.findNickname(nickname) == null) {
//ok!
user.nickname = nickname;
user.password = password;
user.status = this.usr_ST_ON;
user.level = this.usr_LVL_NORMAL;
user.manager.addUser(user);
//向登陆的人发出一个服务器已经做好准备接收数据的信息
user.notify(packMsg(this.m_ACK, "OK", ""));
//向所有其他已经登陆的人发出有人登陆的信息
user.manager.notifyAll(packMsg(this.m_USR, "ON", user.nickname));
//向登陆的人发出其他已与服务器连接的用户的名单信息
user.notify(packMsg(this.m_USR, user.manager.getUserlist(","), ""));
//向登陆的人发出其他已与服务器连接的用户坐在哪张桌子的信息
user.notify(packMsg(this.m_PLA, user.manager.getUserplace(","), ""));
}
else {
//出错,退出
user.notify(packMsg(this.m_ACK, "401", ""));
user.onKill();
}
}
在上面的代码中有一句比较重要的事件函数定义语句就是:
chatSocket.onXML = onXML;
这个其实就是当有XML数据传送过来时就会激发出onXML函数,onXML函数的代码如下:
function onXML(x) {
if (x.firstChild.nodeName == "ACK") {
if (x.firstChild.attributes.VALUE == "OK") {
//重新指定连接函数,而指向通信函数
this.onXML = _root.onXML_Receive;
} else {
this.close();
objLogin.status = "nickname already exists";
}
} else {
trace(x);
}
}
很明显在前面连接成功后就向后台送出一个用户名及其相关信息,如果后台收到这个信息而且已经准备好,就会回送一个<ACK VALUE="OK" />给Flash,然后onXML程序部分就会收到并处理这个信息。其实这个过程与前面的登陆联机一起算是一个握手的过程,或者说是连接后台的过程。其方式就像是说:我(用户)要登陆了,你(服务器)准备好了没有?服务器在准备好之后就说:行了,我准备好了,你可以发数据了。至此,通信建立过程完毕,在握手完毕之后,开始正常的通信,此时要将onXML的事件函数指向正常的通信函数_root.onXML_Receive。
Flash MX使用UTF8编码。在Flash MX里输入汉字的时候为GB码,生成SWF的时候就会将GB转换为UTF8,在浏览器播放的时候,播放器再将其转为GB。但是LOAD外部TXT变量或者XML通信的时候,如果内容是GB码,就会出现问题,显示为乱码。要解决这个问题只需在程序的最开始处加语句:System.useCodepage = true;便可。
游戏在登陆之后进入主控画面,如图7-4所示。

图7-4
从图7-4可以看出整个游戏的画面被分成三个区:左上角是游戏区,主要是摆放游戏台及与游戏相关的内容;下面是聊天区,主要是让连线的玩家聊天与交流;右边是在线用户列表区,显示出连到系统的玩家的名单。好了,下面就逐一介绍这三个区。