项目6-实现业务逻辑模块课件_第1页
项目6-实现业务逻辑模块课件_第2页
项目6-实现业务逻辑模块课件_第3页
项目6-实现业务逻辑模块课件_第4页
项目6-实现业务逻辑模块课件_第5页
已阅读5页,还剩95页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

腾讯云游戏应用开发腾讯云游戏应用开发实现登录功能01任务实现获取自身数据功能02任务实现注册功能03任务实现业务逻辑模块项目6实现匹配功能04任务实现准备功能05任务实现战场管理功能06任务实现登录功能01任务实现获取自身数据功能02任务实现注册功能学习目标

实现游戏的几个重要业务逻辑

掌握CS模式下协议的使用

掌握登录注册功能的基本实现方法学习目标实现游戏的几个重要业务逻辑1实现登录功能1.实现客户端请求登录方法当用户在登录界面中单击“登录”按钮后,后台尝试与服务器建立连接,连接成功后发送登录协议,协议格式为login;id;password;。修改LoginPanel.cs脚本中的OnLoginClick

方法,代码如下。/*登录按钮事件*/

public

void

OnLoginClick

()

{

if

(idInput.text

==

""

||

pwInput.text

==

"")

{

/*打开提示框*/

PanelMgr.instance.OpenPanel<TipPanel>

("用户名密码不能为空!");

return;

}

//如果服务器没有连接,连接服务器

if

(NetMgr.instance.status

!=

NetMgr.Status.Connected)

{

NetMto

=

new

ProtocolStr

();

/*连接*/

if

(!NetMgr.instance.Connect

())

PanelMgr.instance.OpenPanel<TipPanel>

("连接服务器失败!");

}

1实现登录功能1.实现客户端请求登录方法当用户在登录界面中单1实现登录功能1.实现客户端请求登录方法

//发送登录协议

ProtocolStr

protocol

=

new

ProtocolStr

();

protocol.AddString

("login");

protocol.AddString

(idInput.text);

protocol.AddString

(pwInput.text);

/*一次性监听*/

NetMgr.instance.Send

(protocol,

OnLoginBack);

}1实现登录功能1.实现客户端请求登录方法

//发送登1实现登录功能2.实现服务端登录协议处理方法在HandleConnMsg类中添加Msglogin方法,当服务端收到login协议时,分发给Mgslogin方法处理

public

void

Msglogin

(Conn

conn,

ProtocolBase

protoBase)

{

string

id,

pw;

ProtocolStr

protocol

=

(ProtocolStr)protoBase;

id

=

protocol.GetString

(1);

pw

=

protocol.GetString

(2);

/*构建返回协议*/

ProtocolStr

protocolRet

=

new

ProtocolStr

();

protocolRet.AddString

("login");

/*数据库校验*/

//如果用户名密码校验失败

if

(!DataMgr.instance.CheckPassWord

(id,

pw))

{

Console.WriteLine

("[Msglogin]登录失败:用户名和密码错误"

+

conn.GetAddress

());

protocolRet.AddInt

(-1);//返回失败结果

conn.Send

(protocolRet);

return;

}

1实现登录功能2.实现服务端登录协议处理方法在HandleC1实现登录功能2.实现服务端登录协议处理方法

if

(!ServNet.instance.KickOff

(id))

{

//如果踢下线失败

Console.WriteLine

("[Msglogin]登录失败:挤下线失败"

+

conn.player.id);

//返回失败结果

protocolRet.AddInt

(-1);

conn.Send

(protocolRet);

return;

}

PlayerData

playerData

=

DataMgr.instance.GetPlayerData

(id);

//获取玩家数据

if

(playerData

==

null)

{

Console.WriteLine

("[Msglogin]登录失败:获取账户信息失败"

+

conn.player.id);

protocolRet.AddInt

(-1);

//返回失败结果

conn.Send

(protocolRet);

return;

}

conn.player

=

new

Player

(id,

conn,

playerData);

//登入账户,加载数据

protocolRet.AddInt

(0);

//返回成功结果

conn.Send

(protocolRet);

}1实现登录功能2.实现服务端登录协议处理方法

i1实现登录功能3.实现客户端处理回发结果方法添加OnLoginBack方法

/*登录协议回执*/

public

void

OnLoginBack

(ProtocolBase

protocol)

{

/*构建协议*/

ProtocolStr

proto

=

(ProtocolStr)protocol;

/*校验登录结果*/

int

result

=

proto.GetInt

(1);

if

(result

==

0)

{

GameMgr.instance.id

=

idInput.text;

//保存账号ID

PanelMgr.instance.OpenPanel<TipPanel>

("登录成功!");

PanelMgr.instance.OpenPanel<LobbyPanel>

();

/*进入游戏大厅*/

PanelMgr.instance.ClosePanel

(this);

}

else

{

NetMgr.instance.Close

();

//断开连接

PanelMgr.instance.OpenPanel<TipPanel>

("登录失败,请检查用户名密码!");

}

}1实现登录功能3.实现客户端处理回发结果方法添加OnLogi1实现登录功能4.实现踢下线模块如果该角色在游戏中,则把它踢下线。并且发送Logout协议,向被踢下线的客户端发送通知。在ServNet中添加KickOff方法,代码如下。

