这一次我将带领大家用Unity3D游戏引擎去开发一款游戏——坦克大战。
游戏玩法如下:
通过“W”、“A”、“S”、“D”键控制玩家1(蓝方)移动,空格键控制玩家1开炮
通过方向键控制玩家2(红方)移动,回车键控制玩家2开炮
游戏演示效果如下:
说明:游戏开发平台:Windows 10、Unity版本:Unity 2017.2.0f3
一、创建游戏工程按照下图依次点击“New”→“输入工程名”→“选择保存路径”→“点击Create project按钮”
Unity工程创建完成后如图所示:
接下来应该导入此项目所需的Unity Package文件,要用到的Unity package文件大家可以去Unity3D的官方网站下载(地址:https://www.assetstore.unity3d.com/en/?&_ga=2.21331896.203842797.1510021401-332298740.1510021401#!/content/46209/)
导入Package的方法很简单,只需要在“Project”窗口下的“Assets”目录上右键,再依次选择“Import Package”→“Custom Package...”,选中下载好的package文件,然后在弹出的窗口中点击“Import”按钮即可
导入完成后目录结构如下:
二、添加游戏主场景首先在“Assets”目录下新建一个文件夹“Scenes”,用来存放场景。创建方式如图:右键”Assets“→”Create“→”Folder“
按下快捷键”Ctrl S“保存场景,在目录“Assets”→“Prefabs”下找到预制体“LevelArt”,将它拖入“Hierarchy”窗口中
随后删除“Directional Light”
三、制作坦克和炮弹的预制体3.1、坦克预制体的制作
在目录“Assets”→“Models”下找到模型“Tank”,将它拖到“Hierarchy”窗口中
在“Tank”上右键选择“Create Empty”,创建一个空的游戏物体“FiringPoint”。将“FiringPoint”用作炮弹的发射点,后续将从此处发射(实例化)炮弹
将“发射点”调整到合适的位置,如下图:
在“Tank”上右键“UI”→“Slider”创建一个滑动条,后续我们将使用这个滑动条作为坦克的血条,用来显示坦克剩余的血量。
定位到“Canvas”中的“Slider”,展开“Slider”滑动条,将下面的“Handle Slide Area”删除
因为我们将要展示的血条是一个环状的图形,所以我们还需改变它的“Background”。
首先找到目录“Assets”→“Sprites”下的“Health Wheel”,然后选中“Slider”下的“Background”,将前面的“Health Wheel”拖入到“Image”组件上的“Source Image”中,以此来改变Slider的背景
重复上述方式,改变“Fill Area”→“Fill”的“Source Image”
改变“Slider”的显示方式,让其居中,并将“Width”和“Height”设为一个合适的值,比如40
然后将“Slider”里面的“Baackground”、“Fill Area”、“Fill”都设置为上下左右填充的方式,并把它们的“Left”、“Right”、“Top”、“Bottom”统统设为零。然后定位到“Fill”,把“Image”组件的“Color”属性修改为血红色,把“Image Type”属性修改为“Filled”
到这一步血环的基本样式就做好了,你可以通过改变“Slider”的“Value”的大小来检测效果,效果如下图:
上述效果完成之后,还需把“Canvas”的“Render Mode”改为“World Space”,并将“Canvas”整体拖入“Tank”下
修改“Slider”的显示,将其改为上下左右填充,修改“Canvas”的“Width”、“Height”,将它们改为合适的大小,比如3.8,将“Canvas”围绕X轴旋转90度,也就是将“Rotation”的“X”改为90,以让其与地面平行,效果如下:
选中游戏物体“Tank”,点击“Inspector”窗口中的“Add Component”按钮搜索并添加“Rigidbody”和“Box Collider”两个组件
然后点击“Edit Collider”按钮编辑碰撞器的大小,让它吻合坦克的大小即可,如下图,编辑坦克上的绿框即可进行调整
至此,坦克的预制体基本制作完毕,别忘了还要将它拖入到“Assets”→“Prefabs”目录下才算彻底完成
3.2、炮弹预制体的制作
同样的,在目录“Assets”→“Models”下找到“Shell”的模型并将其拖放到场景中,然后通过“Inspector”窗口下的“Add Component”按钮添加两个组件,分别是“Rigidbody”和“Capsule Collider”
同样的,通过编辑碰撞器的大小来吻合炮弹的大小,这里还要将碰撞器的”Direction“属性改为”Z-Axis“
这样炮弹预制体的制作也结束了,一样的,不要忘了要将”Hierarchy“窗口下的”Shell“拖到目录”Assets“→”Prefabs“下才算完成
四、控制坦克的移动和攻击我们的游戏有两个玩家,自然就需要两个坦克。前文已经说过,我们将通过”W“、”A“、”S“、”D“键控制玩家1(1号坦克)、通过方向键控制玩家2(2号坦克)。
首先将之前在”Hierarchy“窗口下的”Tank“和”Shell“两个游戏物体删除。随后将目录”Prefabs“下的”Tank“放入场景中,当然需要放入两个,并把它们分别重命名为”Tank1“、”Tank2“。
为了便于区分,我把”Tank1“设成蓝色,把”Tank2“设为红色
展开”Tank1“→”TankRenderers“,分别将其下面的”TankChassis“、”TankTracksLeft“、”TankTracksRight“、”TankTurret“中的”Materials“的属性”Element 0“的值改为目录”Prefabs“→”Materials“下的”Blue“
对”Tank2“重复上述操作,只不过把材料”Blue“替换为”Red“
改完后的整体效果如下:
4.1、控制坦克移动
在控制坦克的移动之前我们稍微进行一下项目设置,因为要让Unity区分”W“、”A“、”S“、”D“键和方向键并做不同的控制。
首先在菜单栏中依次点击”Edit“→”Project Settings“→”Input“
然后在”Inspector“窗口下右键”Axes“→”Horizontal“,再点击”Duplicate Array Element“复制两个”Horizontal“,将复制得到的一个”Horizontal“的”Name“改为”HorizontalPlayer1“并去掉其中的”left“、”right“两个值,因为我们只希望通过”A“、”D“键而不是左右键来控制玩家1的移动(转向);同理将复制得到的另一个”Horizontal“的”Name“改为”HorizontalPlayer2“并去掉其中的”A“、”D“两个值,因为我们只希望通过左右方向键而不是”A“、”D“键来控制玩家2的移动(转向)。
对于”Vertical“重复上面的操作,只不过要把上面的”Horizontal“全部替换为”Vertical“。
给坦克的预制体添加一个脚本组件,将其命名为”TankMovement“。右键此脚本,点击”Edit Script“,编辑脚本文件的内容如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TankMovement : MonoBehaviour {
private Rigidbody rb;
public int number = 1; // 通过编号区分不同坦克
public float speed = 10; //速度大小
public float angularSpeed = 10; //转向角度
// Use this for initialization
void Start () {
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update () {
float h = Input.GetAxis("HorizontalPlayer" number);
float v = Input.GetAxis("VerticalPlayer" number);
rb.velocity = transform.forward * v * speed;
rb.angularVelocity = transform.up * h * angularSpeed;
}
}
因为number默认为1,所以需要修改”Tank2“的”Tank Movement“组件下的”Number“属性,将其改为2。
然后需要注意一点,我们还要把”Tank“预制体的”Constraints“下的”Freeze Position“的”Y“给勾选上,把”Freeze Rotation“的”X“、”Z“勾选上
4.2、控制坦克攻击
给坦克的预制体添加一个脚本组件,将其命名为”TankAttack“。右键此脚本,点击”Edit Script“,编辑脚本文件的内容如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TankAttack : MonoBehaviour {
public Transform firingPointTransform;
public GameObject shellPrefab;
public KeyCode firingKey = KeyCode.Space; // 开火键,默认为空格键
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(firingKey)) {
Instantiate(shellPrefab, firingPointTransform.position, firingPointTransform.rotation); // 发射炮弹即实例化炮弹
}
}
}
写入以上代码后,别忘了在Unity中给”firingPointTransform“和”shellPrefab“赋值,然后再把”Tank2“的”firingKey“改为回车键。
在”Shell“预制体上添加一个脚本组件,并命名为”Shell“,用来控制炮弹的飞行和爆炸。右键此脚本组件并选择”Edit Script“,编辑脚本的内容如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Shell : MonoBehaviour {
private Rigidbody rb;
public GameObject shellExplosionPrefab;
public float shellSpeed = 15;
private float duration = 1.50f; // 爆炸动画效果持续时间
// Use this for initialization
void Start () {
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update () {
rb.velocity = transform.forward * shellSpeed;
}
private void OnCollisionEnter(Collision collision)
{
GameObject shellExplosion = Instantiate(shellExplosionPrefab, transform.position, transform.rotation) as GameObject;
Destroy(gameObject);
Destroy(shellExplosion, duration);
}
}
同样别忘了在Unity中给属性”shellExplosionPrefab“赋值。还要记得把”ShellExplosion“的”Play On Awake“勾选上。这样动画才能播放
六、控制坦克的血量和伤害首先修改”Shell.cs“脚本的内容如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Shell : MonoBehaviour {
private Rigidbody rb;
public GameObject shellExplosionPrefab;
public float shellSpeed = 15;
private float duration = 1.50f; // 爆炸动画效果持续时间
// Use this for initialization
void Start () {
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update () {
rb.velocity = transform.forward * shellSpeed;
}
private void OnCollisionEnter(Collision collision)
{
GameObject shellExplosion = Instantiate(shellExplosionPrefab, transform.position, transform.rotation) as GameObject;
Destroy(gameObject);
Destroy(shellExplosion, duration);
// 如果炮弹攻击到的是坦克,则对此坦克造成伤害
if (collision.collider.tag == "Tank") {
collision.collider.SendMessage("TankDamage");
}
}
}
给坦克的预制体添加一个名为”TankHealth“的脚本组件用来控制坦克的血量,编辑脚本,其内容如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TankHealth : MonoBehaviour {
public float hp = 100; // 坦克默认共有100滴血
private float hpTotal;
public GameObject tankExplosionPrefab;
private float duration = 1.05f;
public Slider slider;
// Use this for initialization
void Start () {
hpTotal = hp;
}
// Update is called once per frame
void Update () {
}
// 坦克受到伤害
private void TankDamage() {
hp -= Random.Range(10, 20);
slider.value = hp / hpTotal;
if (hp <= 0) { // 坦克血量小于0,被干掉了
GameObject tankExplosion = Instantiate(tankExplosionPrefab, transform.position, transform.rotation) as GameObject;
Destroy(gameObject);
Destroy(tankExplosion, duration);
}
}
}
还是那句话,别忘了在Unity中给属性”tankExplosionPrefab“和”slider“赋值。当然”TankExplosion“的”Play On Awake“也要勾选上。
在控制相机”Camera“之前,先把相机的投影方式改为正交投影”Orthographic“,并控制相机视角让其正好同时能观察到两个坦克
7.1、控制相机的跟随
在相机”Main Camera“中添加脚本组件,并将其命名为”FollowTarget“,脚本文件的内容如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowTarget : MonoBehaviour {
public Transform tank1Transform;
public Transform tank2Transform;
private Vector3 offset; // 相机和两坦克的相对位移,保持其不变即可完成相机跟随
// Use this for initialization
void Start () {
offset = transform.position - (tank1Transform.position tank2Transform.position) / 2;
}
// Update is called once per frame
void Update () {
if (tank1Transform == null || tank2Transform == null) return;
transform.position = (tank1Transform.position tank2Transform.position) / 2 offset;
}
}
这里也要注意别忘了给”tank1Transform“和”tank2Transform“这两个属性赋值。
7.2、控制视野范围的变化
再次打开脚本文件”FollowTarget.cs“,修改为如下内容:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowTarget : MonoBehaviour {
public Transform tank1Transform;
public Transform tank2Transform;
private Camera c;
private Vector3 offset; // 相机和两坦克的相对位移,保持其不变即可完成相机跟随
private float viewProportion; // 此视野比例乘两坦克之间的距离即是当前视野大小
// Use this for initialization
void Start () {
c = GetComponent<Camera>();
offset = transform.position - (tank1Transform.position tank2Transform.position) / 2;
viewProportion = c.orthographicSize / Vector3.Distance(tank1Transform.position, tank2Transform.position);
}
// Update is called once per frame
void Update () {
if (tank1Transform == null || tank2Transform == null) return;
transform.position = (tank1Transform.position tank2Transform.position) / 2 offset;
c.orthographicSize = viewProportion * Vector3.Distance(tank1Transform.position, tank2Transform.position);
}
}
将上面内容添加完毕后你会发现,两个坦克会一直处于相机视野的中心,并且视野范围会随着两个坦克之间距离的变化而变化。
终于到最后了,在这里我们将给游戏添加音效,让游戏玩起来更带感!
你可以定位到”Assets“→”AudioClips“目录下看一看已经准备好的音乐,有游戏的背景声、坦克的引擎声、炮弹的爆炸声等等,也可以先听一听它的效果
8.1、添加游戏背景音
首先我们来添加背景声,在”Hierarchy“窗口下右键→”Create Empty“创建一个空的游戏物体并命名为”GameManager“
按照下图步骤给”GameManager”添加一个”Audio Source“组件
下面给“Audio Source”设置一个声音源,将“Assets”→“AudioClips”目录下的背景音乐的声音设置为“AudioClip”的值,并将“Play On Awake”和“Loop ”给勾选上。这样背景声就可以循环播放
8.2、给坦克添加引擎声和销毁声
8.2.1、设置引擎声
接下来我们设置坦克引擎的声音,打开脚本“TankMovement.cs”,修改为如下内容:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TankMovement : MonoBehaviour {
private Rigidbody rb;
public int number = 1; // 通过编号区分不同坦克
public float speed = 10; //速度大小
public float angularSpeed = 10; //转向角度
public AudioClip engineDrivingAudio;
public AudioClip engineIdleAudio;
// Use this for initialization
void Start () {
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update () {
float h = Input.GetAxis("HorizontalPlayer" number);
float v = Input.GetAxis("VerticalPlayer" number);
rb.velocity = transform.forward * v * speed;
rb.angularVelocity = transform.up * h * angularSpeed;
if (Mathf.Abs(h) > 0.1 || Mathf.Abs(v) > 0.1)
{
AudioSource.PlayClipAtPoint(engineDrivingAudio, transform.position);
}
else {
AudioSource.PlayClipAtPoint(engineIdleAudio, transform.position);
}
}
}
8.2.2、设置销毁声
打开脚本文件“TankHealth.cs”并按如下内容进行修改:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TankHealth : MonoBehaviour {
public float hp = 100; // 坦克默认共有100滴血
private float hpTotal;
public GameObject tankExplosionPrefab;
private float duration = 1.05f;
public Slider slider;
public AudioClip tankExplosionAudio;
// Use this for initialization
void Start () {
hpTotal = hp;
}
// Update is called once per frame
void Update () {
}
// 坦克受到伤害
private void TankDamage() {
hp -= Random.Range(10, 20);
slider.value = hp / hpTotal;
if (hp <= 0) { // 坦克血量小于0,被干掉了
GameObject tankExplosion = Instantiate(tankExplosionPrefab, transform.position, transform.rotation) as GameObject;
Destroy(gameObject);
Destroy(tankExplosion, duration);
AudioSource.PlayClipAtPoint(tankExplosionAudio, transform.position);
}
}
}
8.3、给炮弹添加声音
8.3.1、设置炮弹的装载声
打开脚本“TankAttack.cs”,将内容修改如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TankAttack : MonoBehaviour {
public Transform firingPointTransform;
public GameObject shellPrefab;
public KeyCode firingKey = KeyCode.Space; // 开火键,默认为空格键
public AudioClip shotChargingAudio;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(firingKey)) {
Instantiate(shellPrefab, firingPointTransform.position, firingPointTransform.rotation); // 发射炮弹即实例化炮弹
AudioSource.PlayClipAtPoint(shotChargingAudio, transform.position);
}
}
}
8.3.2、设置炮弹的开火声和爆炸声
打开脚本文件“Shell.cs”,将内容修改如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Shell : MonoBehaviour {
private Rigidbody rb;
public GameObject shellExplosionPrefab;
public float shellSpeed = 15;
private float duration = 1.50f; // 爆炸动画效果持续时间
public AudioClip shellExplosionAudio;
public AudioClip shotFiringAudio;
// Use this for initialization
void Start () {
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update () {
rb.velocity = transform.forward * shellSpeed;
AudioSource.PlayClipAtPoint(shotFiringAudio, transform.position);
}
private void OnCollisionEnter(Collision collision)
{
GameObject shellExplosion = Instantiate(shellExplosionPrefab, transform.position, transform.rotation) as GameObject;
Destroy(gameObject);
Destroy(shellExplosion, duration);
AudioSource.PlayClipAtPoint(shellExplosionAudio, transform.position);
// 如果炮弹攻击到的是坦克,则对此坦克造成伤害
if (collision.collider.tag == "Tank") {
collision.collider.SendMessage("TankDamage");
}
}
}
到这里音效的设置也算告一段落了,还是要提醒一下别忘了在Unity中给相关的“AudioClip”属性赋值。然后也别忘了保存场景哦。
好了,差不多就这样吧!一个简单的坦克对战的游戏就基本开发完成了,你还可以把该游戏Build到电脑上,劲情享受自己开发的游戏带来的乐趣吧!
--END
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved