版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
腾讯云游戏应用开发腾讯云游戏应用开发实现登录功能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. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 气浮设备行业相关投资计划提议范本
- 2025中国旅游集团岗位公开招聘20人高频重点提升(共500题)附带答案详解
- 2025中国南水北调集团江汉水网建设开发限公司春季公开招聘【15人】高频重点提升(共500题)附带答案详解
- 2025中国人民财产保险股份限公司嘉兴市分公司招聘29人高频重点提升(共500题)附带答案详解
- 2025下半年陕西省省属事业单位联考招聘377人高频重点提升(共500题)附带答案详解
- 2025下半年广东佛山市南海区粮油储备限公司招聘3人高频重点提升(共500题)附带答案详解
- 2025下半年四川省泸州市古蔺县事业单位招聘86人历年高频重点提升(共500题)附带答案详解
- 2025上半年江苏省扬州广陵事业单位招聘141人历年高频重点提升(共500题)附带答案详解
- 2025上半年四川省雅安市考试招聘综合类事业单位人员418人高频重点提升(共500题)附带答案详解
- 2025上半年四川南充市高坪区招聘事业单位工作人员48人历年高频重点提升(共500题)附带答案详解
- 楼门牌制作合同范例
- 婴幼儿认知发展与指导学习通超星期末考试答案章节答案2024年
- 2024年居间服务合同:律师事务所合作与业务推广
- 消防设备施工方案
- DB43-T+3015-2014《校园食材配送服务规范》
- 安全生产专(兼)职管理人员职责
- 公检法联席会议制度
- 成都大学《Python数据分析》2022-2023学年期末试卷
- 上海市市辖区(2024年-2025年小学五年级语文)部编版期末考试(上学期)试卷及答案
- 期末试卷(试题)-2024-2025学年五年级上册数学人教版
- 护理安全警示教育-新-
评论
0/150
提交评论