/*如果某id已经在线就踢下线*/

public

bool

KickOff

(string

id)

{

for

(int

i

=

0;

i

<

conns.Length;

i++)

{

if

(conns

[i]

==

null)

continue;

if

(!conns

[i].isUse)

continue;

if

(conns

[i].player

==

null)

continue;

/*如果该玩家已经在线*/

if

(conns

[i].player.id

==

id)

{

lock

(conns[i].player)

{

Console.WriteLine

("检查到"+id+"已在线,踢下线");

/*通知客户端下线*/

ProtocolStr

protocolLogout

=

new

ProtocolStr

();

protocolLogout.AddString

("logout");

conns[i].Send

(protocolLogout);

return

conns

[i].player.Logout

();

}

}

}

return

true;

}1实现登录功能4.实现踢下线模块如果该角色在游戏中,则把它踢2实现获取自身数据功能1.实现客户端发送请求方法在LobbyPanel.cs脚本的OnShowing方法的最后添加相关代码,如下。……

/*请求加载自身数据*/

ProtocolStr

proto

=

new

ProtocolStr

();

proto.AddString

("getachieve");//发送协议,并注册接收方法

NetMgr.instance.Send

(proto,RecvGetAchieve);

}2实现获取自身数据功能1.实现客户端发送请求方法在Lobby2实现获取自身数据功能2.实现服务端处理协议的方法当服务端接收到协议时,分发给对应的方法,将玩家的胜负场次写入协议返回给玩家。在HandlePlayerMsg类中添加协议处理方法Msggetachieve方法,代码如下。/*获取玩家自身数据*/

/*返回协议"getachieve,win,lost,"*/

public

void

Msggetachieve

(Player

player,

ProtocolBase

protoBase)

{

ProtocolStr

protocolRet

=

new

ProtocolStr

();

protocolRet.AddString

("getachieve");

protocolRet.AddString

(player.id);

protocolRet.AddInt

(player.playerData.win);

protocolRet.AddInt

(player.playerData.fail);

player.conn.Send

(protocolRet);

return;

}2实现获取自身数据功能2.实现服务端处理协议的方法当服务端接2实现获取自身数据功能3.实现客户端处理回发结果客户端收到返回协议并更新到UI上,代码如下。

/*个人信息协议接收*/

public

void

RecvGetAchieve

(ProtocolBase

protocol)

{

/*解析协议*/

ProtocolStr

proto

=

(ProtocolStr)protocol;

IDtext.text

=

"玩家:";

IDtext.text

+=

proto.GetString

(1);

IDtext.text

+=

",胜场:";

IDtext.text

+=

proto.GetInt

(2);

IDtext.text

+=

",负场:";

IDtext.text

+=

proto.GetInt

(3);

}2实现获取自身数据功能3.实现客户端处理回发结果客户端收到返3实现注册功能1.实现客户端请求注册方法当用户在注册界面中单击“注册”按钮后,后台尝试与服务器建立连接,连接成功后发送注册协议,协议格式为register;id;password;。修改RegPanel.cs脚本中的OnRegClick方法,代码如下。

/*注册按钮事件*/

public

void

OnRegClick

()

{

/*本地校验*/

//用户名密码为空

if

(idInput.text

==

""

||

pwInput.text

==

"")

{

PanelMgr.instance.OpenPanel<TipPanel>

("用户名密码不能为空!");

return;

}

//两次密码不同

if

(pwInput.text

!=

repInput.text)

{

PanelMgr.instance.OpenPanel<TipPanel>

("两次输入的密码不同!");

return;

}

3实现注册功能1.实现客户端请求注册方法当用户在注册界面中3实现注册功能1.实现客户端请求注册方法

//连接服务器

if

(NetMgr.instance.status

!=

NetMgr.Status.Connected)

{

NetMto

=

new

ProtocolStr

();

if

(!NetMgr.instance.Connect

())

PanelMgr.instance.OpenPanel<TipPanel>

("连接服务器失败!");

}

//构建协议

ProtocolStr

protocol

=

new

ProtocolStr

();

protocol.AddString

("register");

protocol.AddString

(idInput.text);

protocol.AddString

(pwInput.text);

//发送

NetMgr.instance.Send

(protocol,

OnRegBack);

}3实现注册功能1.实现客户端请求注册方法

//连接3实现注册功能2.实现服务端注册协议处理方法当服务端收到register

协议时,分发给Msgregister

方法处理。该方法首先解析协议中的用户名和密码。调用GetXXX是获取协议数值的一种方法。然后调用DataMgr.instance.Register向user中表添加数据,如果添加失败,则通过protocol.AddInt(0)构造参数为0的返回协议。最后通过CreatePlayer创建角色,并返回协议给客户端,代码如下。/*注册协议*/

public

void

Msgregister

(Conn

conn,

ProtocolBase

protoBase)

{

/*解析协议*/

string

id,

pw;

ProtocolStr

protocol

=

(ProtocolStr)protoBase;

id

=

protocol.GetString

(1);

pw

=

protocol.GetString

(2);

Console.WriteLine

("[Msgregister]处理注册协议:"

+

conn.GetAddress

()

+

"

用户名:"

+

id

+

"

密码:"

+

pw);

/*注册*/

bool

result

=

DataMgr.instance.Register

(id,

pw);

3实现注册功能2.实现服务端注册协议处理方法当服务端收到r3实现注册功能2.实现服务端注册协议处理方法

//构建返回协议

ProtocolStr

protocolRet

=

new

ProtocolStr

();

protocolRet.AddString

("register");

if

(result)

{

Console.WriteLine

("[Msgregister]注册成功"

+

conn.GetAddress

());

protocolRet.AddInt

(0);

}

else

{

Console.WriteLine

("[Msgregister]注册失败"

+

conn.GetAddress

());

protocolRet.AddInt

(-1);

}

//返回协议给客户端

conn.Send

(protocolRet);

}3实现注册功能2.实现服务端注册协议处理方法

//构3实现注册功能3.实现客户端处理回发结果方法服务端处理协议后,会返回处理结果,格式为register;result;。result为0表示成功,-1表示失败。客户端收到返回协议再做出响应。注册成功则关闭注册界面。注册失败则提示注册失败。添加OnRegBack

方法,代码如下。

/*注册协议回执*/

public

void

OnRegBack

(ProtocolBase

protocol)

{

/*解析协议*/

ProtocolStr

proto

=

(ProtocolStr)protocol;

int

result

=

proto.GetInt

(1);

if

(result

==

0)

{

PanelMgr.instance.OpenPanel<TipPanel>

("注册成功!");

/*返回登录界面*/

PanelMgr.instance.ClosePanel

(this);

}

else

{

NetMgr.instance.Close

();

PanelMgr.instance.OpenPanel<TipPanel>

("注册失败,请更换用户名!");

}

}3实现注册功能3.实现客户端处理回发结果方法服务端处理协议4实现匹配功能1.实现客户端的匹配请求①单击“匹配”按钮,发送相关协议。在LobbyPanel.cs中添加新字段,代码如下。

/*匹配状态*/

enum

MatchState{

Matching,None

}

MatchState

state=MatchState.None;4实现匹配功能1.实现客户端的匹配请求①单击“匹配”按钮4实现匹配功能1.实现客户端的匹配请求修改LobbyPanel.cs中的OnMatchClick方法,代码如下。

//匹配按钮事件

public

void

OnMatchClick(){

if

(state

==

MatchState.None)

{

ProtocolStr

protocol

=

new

ProtocolStr

();

protocol.AddString

("matchin");

NetMgr.instance.Send

(protocol);

state

=

MatchState.Matching;

btnText.text

=

"匹配中…\n(点击取消)";

}

else

{

ProtocolStr

protocol

=

new

ProtocolStr

();

protocol.AddString

("matchout");

NetMgr.instance.Send

(protocol);

state

=

MatchState.None;

btnText.text

=

"匹配\n(点击开始)";

}

}4实现匹配功能1.实现客户端的匹配请求修改LobbyPan4实现匹配功能2.创建服务端匹配管理类MatchMgrMatchMgr类主要负责以下工作:①定义匹配队列。当匹配队列满足人数要求时,创建房间,并将这些玩家添加到房间的玩家列表里。②定义游戏开始要求的人数。当队列满足人数要求的时候,将队列最前面的几个人放到一个新建的房间类里。③控制队列的进入与离开。添加MatchMgr匹配管理类,代码如下。using

System;

/*匹配管理*/

using

System.Collections.Generic;

public

class

MatchMgr

{

//单例

public

static

MatchMgr

instance;

//匹配列表

public

List<Player>

list

=

new

List<Player>();

//开始游戏需要的人数

public

int

beginNum=4;4实现匹配功能2.创建服务端匹配管理类MatchMgrMa4实现匹配功能2.创建服务端匹配管理类MatchMgr

/*构造方法*/

public

MatchMgr

()

{

instance

=

this;

}

/*判断匹配队列中是否已经足够开局*/

public

void

CanBegin(){

if

(list.Count

>=

beginNum)

{

Console.WriteLine

("匹配成功,创建房间");

Room

room

=

new

Room

();

for(int

i=0;i<beginNum;i++){

room.AddPlayer

(list

[0]);

list.Remove

(list[0]);

}

/*通知所有匹配上的玩家进入房间*/

room.MatchOK();

}

}4实现匹配功能2.创建服务端匹配管理类MatchMgr

4实现匹配功能2.创建服务端匹配管理类MatchMgr

public

void

AddPlayer(Player

player){

lock

(list)

{

if

(list.Contains

(player))

return;

list.Add

(player);

player.tempData.status

=

PlayerTempData.Status.Matching;

Console.WriteLine

("[Msgmatchin]进入匹配队列"+player.id);

CanBegin

();

}

}

/*将玩家移出匹配队列*/

public

void

RemovePlayer(Player

player){

lock

(list)

{

if

(!list.Contains

(player))

return;

player.tempData.status

=

PlayerTempData.Status.None;

list.Remove

(player);

Console.WriteLine

("[Msgmatchout]离开匹配队列"+player.id);

}

}

}4实现匹配功能2.创建服务端匹配管理类MatchMgr

4实现匹配功能3.创建服务端房间类RoomRoom类主要负责以下工作:①当匹配队列满足人数要求时,创建房间,并将这些玩家添加到房间的玩家列表里。②创建房间时,向房间中所有玩家发送匹配成功协议。③分配队伍,以错开的方式,比如135是红队、246是蓝队。添加Room房间类,代码如下。using

System;

using

System.Collections.Generic;

using

System.Linq;

//房间

public

class

Room{

//状态

public

enum

Status

{

/*准备中*/

Prepare

=

1,

/*游戏中*/

Fight

=

2,

}4实现匹配功能3.创建服务端房间类RoomRoom类主要负4实现匹配功能3.创建服务端房间类Room

public

Status

status

=

Status.Prepare;

public

int

maxPlayers

=

2;

//玩家

/*已准备的玩家*/

int

readyNum

=

0;

/*玩家列表*/

public

Dictionary<string,Player>

playerlist

=

new

Dictionary<string,Player>

();

/*座位数组*/

public

Room

()

{

maxPlayers

=

MatchMgr.instance.beginNum;

}

public

bool

AddPlayer

(Player

player)

{

//添加玩家

lock

(playerlist)

{

if

(playerlist.Count

>=

maxPlayers)

return

false;

/*修改玩家临时数据*/

player.tempData.room

=

this;

player.tempData.team

=

SwitchTeam

();

player.tempData.status

=

PlayerTempData.Status.Room;

/*写入*/

playerlist.Add

(player.id,

player);

}

return

true;

}4实现匹配功能3.创建服务端房间类Room

public4实现匹配功能3.创建服务端房间类Room

/*分配队伍*/

/*返回一个队伍的ID*/

public

int

SwitchTeam

()

{

int

count1

=

0;

int

count2

=

0;

foreach

(Player

player

in

playerlist.Values)

{

if

(player.tempData.team

==

1)

count1++;

if

(player.tempData.team

==

2)

count2++;

}

if

(count1

<=

count2)

return

1;

else

return

2;

}

4实现匹配功能3.创建服务端房间类Room

/*分配队伍4实现匹配功能3.创建服务端房间类Room

//广播

public

void

Broadcast

(ProtocolBase

protocol)

{

lock

(playerlist)

{

foreach

(Player

player

in

playerlist.Values)

{

player.conn.Send

(protocol);

}

}

}

/*匹配成功*/

/*通知所有玩家进入房间,并广播房间中所有玩家的信息*/

public

void

MatchOK

()

{

ProtocolStr

protocol

=

new

ProtocolStr

();

protocol.AddString

("enterroom");

Broadcast

(protocol);

}

}4实现匹配功能3.创建服务端房间类Room

//广播

4实现匹配功能4.创建服务端协议处理方法添加HandleMatchMsg.cs文件用来处理匹配协议,它有两个协议处理方法Msgmatchin和Msgmatchout,代码如下。using

System;

using

System.Collections.Generic;

public

partial

class

HandlePlayerMsg

{

//进入匹配队列

public

void

Msgmatchin

(Player

player,

ProtocolBase

protoBase)

{

MatchMgr.instance.AddPlayer

(player);

}

//离开匹配队列

public

void

Msgmatchout

(Player

player,

ProtocolBase

protoBase)

{

MatchMgr.instance.RemovePlayer

(player);;

}

}4实现匹配功能4.创建服务端协议处理方法添加HandleM4实现匹配功能5.客户端响应匹配结果当匹配成功后,服务端会发送enterroom协议,客户端接收协议后进入到房间。在OnShowing方法的最后注册进入房间的协议,代码如下。……/*添加事件监听,匹配成功进入房间*/

NetMgr.instance.msgDist.AddListener("enterroom",

RecvEnterRoom);}添加回调方法,代码如下。

/*协议回发*/

public

void

RecvEnterRoom(ProtocolBase

protocol)

{

Debug.Log

("RecvEnterRoom");

PanelMgr.instance.OpenPanel<RoomPanel>

();

PanelMgr.instance.ClosePanel

(this);

}4实现匹配功能5.客户端响应匹配结果当匹配成功后,服务端会5实现准备功能1.客户端发送准备通知当玩家单击“确认”按钮(也就是游戏中常说的准备)后,向服务端发送choosedhero协议。修改确认按钮的点击事件,代码如下。//确认选择按钮事件

public

void

OnYesClick

()

{

/*通知服务器*/

ProtocolStr

protocol

=

new

ProtocolStr

();

protocol.AddString

("choosedhero");

protocol.AddString

("Archer");

NetMgr.instance.Send

(protocol);

/*点击一次准备按钮后,按钮就失效*/

yesBtn.onClick.RemoveAllListeners

();

}5实现准备功能1.客户端发送准备通知当玩家单击“确认”按钮5实现准备功能2.服务端处理准备结果在HandleMatchMsg中添加处理choosedhero协议的方法,代码如下。

//选择英雄

public

void

Msgchoosedhero(Player

player,ProtocolBase

protoBase){

/*解析协议*/

ProtocolStr

protocol

=

(ProtocolStr)protoBase;

string

heroName

=

protocol.GetString

(1);

/*检查是否可以开始*/

player.tempData.room.ChoosedHero

(player,heroName);

}5实现准备功能2.服务端处理准备结果在HandleMatc5实现准备功能2.服务端处理准备结果每当有一个玩家提交选择英雄协议时进行判断,是否可以开始战斗。在Room类中添加相关方法,代码如下。/*选择英雄*/

public

void

ChoosedHero

(Player

player,

string

heroName)

{

//修改玩家临时数据

player.tempData.heroName

=

heroName;

//当前房间中准备的玩家数量+1

readyNum++;

/*是否可以开始游戏*/

int

beginNum

=

playerlist.Count;

Console.WriteLine

(readyNum+"位玩家已选择英雄");

//如果准备的玩家>=所有玩家,则可以开始

if

(readyNum

>=

beginNum)

{

Console.WriteLine

("所有玩家选择完毕,开始战斗!");

StartFight

();

}

}5实现准备功能2.服务端处理准备结果每当有一个玩家提交选择5实现准备功能2.服务端处理准备结果当所有玩家都准备完毕时,向所有玩家发送游戏开始协议.在Room类中添加方法,代码如下。

/*开始游戏*/

public

void

StartFight

()

{

/*构建fight协议*/

ProtocolStr

protocol

=

new

ProtocolStr

();

protocol.AddString

("fight");

status

=

Status.Fight;

int

teamPos1

=

1;

int

teamPos2

=

1;

lock

(playerlist)

{

protocol.AddInt

(playerlist.Count);

/*将每一个玩家的信息逐一添加到协议中*/

foreach

(Player

p

in

playerlist.Values)

{

/*玩家ID*/

protocol.AddString

(p.id);5实现准备功能2.服务端处理准备结果当所有玩家都准备完毕时5实现准备功能2.服务端处理准备结果

/*选择的英雄*/

protocol.AddString

(p.tempData.heroName);

/*所在队伍*/

protocol.AddInt

(p.tempData.team);

/*队伍位置*/

if

(p.tempData.team

==

1)

protocol.AddInt

(teamPos1++);

else

protocol.AddInt

(teamPos2++);

/*修改所有玩家的临时数据*/

p.tempData.status

=

PlayerTempData.Status.Fight;

p.tempData.isAlive

=

true;

}

/*广播*/

Broadcast

(protocol);

}

}5实现准备功能2.服务端处理准备结果

/*选5实现准备功能3.客户端处理回发协议当服务端确定可以开始游戏时,会向房间中每一个玩家发送一个fight协议,客户端接收fight协议,开始处理战场。添加协议监听并在关闭面板时注销,代码如下。……

/*添加监听*/

NetMgr.instance.msgDist.AddListener

("fight",

RecvFight);

}在OnClosing方法中删除监听,代码如下。

public

override

void

OnClosing

()

{

NetMgr.instance.msgDist.DelListener

("fight",

RecvFight);

}5实现准备功能3.客户端处理回发协议当服务端确定可以开始游5实现准备功能3.客户端处理回发协议实现RecvFight方法,代码如下。/*处理fight协议*/

public

void

RecvFight

(ProtocolBase

protocol)

{

ProtocolStr

proto

=

(ProtocolStr)protocol;

/*开始战斗*/

PanelMgr.instance.OpenPanel<FightPanel>

();

PanelMgr.instance.ClosePanel

(this);

//初始化战场,稍后实现

//

BattleManager.instance.StartBattle

(proto);

}5实现准备功能3.客户端处理回发协议实现RecvFight6实现战场管理功能1.创建BattleManager战场管理类添加BattleManager.cs脚本用来处理战场布置,代码如下。using

System.Collections;

using

System.Collections.Generic;

using

UnityEngine;

public

class

BattleManager

:

MonoBehaviour

