这次的作业是在上一次坦克大战作业的基础上进行改进,实现多人网络对战版。
视频演示
https://www.bilibili.com/video/av25649733/
游戏实现
游戏主要对象还是利用了坦克预设和子弹预设。如下图:
文章图片
将原本的脚本都去掉,然后为tank预设添加Network Identity和Network Transform组件,并且把Network Identity的local player authority选项勾上,以允许能够在本地进行控制。然后创建一个Empty对象并挂载Network Manager和Network Manager HUD脚本,作为整个游戏的网络管理对象。同样的道理,子弹也应该添加Network Identity和Network Transform组件,注意子弹不需要勾选local player authority,并且Network Send Rate设为0即可。最后还要在Network Manager的Spawn Info里面注册相应的预设。具体设置如下:
文章图片
文章图片
文章图片
主要代码
为坦克添加控制脚本PlayerMove。Update()函数首先判断是不是本地对象执行,只有是服务端对象执行才可以修改坦克的位置,通过监听按键输入来控制刚体组件相应的速度来实现。当按下空格的时候,坦克开火。我使用了AddForce来控制子弹实例的刚体运动。如果直接在本地执行函数CmdShoot中使用,会出现client端子弹产生后不会运动的效果。(原因可以查一下谷歌:unity3d network transform addforce not working)。这里需要将AddForce函数放在一个ClientRpc函数中调用,这样才可以在所有客户端中同步。
其他的代码比较简单,这里就不累述。注意下两个函数:OnStartClient()和OnStartServer()。这两个函数分别在客户端对象和服务端对象产生时调用,这里我使用它们的目的是将对象的transform传递给main camera,使得main camera可以根据坦克对象的位置自动更新视野。
public class PlayerMove : NetworkBehaviour
{
public GameObject bulletPrefabs;
public override void OnStartClient()
{
Camera.main.GetComponent().setTarget(this.transform);
}public override void OnStartServer()
{
Camera.main.GetComponent().setTarget(this.transform);
}private void FixedUpdate()
{
if (!isLocalPlayer)
return;
float offsetX = Input.GetAxis("Horizontal");
float y = this.transform.localEulerAngles.y + offsetX * 5;
float x = this.transform.localEulerAngles.x;
this.transform.localEulerAngles = new Vector3(x, y, 0);
}// Update is called once per frame
void Update () {
if (!isLocalPlayer)
return;
if (Input.GetKey(KeyCode.W))
{
this.GetComponent().velocity = this.transform.forward * 20;
}
if (Input.GetKey(KeyCode.S))
{
this.GetComponent().velocity = this.transform.forward * -20;
}
if (Input.GetKeyDown(KeyCode.Space))
{
CmdShoot();
}
}[Command]
void CmdShoot()
{
var bullet = (GameObject)Instantiate(
bulletPrefabs,
new Vector3(transform.position.x, 1.5f, transform.position.z) + transform.forward * 1.5f,
Quaternion.identity);
bullet.transform.forward = transform.forward;
NetworkServer.Spawn(bullet);
RpcAddForceOnAll(bullet);
// make bullet disappear after 2 seconds
Destroy(bullet, 2.0f);
}[ClientRpc]
void RpcAddForceOnAll(GameObject bullet)
{
bullet.GetComponent().AddForce(bullet.transform.forward * 20, ForceMode.Impulse);
}
}
Combat组件用于控制坦克血量,health字段设置为SyncVar,表示该变量是服务端同步的。扣血函数TakeDamage只有服务端才可以调用,并且当玩家坦克血量为0之后(这里我设定为承受5次伤害即死亡),会进行重生,RpcRespawn函数会在客户端对象中更新玩家坦克的位置。
public class Combat : NetworkBehaviour
{public const int maxHealth = 500;
[SyncVar]
public int health = maxHealth;
public void TakeDamage(int amount)
{
if (!isServer)
return;
health -= amount;
Debug.Log("health value = "https://www.it610.com/article/+ health.ToString());
if (health <= 0)
{
health = maxHealth;
RpcRespawn();
}
}[ClientRpc]
void RpcRespawn()
{
if (isLocalPlayer)
{
transform.position = Vector3.zero;
}
}
}
BulletManager 用于管理子弹的状态,当子弹发生碰撞或者子弹落到地上都会消失。如果击中敌军坦克还会对其进行扣血。
public class BulletManager : MonoBehaviour {//private float explosionRadius = 3f;
private void FixedUpdate()
{
if(this.transform.position.y <= 0)
{
Destroy(gameObject);
}
}void OnCollisionEnter(Collision other)
{
var hit = other.gameObject;
var hitPlayer = hit.GetComponent();
if (hitPlayer != gameObject)
{
// 根据击中坦克与爆炸中心的距离计算伤害值
//float distance = Vector3.Distance(colliders[i].transform.position, transform.position);
//被击中坦克与爆炸中心的距离
//float hurt = 100f / distance;
//float current = colliders[i].GetComponent().getHp();
//colliders[i].GetComponent().setHp(current - hurt);
var combat = hit.GetComponent();
combat.TakeDamage(100);
}
Destroy(gameObject);
}
}
总结
完整代码请到我的github查看:https://github.com/CarolSum/Unity3d-Learning/tree/master/hw10
【Unity3D|unity3d-多人坦克对战】老师课上的简单多人游戏教程很详细,参考意义很大~这次作业也比较简单,能做出一个小型多人对战游戏很不错~毕竟小时候也是玩这种游戏大的。但是这远远不够,想要做出更有意义的游戏还是得继续深入学习,当然这得放到期末考之后啦~
推荐阅读
- Unity3D|Unity3d之坦克对战游戏 AI设计
- 笔记|Unity角色控制器CharacterController移动代码
- Unity3d|【Unity3D Debug】“CharacterController.Move()在处理角色移动时,角色不论怎么转向其移动方向始终不变”的解决方案
- Unity3D|Unity3D 角色控制器 Character Controller
- unity3d|Unity3D实现3D立体游戏原理及过程
- Unity3d|Unity Gameplay工具集(Unity Gameplay Tool Set)
- Unity3D|Unity3D ML-Agent-0.8.1 学习一(基础教程)
- unity|Unity3D GUI控件
- Unity3D|【Unity3D】GUI控件