知识屋:更实用的电脑技术知识网站
所在位置:首页 > 综合

Unity 3D游戏编程自学#6——简单射击案例

发表时间:2022-03-25来源:网络

游戏简介:一个只能移动枪口的射击游戏,敌人会在前方场景随机生成,需要玩家在20秒的时间内尽可能多地开枪击杀。

1.枪支随鼠标移动

先导入网上找到的场景模型、枪支模型(网上找来的免费资源,感谢网友!),如图:

然后对枪编写脚本:

为方便就不事先获得枪支的Transform引用,直接gameObject.GetComponent调用Transform组件下的LookAt方法,该方法可使枪向射线与场景碰撞点处调整方向,因此事先要将为场景模型添加Mesh Collider,也因此在游戏测试时如果将鼠标指向天空等无碰撞体的地方,枪支则不会移动。(可通过在背景处创建一个蓝色的Plane当作天空来解决此问题)

在为场景模型添加碰撞体时,有时候会有多种碰撞体可选,因为这里我们要碰撞体仅仅是为了得到一个碰撞点令枪可以移动,所以可以选择简单一些的碰撞体模型,一般碰撞体的复杂程度可由上图中的verts(顶点)来确定,顶点越少,计算量越小,游戏运行越流畅。

注意:测试时可能会发现枪支随鼠标的旋转很不自然(绕着枪中心处旋转),现实中应该是绕着射手的肩膀旋转,因此应将旋转中心设置在枪的后部,这可以通过创建空物体以及父子关系来调整。因此以上脚本应该挂载到作为父物体的空物体上:

 

2. 枪支红点效果

在gun父物体下再创建一个空物体RedPoint,位置设置在枪口(因为红光是从枪口射出的,不是从枪中间射出的),并为其添加Line Renderer组件,设置好其颜色、宽度。(具体步骤上文“线特效”处有提到)

然后补充脚本:

private Ray ray; private RaycastHit hit; private Transform gunTransform; private Transform pointTransform; private LineRenderer rayLineRenderer; void Start() { gunTransform = gameObject.GetComponent(); pointTransform = gunTransform.FindChild("RedPoint"); rayLineRenderer = pointTransform.gameObject.GetComponent(); } void Update() { ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray,out hit)) { gunTransform.LookAt(hit.point); rayLineRenderer.SetPosition(0, pointTransform.position); rayLineRenderer.SetPosition(1, hit.point); } }

这里要通过gun下面的子物体RedPoint生成红光,但脚本是挂载在gun上的,因此要通过FindChild方法得到RedPoint及其LineRenderer组件的引用。

最后通过SetPosition绘制红线,这里有两个参数,第一个是射线经过的路程上的拐点的索引,第二个是位置。脚本中设置了两个拐点(其实就是一条线段,如果有三个不在同一直线上的拐点,则红线由两条线段组成),最终效果:

 

3.敌人生成与击倒

导入僵尸模型,调整其大小,并为其及其所有零部件(子物体)的标签设置为Zombie。

因为模型本身没有自带碰撞体组件,需要手动添加,因为本人使用的模型过于复杂(还有动画效果),因此仅对父物体添加一个胶囊型的碰撞体(覆盖其头部与身体)。考虑到其动画会使其向前稍微移动,因此碰撞体的位置靠前一些。

然后编写脚本:(接在rayLineRenderer.SetPosition后面)

if (hit.collider.tag == "Zombie" && Input.GetMouseButtonDown(0)) { zombieTransform = hit.collider.gameObject.GetComponent(); zombieTransform.Rotate(Vector3.left, 90); GameObject.Destroy(hit.collider.gameObject, 2); }

当向鼠标指向处发射的射线碰撞到的是僵尸,且按下鼠标左键(开火),则首先获取到僵尸的Transform组件的引用,然后旋转(击倒效果),并在2秒后销毁该物体。

如果有较好的模型,可对模型的所有零部件(子物体)添加碰撞体,则脚本应该为:(接在rayLineRenderer.SetPosition后面)

if (hit.collider.tag == "Zombie" && Input.GetMouseButtonDown(0)) { Transform zombieParent = hit.collider.gameObject.GetComponent().parent; Transform[] zombie = zombieParent.GetComponentsInChildren(); for (int i = 0; i (); } zombieParent.Rotate(Vector3.left, 90); GameObject.Destroy(zombieParent.gameObject, 2); }

因为碰撞到的是模型的子物体,所以通过.parent得到父物体的Transform组件,进而通过GetComponentsInChildren得到所有零部件的Transform组件,最后通过循环对所有子物体添加Rigidbody,这样一来,僵尸会“四分五裂”,一方面因为重力,另一方面是因为各个子物体间的碰撞体有重合,添加Rigidbody后各部分会自发散开。

接下来新建一个实例化僵尸的脚本:

public GameObject prefabZombie; float i = 0; void Update() { if (i>1) { Vector3 position = new Vector3(Random.Range(-35,0),2.6f,Random.Range(-10,-5)); GameObject.Instantiate(prefabZombie, position, .identity); i = 0; } i += Time.deltaTime; }

在合适的区域每秒生成一个僵尸,这里用累加Time.deltaTime的方式实现每秒执行,也可以用Invoke函数实现。

