名字不是自己定义的,但人生却可以
——茂叔
为了实现让用户选择角色的姓名和性别,我们需要这样一个界面:
服务器端
要实现这个功能,我们需要在服务器端还应该添加一条命令CREATECHARACTER
。客户端把选择的名字和性别连同这个命令一起发送给服务端后,服务端完成修改,然后把最新的用户Json值返回给客户端。
添加命令很简单,在服务器端的Types.cs
里修改我们的命令枚举就可以了。
public enum GameCommand : byte
{
ERROR = 0,
CONNECTED = 1,
LOGIN,
MAKENAMES,
CREATECHARACTER,//添加在这里就可以了,不喜欢这个位置么?好吧,顺序不重要的,随便添在哪儿都一样。
MOVE,
ATTACK,
SEARCH,
TAKE,
QUIT
}
然后再去GameServer.cs
的ParseClientCommand
方法里面添加解析这条命令的处理代码:
……
case GameCommand.MAKENAMES:
{
uint playerID = ((GameConnection)connection).PlayerID;
JArray retjson = JArray.FromObject(gGame.MakeName(playerID));
((GameConnection)connection).SendMessage(cmd, retjson.ToString());
}
break;
case GameCommand.CREATECHARACTER:
{
uint playerID = ((GameConnection)connection).PlayerID;
JObject datajson = JObject.Parse(data);
int nameidx = int.Parse(datajson["nameidx"].ToString());
byte sexidx = byte.Parse(datajson["sexidx"].ToString());
((GameConnection)connection).SendMessage(cmd, gGame.SetPlayerSexAndName(playerID,nameidx,sexidx));
}
break;
case GameCommand.MOVE:
……
最后,在Game.cs
里面去实现设置姓名和性别的方法:
public string SetPlayerSexAndName(uint PlayerID,int nameidx,int sexidx)
{
GamePlayer player = GetPlayerByPlayerId(PlayerID);
if (player.Name == "@")//已经设置过的就不准再设置了,一个名字跟随你一生。
{
player.Name = player.NameList[nameidx];
player.Gender = (byte)sexidx;
}
return player.ToJson().ToString();
}
所以,整个过程就是:
是不是很简单?所有的命令都是用这样的模式去实现的。定义归定义,解析归解析,实现归实现。以后修改维护都很方便。
服务器端的活就完成了~
客户端
然后我们再来看客户端。客户端除了界面背景,按钮外,还有一些文字,为此,我们定义一个Label
类来处理(别问为什么,这又不是我想出来的……)
在UIOBJECT.js
里面定义新的界面元素(好吧,如果你习惯叫控件也可以).
……
exports.UILabel = UILabel
function UILabel(father, x = 0, y = 0, w = 100, h = 25) {
baseUIObj.call(this, father, x, y, w, h)
this.text = "UILabel"
this.name = "Label"
this.color = "transparent"
this.isTouchable = false
this.borderWidth=0
}
UILabel.prototype = new baseUIObj()
UILabel.prototype.constructor = UILabel
UILabel.prototype.redraw = function (needrender = true, caller = this) {
if (caller.isRedrawing) return
caller.isRedrawing = true
if (caller.isHidden) {
if (caller.father)
caller.father.redraw(caller.father)
} else {
baseUIObj.prototype.redraw(caller)
if (caller.text && caller.text.length > 0)
drawText(caller.gCtx, caller.text, caller.width / 2 - caller.text.length * 7, (caller.height - 12) / 2)
caller.children.forEach(function (child, index, array) {
if (!child.isHidden) {
child.redraw(false)
caller.gCtx.drawImage(child.canvas, child.x, child.y, child.width, child.height)
}
})
}
if (needrender)
GameWindow.redraw()
caller.isRedrawing = false
}
……
考虑到要选择,所以我们的按钮应该添加select()
和unselect()
方法……
……
UIButton.prototype.select = function (caller = this) {
caller.color = "#555"
caller.borderWidth = 2
caller.redraw()
}
UIButton.prototype.unselect = function (caller = this) {
caller.color = "#333"
caller.borderWidth = 1
caller.redraw()
}
……
我偷偷地把UIButton
的默认borderWidth
属性改成1了,2代表当前选中。
我们添加了新的命令,所以,客户端这边要处理这个命令。
在net.js
的parseMessage(msg)
方法里面去添加对命令回传信息的处理:
……
switch (msg.command) //其他命令的处理结果
{
case _g.COMMAND.CREATECHARACTER:
_g.Player = JSON.parse(msg.data)
console.log(_g.Player)
if (_g.Player.Name === "@") {
let nextUI = require('/UI/makename.js')
nextUI.initialize()
} else {
let nextUI = require('/UI/main.js')
nextUI.initialize()
}
break
case _g.COMMAND.MAKENAMES:
_g.Player.NameList = JSON.parse(msg.data)
let nextUI = require('/UI/makename.js')
nextUI.UpdateName()
break
case _g.COMMAND.LOGIN:
_g.Player = JSON.parse(msg.data)
……
考虑到有了新的界面,将来还会有更多的界面,所以,我们把界面处理程序提取出来,单独存放在\UI
目录下,所以,建个\UI
目录,下面建立两个文件main.js
、makename.js
,用来专门处理角色设置和显现游戏主界面:
main.js
exports.initialize = () => {
if (GameGlobal.GameMainUI === undefined) {
GameGlobal.GameMainUI = new UIObj.UIGame()
let image = wx.createImage();
image.src = "images/UI.png"
image.onload = () => {
GameMainUI.background = image
var btn = new UIObj.UIButton(GameMainUI)
btn.x = 44
btn.y = 150
btn.text = "退出游戏"
btn.onClick = () => {
wx.closeSocket()
}
GameWindow = GameMainUI
GameWindow.show()
}
} else {
GameWindow = GameMainUI
GameWindow.show()
}
}
makename.js
var sexSelectItem
var btnSex1
var btnSex2
var nameSelectItem
var btnName0
var btnName1
var btnName2
var btnName3
var btnSubmit
var btnRename
exports.initialize = () => {
if (GameGlobal.GameMakenameUI === undefined) {
GameGlobal.GameMakenameUI = new UIObj.UIGame()
let image = wx.createImage();
image.src = "images/UI.png"
image.onload = () => {
GameMakenameUI.background = image
createMakenameUI()
}
} else {
showMakenameUI()
}
}
function createMakenameUI() {
var label1 = new UIObj.UILabel(GameMakenameUI, 44, 8)
label1.text = "设定角色"
var label2 = new UIObj.UILabel(GameMakenameUI, 8, 50, 60)
label2.text = "性别:"
var label3 = new UIObj.UILabel(GameMakenameUI, 8, 80, 60)
label3.text = "姓名:"
btnSex1 = new UIObj.UIButton(GameMakenameUI, 60, 50, 30)
btnSex1.text = "男"
btnSex1.name = 1
btnSex1.select()
btnSex1.onClick = () => {
if (sexSelectItem) sexSelectItem.unselect()
btnSex1.select()
sexSelectItem = btnSex1
}
sexSelectItem = btnSex1
btnSex2 = new UIObj.UIButton(GameMakenameUI, 110, 50, 30)
btnSex2.text = "女"
btnSex2.name = 0
btnSex2.onClick = () => {
if (sexSelectItem) sexSelectItem.unselect()
btnSex2.select()
sexSelectItem = btnSex2
}
btnName0 = new UIObj.UIButton(GameMakenameUI, 60, 90, 100)
btnName0.text = _g.Player.NameList[0]
btnName0.name = 0
btnName0.select()
btnName0.onClick = () => {
if (nameSelectItem) nameSelectItem.unselect()
btnName0.select()
nameSelectItem = btnName0
}
nameSelectItem = btnName0
btnName1 = new UIObj.UIButton(GameMakenameUI, 60, 120, 100)
btnName1.text = _g.Player.NameList[1]
btnName1.name = 1
btnName1.onClick = () => {
if (nameSelectItem) nameSelectItem.unselect()
btnName1.select()
nameSelectItem = btnName1
}
btnName2 = new UIObj.UIButton(GameMakenameUI, 60, 150, 100)
btnName2.text = _g.Player.NameList[2]
btnName2.name = 2
btnName2.onClick = () => {
if (nameSelectItem) nameSelectItem.unselect()
btnName2.select()
nameSelectItem = btnName2
}
btnName3 = new UIObj.UIButton(GameMakenameUI, 60, 180, 100)
btnName3.text = _g.Player.NameList[3]
btnName3.name = 3
btnName3.onClick = () => {
if (nameSelectItem) nameSelectItem.unselect()
btnName3.select()
nameSelectItem = btnName3
}
btnRename = new UIObj.UIButton(GameMakenameUI, 44, 235)
btnRename.text = "换一批名字"
btnRename.onClick = () => {
var data = {
command: _g.COMMAND.MAKENAMES,
data: _g.Player.PlayerID
}
wx.sendSocketMessage({
data: JSON.stringify(data)
})
}
btnSubmit = new UIObj.UIButton(GameMakenameUI, 44, 265)
btnSubmit.text = "确定"
btnSubmit.onClick = () => {
btnSubmit.hide()
btnRename.hide()
var data = {
command: _g.COMMAND.CREATECHARACTER,
data: {
nameidx: nameSelectItem.name,
sexidx: sexSelectItem.name
}
}
wx.sendSocketMessage({
data: JSON.stringify(data)
})
}
showMakenameUI()
}
exports.UpdateName = () => {
btnName0.text = _g.Player.NameList[0]
btnName1.text = _g.Player.NameList[1]
btnName2.text = _g.Player.NameList[2]
btnName3.text = _g.Player.NameList[3]
btnSubmit.show()
btnRename.show()
GameWindow.show()
}
function showMakenameUI() {
btnName0.onClick()
btnSex1.onClick()
btnSubmit.show()
btnRename.show()
GameWindow = GameMakenameUI
GameWindow.show()
}
这样一来,我们在net.js
里面需要调用这两个界面的时候,就应该这样写:
……
case _g.COMMAND.LOGIN:
_g.Player = JSON.parse(msg.data)
wx.getUserInfo({
success(res) {
_g.Player.nickName = res.userInfo.nickName
_g.Player.avatarUrl = res.userInfo.avatarUrl
console.log(_g.Player)
if (_g.Player.Name === "@") {
let nextUI = require('/UI/makename.js')
nextUI.initialize()
} else {
let nextUI = require('/UI/main.js')
nextUI.initialize()
}
}
})
break
……
所有的主界面我都设置为全局变量,方便在任何地方调用。
客户端和服务器端都修改好了……
是的,就这样就修改好了……方便得不要不要的。
不信你自己调试一下看看,是不是回传的新用户资料已经有了性别和名字了:
点击退出后再进来,就直接进入主界面了。服务器端也同时显示了每次命令的情况:
通过修改姓名和性别的功能实现,我们对代码不断的调整优化,对于后续的开发奠定了良好的基础。下一步,我们需要将玩家的角色加入到小猫小狗(不认识?你没从第一篇开始看么?)的世界,然后把世界的资料回传给客户端,从而实现玩家角色对游戏世界的第一次感知……
截止这一篇的全部代码,请大家去我的GitHub下载:
>>第十四篇代码连接<<