{

/*角色的预制体*/

public

GameObject

archerPre;

/*战场中的所有玩家*/

public

Dictionary<string,BattleArcher>

list

=

new

Dictionary<string,

BattleArcher>

();

/*单例*/

public

static

BattleManager

instance;

/*皮肤*/

public

Material

mat1,mat2;

void

Awake

()

{

instance

=

this;

}

}6实现战场管理功能1.创建BattleManager战场管6实现战场管理功能2.添加初始化战场的方法用StartBattle

方法解析fight协议,实例化协议中的每个玩家,代码如下。

/*开始战斗*/

/*处理一切战斗准备和预设*/

public

void

StartBattle

(ProtocolStr

proto)

{

/*解析协议*/

string

protoName

=

proto.GetString

(0);

int

count

=

proto.GetInt

(1);

//玩家总数

//清理场景

ClearBattle

();

//实例化每一个玩家

for

(int

i

=

0;

i

<

count;

i++)

{

string

id

=

proto.GetString

(4

*

i

+

2);

string

heroName

=

proto.GetString

(4

*

i

+

3);

int

team

=

proto.GetInt

(4

*

i

+

4);

/*出生点ID*/

int

swopID

=

proto.GetInt

(4

*

i

+

5);

//实例化角色

GenerateBattleHero

(id,

heroName,

team,

swopID);

}

}6实现战场管理功能2.添加初始化战场的方法用StartBa6实现战场管理功能3.添加清理战场方法每次开启新战斗之前需要清理战场,包括清空玩家列表,恢复主摄像机的跟随状态,销毁所有角色和辅助物体(如准心)。添加ClearBattle方法,代码如下。public

void

ClearBattle

()

{

//清除玩家列表

list.Clear

();

//恢复主摄像机父级

Camera.main.transform.SetParent

(transform);

/*销毁所有的角色*/

GameObject[]

heros

=

GameObject.FindGameObjectsWithTag

("Archer");

for

(int

i

=

0;

i

<

heros.Length;

i++)

Destroy

(heros

[i]);

/*销毁所有的辅助物体*/

foreach(GameObject

g

in

GameObject.FindGameObjectsWithTag

("Helper"))

GameObject.Destroy(g);

}6实现战场管理功能3.添加清理战场方法每次开启新战斗之前需6实现战场管理功能4.创建角色名称由于是多人对战,为了更好地识别队友和敌人,可以在角色的头上增加一个3Dtext模型,并且让模型始终面向主摄像机。在Archer中添加子物体3DText,重命名为ID,Text字体大小设置为0.3,Position设为(0,1.32,0)6实现战场管理功能4.创建角色名称由于是多人对战,为了更好6实现战场管理功能4.创建角色名称为了让名称一直面向玩家,需要给ID添加一个脚本FaceToCamera.cs,代码如下。using

System.Collections;

using

System.Collections.Generic;

using

UnityEngine;

public

class

FaceToCamera

:

MonoBehaviour

{

void

Update

()

{

transform.rotation

=

Camera.current.transform.rotation;

}

}6实现战场管理功能4.创建角色名称为了让名称一直面向玩家,6实现战场管理功能5.创建出生点游戏设定有两组队伍,每队两人。地图上需要预先设置好玩家的出生点,在场景中新建空游戏对象Spawn,如图6-6-2所示。具体位置玩家可以自己设置,注意出生点不可以放到地形的下面,不然角色出生的时候会掉出地图。6实现战场管理功能5.创建出生点游戏设定有两组队伍,每队两6实现战场管理功能6.实例化玩家GenerateBattleHero

主要实现以下几点:①实例化角色模型,并将模型放到对应出生点的位置。②为角色添加控制组件,为主角添加PlayerCtrl,为其他角色添加NetCtrl。③为主角设置相机跟随。④为其他角色设置刚体。⑤针对不同队伍,设置材质和ID的颜色。添加GenerateBattleHero方法,代码如下。

/*实例化战场角色*/

void

GenerateBattleHero

(string

id,

string

heroName,

int

team,

int

swopID)