为了方便管理生成的僵尸,我们可以将所有生成的僵尸设置为一个空物体的子物体:

public GameObject prefabZombie; public Transform zombieControler; void Start() { zombieControler = gameObject.GetComponent(); InvokeRepeating("Creat", 1, 1); } void Creat() { Vector3 position = new Vector3(Random.Range(-35, 0), 2.6f, Random.Range(-10, -5)); GameObject.Instantiate(prefabZombie, position, .identity); newZombie.GetComponent().SetParent(zombieControler); }

用SetParent方法即可实现,最后将该脚本挂载到空物体ZombieControler上即可。

 

4. 音效及界面UI

添加开枪音效:

private AudioSource gunSound; void Start() { gunSound = gameObject.GetComponent(); } ... if (Input.GetMouseButtonDown(0)) { gunSound.Play(); if (hit.collider.tag == "Zombie") { ... } }

然后为挂载以上脚本的枪支模型添加Audio Source组件,选择合适的开枪音效即可。(注意不要勾选Play On Awake和Loop)

接下来创建UI界面,先将游戏分为三个状态:开始、游戏中以及结束,并编辑对应的UI(创建空物体,添加GUIText组件并调整文字位置、大小、颜色),以下是UI叠加在一起的Game界面:

                     

开始界面要有游戏玩法的基本介绍以及“开始游戏”的按钮,游戏中需要显示分数以及剩余时间,游戏结束需要分数统计、“重新开始”按钮和“退出游戏”按钮。

接下来对父物体UI,创建脚本:

首先编辑一个控制游戏状态的方法(这里采用枚举类型,主要是为了直观,要我写可能就用0、1、2来表示了)。

并将UI在某状态是否显示进行规定:(类似的就省略不写了)

public enum GameState { Start, Gaming, End } private GameObject startUI; ... void Start() { startUI = GameObject.Find("Start"); ... ChangeState(GameState.Start); } public void ChangeState(GameState state) { if (state==GameState.Start) { startUI.SetActive(true); gamingUI.SetActive(false); endUI.SetActive(false); ... } if (state == GameState.Gaming) { ... } if (state == GameState.End) { ... } }

这里需要注意的是ChangeState要为public,因为其他脚本的一些操作也会改变游戏状态。(例如点击开始游戏按钮)

接下来编辑“开始游戏”按钮,以下脚本挂载在“StartSign”:

private UIContorl uiContorl; void Start() { uiContorl = GameObject.Find("UI").GetComponent(); } void OnMouseDown() { uiContorl.ChangeState(UIContorl.GameState.Gaming); }

首先查找到父物体UI挂载的脚本中的ChangeState方法,只要MouseDown就改变游戏状态。

同理可设置重新开始按钮和退出按钮,其中退出按钮极为简单:

void OnMouseDown() { Application.Quit(); }

 

5. 分数、时间显示及部分细节

当在游戏开始和结束状态时,枪支无法移动,因此要对Move脚本进行编辑:

public void ChangeGunMove(bool state) { f = state; } void Update() { if (f) { ... } }

然后在ChangeState方法中的对应阶段设置state为true或false即可。

开始和结束阶段僵尸也无法生成,因此Invoke不能写在Start里面,更改CreateZombie脚本:(以下为CreateZombie脚本的完整版)

在ChangeState的Gaming状态下调用CreateZombie即可,另外,在游戏结束时,除了要CancelInvoke,还要把玩家未消灭的僵尸清除。

接下来要在Gaming中显示分数,在UIControl脚本中添加:

public void AddScore() { score++; scoreText.text = "击杀数:"+score; }

然后在Move脚本中添加:

if (hit.collider.tag == "Zombie") { uiContorl.AddScore(); ... }

每次进入到Gaming状态,要重置分数,在结束状态也要再显示一次分数:

if (state == GameState.Gaming) { score = 0; scoreText.text = "击杀数:" + score; ... } if (state == GameState.End) { finalScore.text = "最终击杀数:" + score; ... }

接下来显示剩余时间,在UIControl脚本中添加:

void Update() { if (startTime) { time -= Time.deltaTime; timeText.text = "剩余时间:" + Math.Round(time, 2); if (time

startTime为bool类型,因为Update时刻运行,因此添加该变量确保倒计时只在Gaming状态下运行。

if (state == GameState.Gaming) { startTime = true; time = 20; ... }

至此全部脚本编写完毕。

 

6. 效果及源代码

Game界面:

Build后运行结果:(分别是开始界面、游戏界面、结束界面)

原谅我懒得细调开始和结束UI的位置……

最后放出Move脚本:

UIControll脚本:

最后提醒:

做项目前一定要仔细规划(游戏阶段划分、资源模型的管理、脚本,尤其是各种变量名编写一定要注意,我在写的时候差点被自己编的变量名绕晕),此外还有脚本中各个变量的访问修饰符(public还是private一定要搞清楚)。

实际上,如果是个人开发,变量全写public也可以,但这并不是什么好习惯,尤其是在日后团队协作全写public就是坑队友嘛,所以建议现在开始就养成好习惯,细究public和private。

 

本文部分内容来自擅码网(http://www.mkcode.net)Unity 3D课程,经本人学习、整理得来,若有错漏,欢迎指正!

收藏

热门推荐

  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