Unity3D 多人网络游戏-客户端于服务器的同步
Unity3D 多人网络游戏-客户端于服务器的同步
第一次发表,非原创,是参照《Unity4.x 从入门到精通》一书做的Demo,mario是我从别的项目上扒下来的
游戏运行效果:客户端和服务器端的同步(运行稍有延迟现象)
游戏场景自行建立,只需要能体现出来即可,如一个地面一个预设物体即可
1. 启用Unity3D新建一项目,在场景中新建两个空的GameObject对象,并分别命名为Connect和RobotControl,如图所示,Connect对象负责客户端与服务器端的脚本逻辑.在该场景中服务器也参与游戏的运行.RobotControl对象主要负责控制主角的状态.
2. 在Project视图下建立C#文件,并命名AuthoritativeNetworkServer
3.编辑AuthoritativeNetworkServer脚本文件,代码如下:
using UnityEngine;
usingSystem.Collections;
publicclass AuthoritativeNetworkServer : MonoBehaviour {
// Use this for initialization
//定义远程连接IP地址(这里为本地)
private string ip="127.0.0.1";
//定义服务器端口号
private int port=10001;
void OnGUI(){
switch (Network.peerType) {
//服务器是否开启
case NetworkPeerType.Disconnected:
StartCreat();
break;
case NetworkPeerType.Server:
OnServer ();
break;
//启用客户端
case NetworkPeerType.Client:
OnClient();
break;
case NetworkPeerType.Connecting:
GUILayout.Label("连接中");
break;
}
}
void StartCreat(){
GUILayout.BeginVertical ();
//新建服务器连接
if (GUILayout.Button ("新建服务器")){
//初始化服务器端口
NetworkConnectionErrorerror=Network.InitializeServer(30,port);
Debug.Log(error);
}
//客户端是否连接服务器
if (GUILayout.Button ("连接服务器")){
//连接至服务器
NetworkConnectionErrorerror=Network.Connect(ip,port);
Debug.Log(error);
}
GUILayout.EndVertical ();
}
//启用服务器
void OnServer(){
GUILayout.Label ("新建服务器成功,等待客户端连接");
//连接的客户端数量
int length =Network.connections.Length;
for(int i=0;i<length;i++){
GUILayout.Label("连接的IP:"+Network.connections[i].ipAddress);
GUILayout.Label("连接的端口:"+Network.connections[i].port);
}
if (GUILayout.Button ("断开连接")){
Network.Disconnect();
}
}
//启用客户端
void OnClient(){
GUILayout.Label ("连接成功");
if (GUILayout.Button ("断开连接")){
Network.Disconnect();
}
}
}
3. 该脚本把客户端脚本与服务器脚本写至同一个类文件中,作为服务器还是客户端取决于单击的按钮.如果单击新建服务器按钮,那么该界面就作为服务器运行,以此类推
4. 拖动该脚本文件到Connect对象上,如图
5. 单击运行按钮,预览游戏
屏幕左上角出现了两个按钮,新建服务器已经连接服务器,单击新建服务器后提示创建服务器成功如图
6. 返回Unity编辑器中,在Project视图中新建C#脚本文件,并为其命名为PlayerCreat
7. 编辑该脚本,代码如下
usingUnityEngine;
usingSystem.Collections;
publicclass PlayerCreat : MonoBehaviour {
//新建目标对象
public Transform playerPrefab;
//新建集合,用于存储playerControl脚本组件
private ArrayList list=new ArrayList();
//服务器新建完成后运行
void OnServerInitialized(){
MovePlayer (Network.player);
}
//玩家连接后运行
void OnPlayerConnected(NetworkPlayer player){
MovePlayer (player);
}
void MovePlayer(NetworkPlayer player){
//获取玩家id值
int playerID = int.Parse(player.ToString());
//初始化目标对象
Transform playerTrans =(Transform)Network.Instantiate(playerPrefab,transform.position,transform.rotation,playerID);
NetworkView playerObjNetworkview =playerTrans.networkView;
//添加PlayerControl组件至集合中
list.Add(playerTrans.GetComponent("PlayerControl"));
//调用RPC,函数名为SetPlayer
playerObjNetworkview.RPC("SetPlayer",RPCMode.AllBuffered,player);
}
//玩家断开连接时调用
void OnPlayerDisconnected(NetworkPlayerplayer){
Debug.Log ("Clean up afterplayer "+player);
//遍历集合对象上的PlayerControl组件
foreach (PlayerControl script inlist) {
if(player==script.ownerPlayer){
Network.RemoveRPCs(script.gameObject.networkView.viewID);
Network.Destroy(script.gameObject);
list.Remove(script);
break;
}
}
int playerNumber = int.Parse(player+"");
Network.RemoveRPCs(Network.player,playerNumber);
Network.RemoveRPCs (player);
Network.DestroyPlayerObjects(player);
}
//客户端断开连接时调用
voidOnDisconnectedFromServer(NetworkDisconnection info){
Application.LoadLevel(Application.loadedLevel);
}
}
当服务器初始化完成时会运行OnServerInitialized函数。游戏中通过调用RPC函数来运行服务器或客户端的SetPlayer函数,需要使用RPC函数时,需要在该函数的上方添加@RPC(javasciprt)或者[RPC]C#,并传递N额头workPlayer对象到该函数中
10.拖动该脚本到RobotControl上,如图
11.在Project视图中Assets文件夹下找到mario预设体,为该预设体添加NetworkView,Rigidbody组件,为了避免该预设体对象发生穿墙等错误结果,需要为该预设体添加Box Collider组件,如图
12在Project视图中Assets下创建C#脚本文件,并为其命名为PlayerControl 编辑其脚本
using UnityEngine;
using System.Collections;
public class PlayerControl : MonoBehaviour{
//玩家对象
publicNetworkPlayer ownerPlayer;
//保存水平方向控制
privatefloat clientHInput=0;
//保存垂直方向控制
privatefloat clientVInput = 0;
//服务器水平方向控制
privatefloat serverHInput=0;
//服务器垂直方向控制
privatefloat serverVInput=0;
//游戏对象向前移动
privateint Player_Up=0;
//游戏对象向右移动
privateint Player_Right=1;
//游戏对象向后移动(相对于前)
privateint Player_Down=2;
//游戏对象向左移动
privateint Player_Left=3;
//游戏对象的旋转值
privateint PlayerRotate;
//游戏对象的位置
privateVector3 playerTransform;
//游戏对象的当前状态
privateint playerState=0;
voidAwake(){
//是否运行于服务器
if(Network.isClient) {
enabled=false;
}
}
voidUpdate(){
if(ownerPlayer != null & Network.player == ownerPlayer) {
//获取水平控制
floatcurrentHInput=Input.GetAxis ("Horizontal");
//获取垂直控制
floatcurrentVInput=Input.GetAxis("Vertical");
if(clientHInput!=currentHInput|| clientVInput!=currentVInput){
clientHInput=currentHInput;
clientVInput=currentVInput;
if(Network.isServer){
SendMovementInput(currentHInput,currentVInput);
}elseif(Network.isClient){
//只在服务器运行SendMovementInput函数
networkView.RPC("SendMovementInput",RPCMode.Server,currentHInput,currentVInput);
}
}
}
if(Network.isServer) {
//输入状态
if(serverVInput==1){
setState(Player_Up);
}
elseif(serverVInput==-1){
setState(Player_Down);
}
if(serverHInput==1){
setState(Player_Right);
}
elseif(serverHInput==-1){
setState(Player_Left);
}
if(serverHInput==0&& serverVInput==0){
//没有按下反向键时候 播放默认动画
animation.Play();
networkView.RPC("PlayState",RPCMode.OthersBuffered,"walk");
}
}
}
voidsetState(int state){
PlayerRotate= (state - playerState) * 90;
//当按下方向键,播放walk动画
animation.Play("walk");
networkView.RPC("PlayState",RPCMode.OthersBuffered,"walk");
switch(state) {
//向前移动
case0:
playerTransform= Vector3.forward*Time.deltaTime;
break;
case1:
//向右移动
playerTransform=Vector3.right*Time.deltaTime;
break;
case2:
//向后移动
playerTransform=Vector3.back*Time.deltaTime;
break;
case3:
//向左移动
playerTransform=Vector3.left*Time.deltaTime;
break;
}
//移动游戏对象
transform.Translate(playerTransform*5,Space.World);
//旋转游戏对象
transform.Rotate(Vector3.up,PlayerRotate);
//存储游戏状态
playerState= state;
}
[RPC]
voidPlayState(string state)
{
animation.Play(state);
}
[RPC]
//调用客户端(这里包括服务器)的setPlayer函数
voidSetPlayer(NetworkPlayer player){
ownerPlayer= player;
if(player == Network.player) {
enabled=true;
}
}
[RPC]
voidSendMovementInput(float currentHInput,float currentVInput){
serverHInput= currentHInput;
serverVInput= currentVInput;
}
voidOnSerializeNetworkView(BitStream stream,NetworkMessageInfo info){
//发送状态数据
if(stream.isWriting) {
Vector3pos = rigidbody.position;
Quaternionrot = rigidbody.rotation;
Vector3velocity = rigidbody.velocity;
Vector3angularVelocity = rigidbody.angularVelocity;
stream.Serialize(ref pos);
stream.Serialize(ref velocity);
stream.Serialize(ref rot);
stream.Serialize(ref angularVelocity);
}else {
//读取状态数据
Vector3pos=Vector3.zero;
Vector3velocity=Vector3.zero;
Quaternionrot=Quaternion.identity;
Vector3angularVelocity=Vector3.zero;
stream.Serialize(refpos);
stream.Serialize(refvelocity);
stream.Serialize(refrot);
stream.Serialize(refangularVelocity);
}
}
}
OnSerializeNetworkView函数通过判断是否写入,以序列化主角的位置(谁拥有该游戏对象,谁就能操作isWring属性),如果客户端操控游戏对象时处于写入状态,服务器则处于读取状态,反之亦然
13.点击Play按钮,预览游戏如图
退出游戏预览模式。为了使服务器能够运行与后台,一次打开菜单中Edit—ProjectSettings—Player项,在Inspector视图中勾选Per-PlatformSettings面板中的RunInBackground项,如果发布WEB端游戏,也需要勾选 如图
14.打开菜单栏的File—BuildSettings项,在弹出的对话框中选择要发布的平台,添加当前的场景后发布。
最后运行游戏,在客户端或者服务器端移动游戏主角时,可以看到服务器端和客户端的同步显示
Unity3D 多人网络游戏-客户端于服务器的同步相关推荐
- 安卓模拟器获取服务器信息出错,安卓模拟器客户端与服务器不同步
安卓模拟器客户端与服务器不同步 内容精选 换一换 目前从本地或虚拟机通过DRS备份迁移功能直接迁移到本云RDS for SQL Server实例上,在迁移完成后还需要针对Login账号,DBLink, ...
- 客户端与服务器持续同步解析(轮询,comet,WebSocket)
作者:盼逆邵年来源:博客园发布时间:2012-02-10 20:42 阅读:1943 次原文链接[收藏] 在B/S模型的Web应用中,客户端常常需要保持和服务器的持续更新.这种对及时性要求比较高的应 ...
- 多人网络游戏服务器开发基础学习笔记 II: 帧同步 | 游戏客户端预测原理分析 | FPS 游戏状态同步
这篇是对书本 网络多人游戏架构与编程 的学习第二篇(第一篇:多人网络游戏服务器开发基础学习笔记 I:基本知识 | 游戏设计模式 | 网游服务器层次结构 | 游戏对象序列化 | 游戏 RPC 框架 | ...
- [转载]Flash为客户端的多人网络游戏的实现
多人网络游戏的实现 项目开发的基本硬件配置 一台普通的pc就可以了, 安装好windows 2000和vc6就可以了, 然后连上网,局域网和internet都可以, 接下去的东西我都简化,不去用晦涩的 ...
- unity android服务器端,【深圳Unity3D培训】 Android客户端与PC服务器实现Socket通信
[深圳Unity3D培训] Android客户端与PC服务器实现Socket通信 Android终端连续扫描AP信息并发送给服务器端的完成.起首基于TCP协定在Android终端和PC两头之间构成收集 ...
- Unity3d搭建HTTP弱联网的服务器搭建及客户端编写(一)之java服务器
HTTP弱联网java服务器 HTTP弱联网java服务器 通过tomcat搭建java服务器linux 1java环境搭建 2tomcat环境搭建 3服务器搭建 下一篇php服务器 通过tomcat ...
- 【Unity学习笔记】b站Unity架构课Unity3D 商业化的网络游戏架构(高级/主程级别)
[Unity学习笔记]b站Unity架构课Unity3D 商业化的网络游戏架构(高级/主程级别) 自己跟着学完了,写了不少代码,会放在CSDN代码库,因为老师并没有提供源码,录屏也不是完全连续,所以难 ...
- Unity3d多人在线教程
[转载]Unity3d多人在线教程 (2013-02-25 16:02:49) 转载▼ 标签: 转载 原文地址:Unity3d多人在线教程作者:lsy0031 Unity 多个玩家开发教程 Uni ...
- 百万人同时在线直播的服务器,QQ游戏百万人同时在线的服务器架构实现
近日在与业内人士讨论时,提到QQ游戏的实现方式并不是我原来所想的那样,于是,今天又认真抓了一下QQ游戏的包,结果确如这位兄弟所言,QQ游戏的架构 与我当初所设想的那个架构相差确实不小.下面,我重新给出 ...
最新文章
- UBC、谷歌联合Hinton等提出3D点云的无监督胶囊网络,多任务上实现SOTA | AI日报...
- Kafka如果丢了消息,怎么处理的?
- 菜鸟经验积累之JS运算
- 电商仓储管理水平的五大标准
- CTF-Misc--处理压缩包大量文件将其转为二进制->10进制->字符串 脚本
- cesium模型不遮挡点线面_cesium点线面测试数据
- 从程序员到CTO的Java技术路线图 (转自安卓巴士)
- SAP Data Intelligence API执行出错的排错之道
- 来,拆一堆芯片看看!
- 最长回文子串(Longest Palindromic Substring)
- mysql定时异地备份_MYsql 异地备份脚本
- 我,23 岁 深漂女 Python自动化测试的心路历程|2021 总结
- 搜c语言题答案软件下载,C语言二级题库软件下载-C语言二级题库官方版下载v1.01-乐游网安卓下载...
- Node.js学习笔记(五)——WebSocket
- java支持xls格式的excel导入和导出
- 党² - 李超线段树
- 双月数据生成及其常见算法(二)
- The Untended Antiquity (二维树状数组 哈希)
- 在PrimeFaces中更改主题
- 论文研读笔记(二)——VGG
热门文章
- 操作系统——让操作系统走进保护模式
- Level 0 - Level 1
- dedecms系统搬家后或在系统还原后
- linux网卡多队列技术
- PHP美食甜点蛋糕店网站模板源码+带手机端/后台
- vue引用tinymce富文本编辑器及tinymce配置
- Elasticsearch 系列(三)Elasticsearch 安装以及相关插件的介绍
- 安大计算机图形学实验——二维图形变换
- Parallels虚拟机kali linux 启动ssh服务 容许root远程登陆
- 商品图片外链转内链php,wordpress外链转内链代码(支持跳转页、nofollow、加密原链接)...