多人联机游戏
实验要求
利用unity中的多人网络组件与API,设计一个多人联机的游戏
实验内容
本次实验是在课堂的基础上,进行设计的。
- 游戏内容:联机的几方,可以在系统敌人发射的子弹下进行移动,以期望存活时间最长
- 游戏视频链接:百度云盘链接
- 游戏代码下载:CSDN下载链接
- 第三点中的游戏代码下载之后,直接复制粘贴到unity3d新建项目的assets文件夹中即可进行操作
实验操作
游戏对象
- 首先需要一个空对象作为NetworkManager
- 其次是一个Plane
- 需要一个空对象来作为生产敌人的工厂
- 需要两个空对象作为游戏角色死亡后复活的点
- 需要游戏对象预制
- 需要子弹的预制
- 需要敌人的预制
游戏脚本
- PlayerMove脚本
using UnityEngine;
using UnityEngine.Networking;
public class PlayerMove : NetworkBehaviour
{
public GameObject bulletPrefab;
public override void OnStartLocalPlayer()
{
GetComponent<MeshRenderer>().material.color = Color.red;
}
[Command]
void CmdFire()
{
// This [Command] code is run on the server!
// create the bullet object locally
var bullet = (GameObject)Instantiate(
bulletPrefab,
transform.position - transform.forward,
Quaternion.identity);
bullet.GetComponent<Rigidbody>().velocity = -transform.forward * 4;
// spawn the bullet on the clients
NetworkServer.Spawn(bullet);
// when the bullet is destroyed on the server it will automaticaly be destroyed on clients
Destroy(bullet, 2.0f);
}
void Update()
{
if (!isLocalPlayer)
return;
var x = Input.GetAxis("Horizontal") * 0.1f;
var z = Input.GetAxis("Vertical") * 0.1f;
transform.Translate(x, 0, z);
if (Input.GetKeyDown(KeyCode.Space))
{
// Command function is called from the client, but invoked on the server
CmdFire();
}
}
}
- Bullet脚本
using UnityEngine;
public class Bullet : MonoBehaviour
{
void OnCollisionEnter(Collision collision)
{
var hit = collision.gameObject;
var hitCombat = hit.GetComponent<Combat>();
if (hitCombat != null)
{
hitCombat.TakeDamage(10);
Destroy(gameObject);
}
}
}
- Combat脚本
using UnityEngine;
using UnityEngine.Networking;
public class Combat : NetworkBehaviour
{
public const int maxHealth = 100;
public bool destroyOnDeath;
[SyncVar]
public int health = maxHealth;
public void TakeDamage(int amount)
{
if (!isServer)
return;
health -= amount;
if (health <= 0)
{
if (destroyOnDeath)
{
Destroy(gameObject);
}
else
{
health = maxHealth;
// called on the server, will be invoked on the clients
RpcRespawn();
}
}
}
[ClientRpc]
void RpcRespawn()
{
if (isLocalPlayer)
{
// move back to zero location
transform.position = Vector3.zero;
}
}
}
- HealthBar脚本
using UnityEngine;
using System.Collections;
public class HealthBar : MonoBehaviour
{
GUIStyle healthStyle;
GUIStyle backStyle;
Combat combat;
void Awake()
{
combat = GetComponent<Combat>();
}
void OnGUI()
{
InitStyles();
// Draw a Health Bar
Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
// draw health bar background
GUI.color = Color.grey;
GUI.backgroundColor = Color.grey;
GUI.Box(new Rect(pos.x - 26, Screen.height - pos.y + 20, Combat.maxHealth / 2, 7), ".", backStyle);
// draw health bar amount
GUI.color = Color.green;
GUI.backgroundColor = Color.green;
GUI.Box(new Rect(pos.x - 25, Screen.height - pos.y + 21, combat.health / 2, 5), ".", healthStyle);
}
void InitStyles()
{
if (healthStyle == null)
{
healthStyle = new GUIStyle(GUI.skin.box);
healthStyle.normal.background = MakeTex(2, 2, new Color(0f, 1f, 0f, 1.0f));
}
if (backStyle == null)
{
backStyle = new GUIStyle(GUI.skin.box);
backStyle.normal.background = MakeTex(2, 2, new Color(0f, 0f, 0f, 1.0f));
}
}
Texture2D MakeTex(int width, int height, Color col)
{
Color[] pix = new Color[width * height];
for (int i = 0; i < pix.Length; ++i)
{
pix[i] = col;
}
Texture2D result = new Texture2D(width, height);
result.SetPixels(pix);
result.Apply();
return result;
}
}
- EnemyFire脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class EnemyFire : NetworkBehaviour
{
public GameObject bulletPrefab;
// Use this for initialization
private int num = 0;
// Update is called once per frame
void Update () {
num++;
num = num % 100;
if(num == 0) CmdFire();
}
[Command]
void CmdFire()
{
// This [Command] code is run on the server!
// create the bullet object locally
var bullet = (GameObject)Instantiate(
bulletPrefab,
transform.position - transform.forward,
Quaternion.identity);
bullet.GetComponent<Rigidbody>().velocity = -transform.forward * 4;
//behind
var bullet1 = (GameObject)Instantiate(
bulletPrefab,
transform.position + transform.forward,
Quaternion.identity);
bullet1.GetComponent<Rigidbody>().velocity = transform.forward * 4;
//left
var bullet2 = (GameObject)Instantiate(
bulletPrefab,
transform.position - transform.right,
Quaternion.identity);
bullet2.GetComponent<Rigidbody>().velocity = -transform.right * 4;
//right
var bullet3 = (GameObject)Instantiate(
bulletPrefab,
transform.position + transform.right,
Quaternion.identity);
bullet3.GetComponent<Rigidbody>().velocity = transform.right * 4;
// spawn the bullet on the clients
NetworkServer.Spawn(bullet);
NetworkServer.Spawn(bullet1);
NetworkServer.Spawn(bullet2);
NetworkServer.Spawn(bullet3);
// when the bullet is destroyed on the server it will automaticaly be destroyed on clients
Destroy(bullet, 2.0f);
Destroy(bullet1, 2.0f);
Destroy(bullet2, 2.0f);
Destroy(bullet3, 2.0f);
}
}
- EnemySpawner脚本
using UnityEngine;
using UnityEngine.Networking;
public class EnemySpawner : NetworkBehaviour
{
public GameObject enemyPrefab;
public int numEnemies;
public override void OnStartServer()
{
for (int i = 0; i < numEnemies; i++)
{
var pos = new Vector3(
Random.Range(-8.0f, 8.0f),
0.2f,
Random.Range(-8.0f, 8.0f)
);
//var rotation = Quaternion.Euler(Random.Range(0, 180), Random.Range(0, 180), Random.Range(0, 180));
var rotation = Quaternion.Euler(0,0,0);
var enemy = (GameObject)Instantiate(enemyPrefab, pos, rotation);
NetworkServer.Spawn(enemy);
}
}
}