{

/*获取出生点*/

Transform

sp

=

GameObject.Find

("Spawn").transform;

Transform

swopTrans;

if

(team

!=

1

&&

team

!=

2)

{

Debug.LogError

("team的格式不正确");

return;

}6实现战场管理功能6.实例化玩家GenerateBattl6实现战场管理功能6.实例化玩家

if

(swopID

<

1

||

swopID

>

5)

{

Debug.LogError

("swopID的格式不正确");

return;

}

//查找出生点对象

swopTrans

=

sp.GetChild

(team

-

1).GetChild

(swopID

-

1);

if

(swopTrans

==

null)

{

Debug.LogError

("GenerateBattleHero出生点错误!");

return;

}

if

(archerPre

==

null)

{

Debug.LogError

("GenerateBattleHero找不到预制体!");

return;

}

6实现战场管理功能6.实例化玩家

if

(swopI6实现战场管理功能6.实例化玩家

/*实例化角色*/

//实例化模型

GameObject

heroObj

=

(GameObject)Instantiate

(archerPre);

//名称

heroO

=

id;

/*位置*/

heroObj.transform.localPosition

=

Vector3.zero;

heroObj.transform.position

=

swopTrans.position;

heroObj.transform.rotation

=

swopTrans.rotation;

/*添加组件*/

//如果这个是玩家自身

if

(id

==

GameMgr.instance.id)

{

//添加玩家控制器

PlayerCtrl

pc=

heroObj.AddComponent<PlayerCtrl>

();

pc.aimPoint=Resources.Load("Prefabs/AimMark",typeof(GameObject))as

GameObject;

pc.arrowPrefab=Resources.Load("Prefabs/Arrow",typeof(GameObject))as

GameObject;

6实现战场管理功能6.实例化玩家

/*实例化角色*/6实现战场管理功能6.实例化玩家

//附着主摄像机

Camera.main.GetComponent<CameraTracePlayer>

().SetTarget

(heroObj.transform);

}

else

{

//添加网络控制器

NetCtrl

nc=

heroObj.AddComponent<NetCtrl>

();

nc.arrowPrefab=Resources.Load("Prefabs/Arrow",typeof(GameObject))as

GameObject;

/*设置刚体*/

Rigidbody

rrb

=

heroObj.GetComponent<Rigidbody>

();

rrb.useGravity

=

false;

rrb.isKinematic

=

true;

}

/*根据队伍处理材质*/

//如果是队伍1

if

(team

==

1)

{

6实现战场管理功能6.实例化玩家

//附着主6实现战场管理功能6.实例化玩家

Renderer[]

rs

=

heroObj.GetComponentsInChildren<Renderer>

();

//设置ID之外模型的材质

foreach

(Renderer

r

in

rs)

{

if(!="ID")

r.material

=

mat1;

}

/*设置ID的颜色*/

TextMesh

tm

=

heroObj.transform.Find

("ID").GetComponent<TextMesh>();

tm.color

=

Color.red;

tm.text

=

id;

}

else

{

Renderer[]

rs

=

heroObj.GetComponentsInChildren<Renderer>

();

//设置ID之外模型的材质

foreach

(Renderer

r

in

rs)

{

if(!="ID")

r.material

=

mat2;

}

6实现战场管理功能6.实例化玩家

Rendere6实现战场管理功能6.实例化玩家

/*设置ID的颜色*/

TextMesh

tm

=

heroObj.transform.Find

("ID").GetComponent<TextMesh>();

tm.color

=

Color.blue;

tm.text

=

id;

}

//列表处理

BattleArcher

ba

=

new

BattleArcher

();

ba.archer

=

heroObj.GetComponent<Archer>

();

ba.team

=

team;

list.Add

(id,

ba);

}6实现战场管理功能6.实例化玩家

/*设置ID的6实现战场管理功能6.实例化玩家using

System.Collections;

using

System.Collections.Generic;

using

UnityEngine;

public

class

NetCtrl

:

MonoBehaviour

{

}NerCtrl是网络同步控制脚本,被添加在非玩家控制的其他角色身上。脚本具体的内容会在项目7中实现,本任务中只创建NerCtrl脚本,代码如下。6实现战场管理功能6.实例化玩家using

System.6实现战场管理功能7.添加相机动态跟随脚本using

System.Collections;

using

System.Collections.Generic;

using

UnityEngine;

public

class

CameraTracePlayer

:

MonoBehaviour{

public

int

type

=

0;

public

Transform

player;

public

void

SetTarget

(Transform

target)

{

Transform

head

=

target.Find

("Body").Find

("Head");

transform.SetParent

(head);

transform.localPosition

=

new

Vector3

(0,

0.075f,

0.115f);

transform.localRotation

=

Quaternion.identity;

}

void

Start

()

{

if

(type

>

0)

SetTarget

(player);

}

}为了让相机动态地变成新建角色的子物体,不能再用以前直接拖动的方式,而是用脚本去实现,新建CameraTracePlayer脚本,并添加到主相机上,代码如下。6实现战场管理功能7.添加相机动态跟随脚本using

SyThankYOU!Thank腾讯云游戏应用开发腾讯云游戏应用开发实现登录功能01任务实现获取自身数据功能02任务实现注册功能03任务实现业务逻辑模块项目6实现匹配功能04任务实现准备功能05任务实现战场管理功能06任务实现登录功能01任务实现获取自身数据功能02任务实现注册功能学习目标

实现游戏的几个重要业务逻辑

掌握CS模式下协议的使用

掌握登录注册功能的基本实现方法学习目标实现游戏的几个重要业务逻辑1实现登录功能1.实现客户端请求登录方法当用户在登录界面中单击“登录”按钮后,后台尝试与服务器建立连接,连接成功后发送登录协议,协议格式为login;id;password;。修改LoginPanel.cs脚本中的OnLoginClick

方法,代码如下。/*登录按钮事件*/

public

void

OnLoginClick

()

{

if

(idInput.text

==

""

||

pwInput.text

==

"")

{

/*打开提示框*/

PanelMgr.instance.OpenPanel<TipPanel>

("用户名密码不能为空!");

return;

}

//如果服务器没有连接,连接服务器

if

(NetMgr.instance.status

!=

NetMgr.Status.Connected)

{

NetMto

=

new

ProtocolStr

();

/*连接*/

if

(!NetMgr.instance.Connect

())

PanelMgr.instance.OpenPanel<TipPanel>

("连接服务器失败!");

}

1实现登录功能1.实现客户端请求登录方法当用户在登录界面中单1实现登录功能1.实现客户端请求登录方法

//发送登录协议

ProtocolStr

protocol

=

new

ProtocolStr

();

protocol.AddString

("login");

protocol.AddString

(idInput.text);

protocol.AddString

(pwInput.text);

/*一次性监听*/

NetMgr.instance.Send

(protocol,

OnLoginBack);

}1实现登录功能1.实现客户端请求登录方法

//发送登1实现登录功能2.实现服务端登录协议处理方法在HandleConnMsg类中添加Msglogin方法,当服务端收到login协议时,分发给Mgslogin方法处理

public

void

Msglogin

(Conn

conn,

ProtocolBase

protoBase)

{

string

id,

pw;

ProtocolStr

protocol

=

(ProtocolStr)protoBase;

id

=

protocol.GetString

(1);

pw

=

protocol.GetString

(2);

/*构建返回协议*/

ProtocolStr

protocolRet

=

new

ProtocolStr

();

protocolRet.AddString

("login");

/*数据库校验*/

//如果用户名密码校验失败

if

(!DataMgr.instance.CheckPassWord

(id,

pw))

{

Console.WriteLine

("[Msglogin]登录失败:用户名和密码错误"

+

conn.GetAddress

());

protocolRet.AddInt

(-1);//返回失败结果

conn.Send

(protocolRet);

return;

}

1实现登录功能2.实现服务端登录协议处理方法在HandleC1实现登录功能2.实现服务端登录协议处理方法

if

(!ServNet.instance.KickOff

(id))

{

//如果踢下线失败

Console.WriteLine

("[Msglogin]登录失败:挤下线失败"

+

conn.player.id);

//返回失败结果

protocolRet.AddInt

(-1);

conn.Send

(protocolRet);

return;

}

PlayerData

playerData

=

DataMgr.instance.GetPlayerData

(id);

//获取玩家数据

if

(playerData

==

null)

{

Console.WriteLine

("[Msglogin]登录失败:获取账户信息失败"

+

conn.player.id);

protocolRet.AddInt

(-1);

//返回失败结果

conn.Send

(protocolRet);

return;

}

conn.player

=

new

Player

(id,

conn,

playerData);

//登入账户,加载数据

protocolRet.AddInt

(0);

//返回成功结果

conn.Send

(protocolRet);

}1实现登录功能2.实现服务端登录协议处理方法

i1实现登录功能3.实现客户端处理回发结果方法添加OnLoginBack方法

/*登录协议回执*/

public

void

OnLoginBack

(ProtocolBase

protocol)

{

/*构建协议*/

ProtocolStr

proto

=

(ProtocolStr)protocol;

/*校验登录结果*/

int

result

=

proto.GetInt

(1);

if

(result

==

0)

{

GameMgr.instance.id

=

idInput.text;

//保存账号ID

PanelMgr.instance.OpenPanel<TipPanel>

("登录成功!");

PanelMgr.instance.OpenPanel<LobbyPanel>

();

/*进入游戏大厅*/

PanelMgr.instance.ClosePanel

(this);

}

else

{

NetMgr.instance.Close

();

//断开连接

PanelMgr.instance.OpenPanel<TipPanel>

("登录失败,请检查用户名密码!");

}

}1实现登录功能3.实现客户端处理回发结果方法添加OnLogi1实现登录功能4.实现踢下线模块如果该角色在游戏中,则把它踢下线。并且发送Logout协议,向被踢下线的客户端发送通知。在ServNet中添加KickOff方法,代码如下。

/*如果某id已经在线就踢下线*/

public

bool

KickOff

(string

id)

{

for

(int

i

=

0;

i

<

conns.Length;

i++)

{

if

(conns

[i]

==

null)

continue;

if

(!conns

[i].isUse)

continue;

if

(conns

[i].player

==

null)

continue;

/*如果该玩家已经在线*/

if

(conns

[i].player.id

==

id)

{

lock

(conns[i].player)

{

Console.WriteLine

("检查到"+id+"已在线,踢下线");

/*通知客户端下线*/

ProtocolStr

protocolLogout

=

new

ProtocolStr

()

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论