使用Multiplayer Networking做一个简单的多人游戏例子-2/3(Unity3D开发之二十六)
猴子原创,欢迎转载。转载请注明: 转载自Cocos2Der-CSDN,谢谢!
原文地址: http://blog.csdn.net/cocos2der/article/details/51007512
使用Multiplayer Networking做一个简单的多人游戏例子-1/3
使用Multiplayer Networking做一个简单的多人游戏例子-2/3
使用Multiplayer Networking做一个简单的多人游戏例子-3/3
7. 在网络中控制Player移动
上一篇中,玩家操作移动会同时控制同屏内的所有Player,且只有自己的屏幕生效。因为咱们还没有同步Transform信息。
下面我们通过UnityEngine.Networking组件来实现玩家控制各自Player
- 打开PlayerController脚本
- 添加命名空间UnityEngine.Networking
using UnityEngine.Networking;
- 修改MonoBehaviour为NetworkBehaviour
public class PlayerController : NetworkBehaviour
- 在Update函数中添加如下方法
if (!isLocalPlayer)
{
return;
}
最后你的PlayerController内容如下:
using UnityEngine;
using UnityEngine.Networking;
public class PlayerController : NetworkBehaviour
{
void Update()
{
if (!isLocalPlayer)
{
return;
}
var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
var z = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;
transform.Rotate(0, x, 0);
transform.Translate(0, 0, z);
}
}
- 保存脚本
- 回到Unity中
- 选中Player prefab在Project面板中
- 保持Player prefab为选中状态
- 添加组件Network > NetworkTransform
- 保存工程
NetworkTransform用于在网络中同步所有Client信息。加上isLocalPlayer判断,只让当前客户端操作。
8. 测试网络中多玩家移动
- 同样Build一个Mac standalone application作为主机运行
- 点击LAN Host作为主机开始游戏
- 运行Unity,点击LAN Client作为另一个客户端加入游戏
- 点击各自的WASD移动各自Player
9. 区分各自的Player
上面中两个Player外观一致,我们修改自己Player的颜色
- 打开PlayerController脚本
- 添加OnStartLocalPlayer方法
public override void OnStartLocalPlayer()
{
GetComponent<MeshRenderer>().material.color = Color.blue;
}
最终PlayerController:
using UnityEngine;
using UnityEngine.Networking;
public class PlayerController : NetworkBehaviour
{
void Update()
{
if (!isLocalPlayer)
{
return;
}
var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
var z = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;
transform.Rotate(0, x, 0);
transform.Translate(0, 0, z);
}
public override void OnStartLocalPlayer()
{
GetComponent<MeshRenderer>().material.color = Color.blue;
}
}
- Build新的Mac版本,测试效果
- 关闭Mac版本,停止运行Unity,回到编辑状态
10. 给Player添加射击武器
创建子弹
- 创建一个Sphere GameObject
- 修改名称为“Bullet”
- 选中Bullet对象
- 修改Transform (0.2, 0.2, 0.2)
- 添加组件Physics > Rigidbody
- 在Rigidbody属性中取消Use Gravity
- 拖拽Bullet到Project面板中,制作为Prefab
- 删除场景中Bullet
- 保存场景
下面修改PlayerController添加发射子弹
- 打开PlayerController脚本
- 添加public变量bulletPrefab
public GameObject bulletPrefab;
- 添加子弹local发射点
public Transform bulletSpawn;
- 在Update中加入输入源
if (Input.GetKeyDown(KeyCode.Space))
{
Fire();
}
- 添加Fire方法
void Fire()
{
// Create the Bullet from the Bullet Prefab
var bullet = (GameObject)Instantiate (
bulletPrefab,
bulletSpawn.position,
bulletSpawn.rotation);
// Add velocity to the bullet
bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * 6;
// Destroy the bullet after 2 seconds
Destroy(bullet, 2.0f);
}
最终PlayerController如下:
using UnityEngine;
using UnityEngine.Networking;
public class PlayerController : NetworkBehaviour
{
public GameObject bulletPrefab;
public Transform bulletSpawn;
void Update()
{
if (!isLocalPlayer)
{
return;
}
var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
var z = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;
transform.Rotate(0, x, 0);
transform.Translate(0, 0, z);
if (Input.GetKeyDown(KeyCode.Space))
{
Fire();
}
}
void Fire()
{
// Create the Bullet from the Bullet Prefab
var bullet = (GameObject)Instantiate(
bulletPrefab,
bulletSpawn.position,
bulletSpawn.rotation);
// Add velocity to the bullet
bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * 6;
// Destroy the bullet after 2 seconds
Destroy(bullet, 2.0f);
}
public override void OnStartLocalPlayer ()
{
GetComponent<MeshRenderer>().material.color = Color.blue;
}
}
- 保存脚本
- 回到Unity
下面开始针对变化过的PlayerController修改Player Prefab
- 将Player Prefab拖拽到场景中
- 保持Player prefab选中
- 创建一个Cylinder圆柱体作为其Child
- 修改Cylinder名称为“Gun”
- 保持Gun被选中
- 移除Capsule Collider组件
- 设置Transform Position (0.5, 0.0, 0.5)
- 设置Transform Rotation (90.0, 0.0, 0.0)
- 设置Transform Scale (0.25, 0.5, 0.25)
- 设置Material为Black Material
最后Player效果:
- 保持Player选中状态
- 创建一个empty GameObject作为Child
- 修改empty GameObject名称为“Bullet Spawn”
- 设置Bullet Spawn Position (0.5, 0.0, 1.0)
主要是将子弹发射点Bullet Spawn设置到枪口处
- 保持Player Prefab选中
- 将Bullet prefab拖到PlayerController中的Bullet Prefab 框
- 将Player的Child Bullet Spawn拖到PlayerController中的Bullet Spawn 框
- 保存工程
- Build新的Mac版本,并测试
你会发现空格键可以在各自场景中发射子弹,但是子弹没有出现在对方场景中。
- 关闭Mac版本
- 停止Unity,回到编辑模式
11. 增加多人射击
下面我们会将Bullet prefab注册到NetworkManager
- 选中Bullet prefab在Project面板中
- 保存Bullet prefab选中
- 添加组件Network > NetworkIdentity
- 添加组件Network > NetworkTransform
- 设置NetworkTransform中Network Send Rate为0
子弹不会中途改变方向,所以我们不需要每帧更新位置,每个客户端自己计算Bullet坐标信息,所以将Network Send Rate设置为0,网络不需要同步坐标信息。
- 选中NetworkManager在Hierarchy面板中
- 保持NetworkManager选中
- 展开Spawn Info
- 点击Registered Spawnable Prefabs右下角+
将Bullet Prefab加入到Registered Spawnable Prefabs中
打开PlayerController脚本
注意[Command]可以声明一个函数可以本客户端调用,但是会在服务端(主机)执行。
- 添加[Command]给Fire函数
- 修改Fire函数名称为“CmdFire”
[Command]
void CmdFire()
- Update函数中修改调用为CmdFire
CmdFire();
- 在CmdFire函数中添加NetworkServer.Spawn方法来创建bullet
NetworkServer.Spawn(bullet);
最终PlayerController如下:
using UnityEngine;
using UnityEngine.Networking;
public class PlayerController : NetworkBehaviour
{
public GameObject bulletPrefab;
public Transform bulletSpawn;
void Update()
{
if (!isLocalPlayer)
{
return;
}
var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
var z = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;
transform.Rotate(0, x, 0);
transform.Translate(0, 0, z);
if (Input.GetKeyDown(KeyCode.Space))
{
CmdFire();
}
}
// This [Command] code is called on the Client …
// … but it is run on the Server!
[Command]
void CmdFire()
{
// Create the Bullet from the Bullet Prefab
var bullet = (GameObject)Instantiate(
bulletPrefab,
bulletSpawn.position,
bulletSpawn.rotation);
// Add velocity to the bullet
bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * 6;
// Spawn the bullet on the Clients
NetworkServer.Spawn(bullet);
// Destroy the bullet after 2 seconds
Destroy(bullet, 2.0f);
}
public override void OnStartLocalPlayer ()
{
GetComponent<MeshRenderer>().material.color = Color.blue;
}
}
- 保存脚本
- 回到Unity
- Build新版本Mac,测试
此时应该可以看到子弹同步到了每个玩家场景中
- 关闭Mac版本
- 停止运行Unity,回到编辑模式
添加玩家生命值
- 给Bullet Prefab添加一个新脚本“Bullet”
- 打开Bullet脚本
- 添加碰撞函数
using UnityEngine;
using System.Collections;
public class Bullet : MonoBehaviour {
void OnCollisionEnter(Collision collision)
{
Destroy(gameObject);
}
}
此时子弹碰撞到Player之后自动销毁
添加玩家生命值
- 给Player prefab添加一个新脚本“Health”
Health脚本如下:
using UnityEngine;
public class Health : MonoBehaviour
{
public const int maxHealth = 100;
public int currentHealth = maxHealth;
public void TakeDamage(int amount)
{
currentHealth -= amount;
if (currentHealth <= 0)
{
currentHealth = 0;
Debug.Log("Dead!");
}
}
}
- 保存脚本
在Bullet中增加击中受伤
- 修改Bullet中的OnCollisionEnter函数
using UnityEngine;
using System.Collections;
public class Bullet : MonoBehaviour {
void OnCollisionEnter(Collision collision)
{
var hit = collision.gameObject;
var health = hit.GetComponent<Health>();
if (health != null)
{
health.TakeDamage(10);
}
Destroy(gameObject);
}
}
添加一个简易的玩家头顶血条
- 在场中中创建一个UI Image
- 修改Canvas名称为“Healthbar Canvas”
- 修改Image名称为“Background”
- 保存Background选中
- 设置RectTransform Width 100
- 设置RectTransform Height 10
- 修改Source Image 为 built-in InputFieldBackground
- 修改 Image Color 为红色
- 不要修改Background的中心点和锚点
- 复制一份Background
- 修改复制出来的Background名称为Foreground
- 将Foreground设置为Background的Child
- 将Player prefab拖到场景中
将Healthbar Canvas拖到Player中作为Child
整个Player结构如下:
选中Foreground
- 设置Foreground Image为绿色
将Foreground 中心点和锚点修改为Middle Left(用于血条从左到右填充)
选中Healthbar Canvas
- 点击RectTransform设置按钮(小齿轮)中的Reset
- 设置RectTransform Scale (0.01, 0.01, 0.01)
- 设置RectTransform Position (0.0, 1.5, 0.0)
- 选中Player,点击apply,保存Player Prefab
- 保存场景
修改Health脚本,控制血条
最终Health脚本如下:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Health : MonoBehaviour {
public const int maxHealth = 100;
public int currentHealth = maxHealth;
public RectTransform healthBar;
public void TakeDamage(int amount)
{
currentHealth -= amount;
if (currentHealth <= 0)
{
currentHealth = 0;
Debug.Log("Dead!");
}
healthBar.sizeDelta = new Vector2(currentHealth, healthBar.sizeDelta.y);
}
}
- 保存脚本
- 回到Unity
- 保持Player选中
- 将Foreground拖到Healthbar输入框中
- apply Player prefab
- 删除场景中的Player
- 保存场景
最后,修改Healthbar永远朝向主摄像机
- 给Player prefab中的Healthbar Canvas添加新脚本“Billboard”
Billboard脚本如下:
using UnityEngine;
using System.Collections;
public class Billboard : MonoBehaviour {
void Update () {
transform.LookAt(Camera.main.transform);
}
}
- 编译新Mac版本,测试
你会发现血条只在本地变化了,没有同步到所有玩家。
使用Multiplayer Networking做一个简单的多人游戏例子-2/3(Unity3D开发之二十六)的更多相关文章
- 使用Multiplayer Networking做一个简单的多人游戏例子-3/3(Unity3D开发之二十七)
使用Multiplayer Networking做一个简单的多人游戏例子-1/3 使用Multiplayer Networking做一个简单的多人游戏例子-2/3 使用Multiplayer Netw ...
- 使用Multiplayer Networking做一个简单的多人游戏例子-1/3(Unity3D开发之二十五)
猴子原创,欢迎转载.转载请注明: 转载自Cocos2Der-CSDN,谢谢! 原文地址: http://blog.csdn.net/cocos2der/article/details/51006463 ...
- 使用Multiplayer Networking做一个简单的多人游戏例子-1/2
原文地址: http://blog.csdn.net/cocos2der/article/details/51006463 本文主要讲述了如何使用Multiplayer Networking开发多人游 ...
- 使用Multiplayer Networking做一个简单的多人游戏例子-1/2(换一种方法)
SynMove.cs using UnityEngine; using System.Collections; using UnityEngine.Networking; public class S ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(十六)——dapr+sentinel中间件实现服务保护
dapr目前更新到了1.2版本,在之前4月份的时候来自阿里的开发工程师发起了一个dapr集成Alibaba Sentinel的提案,很快被社区加入到了1.2的里程碑中并且在1.2 release 相关 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(十九)——分布式事务之Saga模式
在之前的系列文章中聊过分布式事务的一种实现方案,即通过在集群中暴露actor服务来实现分布式事务的本地原子化.但是actor服务本身有其特殊性,场景上并不通用.所以今天来讲讲分布式事务实现方案之sag ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(十八)——服务保护之多级缓存
很久没有更新dapr系列了.今天带来的是一个小的组件集成,通过多级缓存框架来实现对服务的缓存保护,依旧是一个简易的演示以及对其设计原理思路的讲解,欢迎大家转发留言和star 目录:一.通过Dapr实现 ...
- 【Bugly干货分享】一起用 HTML5 Canvas 做一个简单又骚气的粒子引擎
Bugly 技术干货系列内容主要涉及移动开发方向,是由Bugly邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,转载请标明出处. 前言 好吧,说是“粒子引擎”还是大言不 ...
- 使用React并做一个简单的to-do-list
1. 前言 说到React,我从一年之前就开始试着了解并且看了相关的入门教程,而且还买过一本<React:引领未来的用户界面开发框架 >拜读.React的轻量组件化的思想及其virtual ...
随机推荐
- ubuntu蓝牙音响配对成功但在声音设置中无法设置 解决
ubuntu蓝牙音响配对成功但在声音设置中无法设置 解决 首先,连接蓝牙 但是,在声音设置中如下: 都没有发现设备??? 打开终端输入: ~$ pactl load-module module-blu ...
- 初识Spring Boot框架
前面的铺垫文章已经连着写了六篇了,主要是介绍了Spring和SpringMVC框架,小伙伴们在学习的过程中大概也发现了这两个框架需要我们手动配置的地方非常多,不过做JavaEE开发的小伙伴们肯定也听说 ...
- hive 压缩全解读(hive表存储格式以及外部表直接加载压缩格式数据);HADOOP存储数据压缩方案对比(LZO,gz,ORC)
数据做压缩和解压缩会增加CPU的开销,但可以最大程度的减少文件所需的磁盘空间和网络I/O的开销,所以最好对那些I/O密集型的作业使用数据压缩,cpu密集型,使用压缩反而会降低性能. 而hive中间结果 ...
- cassandra 监控方案评估
摘要 最开始做cassandra monitor 方案的选型时,主要是从cassandra 本身入手,后来发现cassandra运行在JVM上,所有的metrics都是通过JMX 暴露出来.所以又可以 ...
- Swift的print不换行打印的方法
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) swift大多数情况下我们直接用默认的print函数打印就可以 ...
- 剑指offer面试题4 替换空格(java)
注:利用java中stringBuilder,append,length方法很方便的解决字符串问题 /* * 剑指offer 替换空格 * xsf * */ /*开始替换空格的函数,length为原数 ...
- achartengine之折线图
问题在文章的最后,大致说来就是折线图,如果点的个数大于3个的时候,不是所有的点都显示对应的值的,这是为什么呢,本来以为是小问题,但两天了还没找到原因) 将前两天的折线图代码做了小量修改,形成一个类似于 ...
- 5.1、Android Studio用Logcat编写和查看日志
Android Studio在Android Monitor中包含了一个logcat的tab,可以打印系统事件,比如垃圾回收发生时,实时打印应用消息. 为了显示需要的信息,你可以创建过滤器,更改需要显 ...
- Android计时器Chronometer-android学习之旅(二十一)
Chronometer简介 Chronometer和DigitalColok都继承与TextView,但是Chronometer不是显示的当前时间,而是从某个时间开始又过去了多少时间,是一个时间差. ...
- MacOS的菜单状态栏App添加饼型进度
猴子原创,欢迎转载.转载请注明: 转载自Cocos2Der-CSDN,谢谢! 原文地址: http://blog.csdn.net/cocos2der/article/details/52075418 ...