3D雷霆战机的核心功能:玩家3D飞机的控制移动、攻击等,敌人生成、移动、攻击、死亡等。

玩家3D飞机的控制移动、攻击等功能使用一个脚本或分多个脚本处理,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//可序列化 让这个Boundary类生成的对象能够在U3D中可见
[System.Serializable]
public class Boundary
{public float xMin=-6.5f;public float xMax=6.5f;public float zMin=-4.5f;public float zMax=14f;
}
public class PlayerController : MonoBehaviour {public AudioClip fire; //射击声音private AudioSource m_AudioSource;//声音源private Rigidbody m_Rigidbody;//飞机刚体组件public float speed = 10f;//飞机速度public Boundary bound;//画面界限范围public GameObject bolt;//子弹 从U3D界面直接拖动获得public Transform spawnPos;//子弹位置(U3D的特点,从外面拉进来的物体进来后会根据这个变量而强制性转换为Transform)public float fireRate = 0.01f;//发射时间间隔private float nextFire;//下次发射时间void Start(){m_Rigidbody = gameObject.GetComponent<Rigidbody>();m_AudioSource = gameObject.GetComponent<AudioSource>();}void Update(){//鼠标按下左击 若当前时间大于下一次发射时间,可以发射if (Input.GetButton("Fire1") && Time.time>nextFire){nextFire = Time.time + fireRate;//获取下一次发射时间//产生子弹位置位于飞机前方Instantiate(bolt, spawnPos.position, this.transform.rotation);//产生子弹生效m_AudioSource.PlayOneShot(fire);}}void FixedUpdate(){float h = Input.GetAxis("Horizontal");float v = Input.GetAxis("Vertical");//摄像机水平方向的大小就是x,物体的y是0,摄像机垂直方向就是物体的zVector3 move = new Vector3(h, 0f, v);//给刚体一个速度为10m的速度,方向根据W,A,S,D或方向箭头按钮而控制 m_Rigidbody.velocity=speed * move;//限制飞机的行走范围 Mathf.Clamp(value,min,max)限制value的值在min~max之间m_Rigidbody.position = new Vector3(Mathf.Clamp(m_Rigidbody.position.x,bound.xMin,bound.xMax),0,Mathf.Clamp(m_Rigidbody.position.z,bound.zMin,bound.zMax));}
}

敌人生成(孵化器)代码如下:其实是一个游戏控制器,有些许复杂稍微花点时间能看懂游戏是怎么个流程,模拟敌人生成。

using System.Collections;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
using UnityEngine;public class GameController : MonoBehaviour {public GameObject followObject;public BigShip bigShip;//BigShip脚本控制新版玩家等级public Vector3 spawnValues;//岩石出现位置public Vector3 enemyValue;//敌人出现位置public Vector3 streamBoatValue;//蒸汽船出现位置public GameObject[] hazards;//岩石种类public int[] numPerWave;//每波数目public float[] spawnWait;//小行星产生间隔时间public float startWait;//出现小行星之前的等待时间public float[] waveWait;//每两波之间的时间间隔public GameObject enemyObject;//敌人主体public GameObject streamBoat;//蒸汽船主体private int wave1 = 0;         //行星波数private int wave2 = 0;         //敌机波数public float enemyStartWait;//第一波波开始等待敌机时间public float[] enemyWaveWait;//每波敌机出现间隔public float[] enemyWaveNum;//每波敌机数量public float[] enemyWait;//每个敌机产生间隔public GUIText scoreText;//显示分数文本private int power;//记录能量private int score;//记录分数public GUIText powerText;//显示能量文本private bool gameOver;//游戏结束标志位public GUIText gameOverText;//结束游戏文本public GUIText helpText;//帮助文本public GameObject[] light;//控制灯光亮灭// Use this for initializationvoid Start () {//灯光在游戏开始的时候点亮//for (int i = 0; i < light.Length; i++)//{//    light[i].gameObject.SetActive(true);//}StartCoroutine("StreamBoat");StartCoroutine("SpawnWaves");StartCoroutine("Enemy");powerText.text = "Power: " + power;scoreText.text = "Score: " + score;gameOverText.text = "";helpText.text = "";}// Update is called once per framevoid Update () {//结束游戏而且按下了R键 就重新启动程序if (gameOver && Input.GetKeyDown(KeyCode.R)){// Application.LoadLevel(Application.loadedLevel);SceneManager.LoadScene(SceneManager.GetActiveScene().name);}}IEnumerator StreamBoat(){yield return new WaitForSeconds(15f);//15秒后登场while (true){CreateStreamBoat();yield return new WaitForSeconds(6f);//1秒出一个if (gameOver)break;}}/// <summary>/// 随机产生蒸汽船障碍物/// </summary>public void CreateStreamBoat(){Vector3 v = new Vector3(Random.Range(100f, 500f), streamBoatValue.y, Random.Range(987f, 1172f));Quaternion q = Quaternion.identity;GameObject o3=Instantiate(streamBoat, v, q) as GameObject;o3.GetComponent<Transform>().parent = followObject.GetComponent<Transform>();}/// <summary>/// 协同程序延时产生每波敌机/// </summary>/// <returns></returns>IEnumerator Enemy() {yield return new WaitForSeconds(enemyStartWait);//2秒出现后一波敌机while (true){//第一波 8次(32s)(1个/次) 第二波15次(45s)(2个/次) 第三波 25个(50s)(3个/次)for (int i = 0; i < enemyWaveNum[wave2]; i++){for(int j=0;j<=wave2;j++)CreateEnemy();yield return new WaitForSeconds(enemyWait[wave2]);//4,3,2秒出现一次敌机}//当三波都通过的时候结束游戏并且优化结束界面if (gameOver || wave2 == 2){if (wave2 == 2)GameOver();break;}yield return new WaitForSeconds(enemyWaveWait[wave2]);//0,12,8秒出现下一波 其实第三波的时间不用设置wave2++;}}/// <summary>/// 随机单个产生敌人飞机/// </summary>public void CreateEnemy(){Vector3 v = new Vector3(Random.Range(50f, 600f), enemyValue.y, Random.Range(enemyValue.z+30f, enemyValue.z + 60.0f));Quaternion q = Quaternion.identity;GameObject o = Instantiate(enemyObject, v, q) as GameObject;o.GetComponent<Transform>().parent = followObject.GetComponent<Transform>();}//IEnumberator是协同程序关键字 不要弄错了IEnumerable这个不是!!!/// <summary>/// 协同程序批量产生岩石(启动游戏2秒后执行,一波10个岩石,产生间隔是1s,每波间隔4s/// </summary>/// <returns></returns>IEnumerator SpawnWaves(){int k = 2;yield return new WaitForSeconds(startWait);//2秒后出现while (true){//第一波 10个(30)第二波 18个(54)第三波 25个(50)for (int i = 0; i < numPerWave[wave1]; i++){for(int j=0;j<=wave1+k;j++)Spawn();yield return new WaitForSeconds(spawnWait[wave1]);//3, 3 ,2}k++;//结束游戏就不再生成if (gameOver || wave1 == 2){if (wave1 == 2)GameOver();break;}yield return new WaitForSeconds(waveWait[wave1]);//2,3,4wave1++;}}/// <summary>/// 随机地产生石头/// </summary>public void Spawn(){Vector3 p = new Vector3();GameObject o = hazards[Random.Range(0, hazards.Length)];//从3种岩石中随机选一种生成if(o.gameObject.name=="Asteroid")p = new Vector3(Random.Range(150f, 600f), spawnValues.y, Random.Range(412f,450f));//生成位置随机if(o.gameObject.name=="Asteroid2")p = new Vector3(Random.Range(150f, 600f), spawnValues.y, Random.Range(505f,572f));//生成位置随机if(o.gameObject.name=="Asteroid3")p = new Vector3(Random.Range(150f, 600f), spawnValues.y, Random.Range(671f,811f));//生成位置随机Quaternion q = Quaternion.identity;//物体无旋转诞生Instantiate(o, p, q);}public void AddPower(){power++;powerText.text = "Power: " + power;if (power == 10){bigShip.LevelUp();}if (power == 30){bigShip.LevelUp();}}//显示分数和增加分数public void AddScore(int v){score += v;scoreText.text = "Score: " + score;}//显示结束界面public void GameOver(){gameOver = true ;enemyObject.GetComponent<enemyController>().EnemyOver();//敌机射击结束gameOverText.text = "Game Over!";helpText.text = "Press 'R' to Restart";}}

敌人的移动、攻击、死亡等脚本,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class enemyController : MonoBehaviour {private GameUIController gameUIController;//UI控制器private GameObject gameUIObject; //UI界面public GameObject bolt;//敌机子弹public Transform boltPos;//敌机子弹位置public GameObject playerObject;//玩家物体public float startWait;//等待敌机发射时间public float shootWait;//敌机射击间隔private Rigidbody rigidbody;//敌机刚体private Transform transform;//敌机Transformpublic float speed=15f;//敌机速度private Vector3 vector;//控制敌机左右方向的三维向量private float perSub=5f;//控制敌机左右方向的每帧移动距离private AudioSource m_AudioSource;//声音源public AudioClip fire;//敌机射击声音private bool enemyOver;//敌机子弹发射结束标志位 (一定要是private)void Start (){gameUIObject = GameObject.FindWithTag("MainCamera");gameUIController = gameUIObject.GetComponent<GameUIController>();m_AudioSource = gameObject.GetComponent<AudioSource>();StartCoroutine("CreateEnemyBolt");transform=gameObject.GetComponent<Transform>();rigidbody = gameObject.GetComponent<Rigidbody>();rigidbody.velocity = speed * transform.forward;transform.Rotate(new Vector3(0, 180, 0));}/// <summary>/// 协同程序延时产生敌机子弹直至敌机被摧毁或离开场地/// </summary>/// <returns></returns>IEnumerator CreateEnemyBolt(){yield return new WaitForSeconds(startWait);      while(true){//实例化敌机子弹EnemyBolt();//发射子弹声音//判断是否静音状态       if (!gameUIController.flag)m_AudioSource.PlayOneShot(fire);m_AudioSource.volume = gameUIController.soundValume;  yield return new WaitForSeconds(shootWait);if (enemyOver)break;}}/// <summary>/// 产生敌机子弹/// </summary>public void EnemyBolt(){GameObject o = Instantiate(bolt, boltPos.position, boltPos.rotation) as GameObject;}void FixedUpdate(){vector=new Vector3(transform.position.x+perSub,transform.position.y,transform.position.z);if (transform.position.x <= 50){    perSub = 5f;  }if (transform.position.x >= 600){  perSub = -5f;}//敌机左右移动代码                        //设置沿着y轴旋转1度transform.SetPositionAndRotation(vector,new Quaternion(0,1,0,0));}void Update () {//使敌机时刻朝向玩家transform.LookAt(playerObject.GetComponent<Transform>());//  Debug.Log(playerObject.GetComponent<Transform>());//Debug.Log(this.gameObject.transform.position);//t += 1f / 10 * Time.deltaTime;//targetObject.position = Vector3.Lerp(targetObject.position, transform.position, t);}/// <summary>/// 敌机销毁/// </summary>public void EnemyOver(){enemyOver = true;}
}

还有一个代码就是关于跟踪子弹的脚本实现如下,这个比较高级:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class FollowEnemy : MonoBehaviour
{public GameObject followObject;//跟踪目标父物体(父物体下有若干个敌人物体)public GameObject bolt3Parent;//跟踪子弹父物体(父物体下有若干个跟踪子弹物体)private Vector3 target;private float speed = 420f;private bool flag = true;private Transform transform;private Rigidbody rigidbody;/// <summary>// 实现一个跟踪子弹跟踪一个敌人效果/// </summary>void Update(){//遍历敌人(followObject是敌人的父物体,childCount是敌人总数)for (int i = 0; i < followObject.transform.childCount; i++){//当敌机下标i超出子弹下标最大值时退出循环(避免子弹数组索引溢出bug)if (i >= bolt3Parent.transform.childCount){break;}Transform enemyTransform, bolt3Transform;//获取第i个敌人transform信息enemyTransform = followObject.transform.GetChild(i);//获取第i个子弹transform信息bolt3Transform = bolt3Parent.transform.GetChild(i);//计算出子弹到敌人的单位化向量target(即目标朝向)target = (enemyTransform.position - bolt3Transform.position).normalized;//经测试a会在(0~正数无穷大)之间徘徊,当子弹自身z轴向量与目标朝向的夹角越大,a值就越小,//而当a的值小于1 /3时,说明夹角大于15°(测试得出),当大于15°时,朝向会每帧偏转(夹角* (5/夹角)=5)°朝着目标朝向偏转,也就是每帧偏转5°(这句话可能会有点难理解下面说明)//下面的这行代码的5.0f决定是5°,而夹角*(5/夹角)这个公式是因为Vector3.Slerp这个方法,它具体是怎么个原理可百度,下面我简单说下,//Slerp是会将第一个参数源向量根据第三个参数权值,目标向量是第二个参数向量,进行一次插值运算得出一个新的向量,//例如:第三个参数是1/2的话,新生成的向量就是第一个参数向量和第二个参数向量之间的中线向量,若是1的话,返回的新向量就是第二个参数向量,若为0就是第一个参数向量(也就是不变)//所以上面这些总结成数学公式可以差不多地理解为:为了生成新的向量而第一个参数向量要偏转的角度 = (第一参数和第二参数之间的)夹角 * a                        float a = 5.0f / (Vector3.Angle(bolt3Transform.forward, target));// a = 5/夹角//a<1/3就是夹角大于15°的情况(这是我测试得出的,必然正确!!!相信我!!!你也可以自己测试下)if (a < 1.0f / 3.0f){//在上方Slerp的说明可理解,下面的bolt3Transform.forward = Vector3.Slerp(bolt3Transform.forward, target, a).normalized;就相当于                //已知 a = 5 / 夹角 , 那么第一个参数向量要偏转的角度 = 夹角 * a = 夹角 * (5/夹角) = 5//最后结论是:子弹朝向blot3Transform.forward会每帧朝着目标向量target转动5度°,从而实现不断地趋向于目标朝向bolt3Transform.forward = Vector3.Slerp(bolt3Transform.forward, target, a).normalized;                }else//夹角小于等于15°{//直接朝着目标点跑,也就是子弹朝向等于target(目标朝向),这是因为第三参数是1(很明显)bolt3Transform.forward = Vector3.Slerp(bolt3Transform.forward, target, 1).normalized;}//这一步不用说了吧.bolt3Transform.position += bolt3Transform.forward * speed * Time.deltaTime;}//上面已经把能用的跟踪子弹都用了,但是可能还会有剩余的跟踪子弹,下面就是处理剩余的跟踪子弹怎么飞的问题//当子弹超出敌机数量时,保证额外的子弹能够正常向前移动if (bolt3Parent.transform.childCount > followObject.transform.childCount){//处理完没处理跟踪功能的子弹:默认向前移动for (int i = followObject.transform.childCount; i < bolt3Parent.transform.childCount; i++){transform = bolt3Parent.transform.GetChild(i);transform.position += transform.forward * speed * Time.deltaTime;}}}//总结:实现子弹与目标点角度小于等于15°时直接朝着目标点飞,而大于15°时子弹会每帧5°来调整朝向目标点飞的这么一个跟踪效果//后期会进一步完善,模拟更加现实的子弹跟踪效果,即考虑当夹角大于15°时,角度越大其每帧偏移角度也就越大,当角度越接近15°时,会不断趋向一个固定偏转角度,而不是每帧都一样的偏转角度//其实实现方法我也想到了,将夹角转变为弧度来看待这个问题,就非常简单了,算夹角的弧度公式如下://弧度= 夹角 * 2π/360 = 夹角 * Mathf.Rad2Deg,因为夹角范围[0,180]那么弧度范围[0,π],π就是3.14//假设简单点,我设置一个偏移最大角度为10°和偏移最小角度5°,那么上面 a = (弧度+π)/π * 5.0f / 夹角 ,当弧度极限为π时候,偏移角度为10°,当弧度为15度时,也就是刚好达成进入if的条件,偏移角度会比5度大一点
}

总之以上就是3D雷霆战机的核心部分的代码。

【Unity】3D雷霆战机相关推荐

  1. Unity编写雷霆战机流程(二)

    三.功能的具体实现 这里只介绍部分主要功能以及一些核心代码,其他细节可自行设计 1. 开始游戏场景: 开始游戏点击开始按钮,调用Gamanager里的公开方法,运行开始面板的动画(这里用的是DoTwe ...

  2. Unity 3D学习之雷霆战机(一)

    雷霆战机(一) 注:本文包括雷霆战机的第一部分,在没书的情况下,慢慢摸索自己真的了解到许多知识,现于初学者分享并求指教,因为自己是初学者中间可能会有许多不成熟的地方或者错误的地方,望指教.再次重申本人 ...

  3. Unity 3D学习视觉脚本无需编码即可创建高级游戏

    在本课程中,您将学习如何在Unity中使用可视化脚本(以前称为Bolt)以及如何在不编写一行代码的情况下创建自己的高级游戏所需的一切.本课程将教你如何掌握可视化脚本,即使你以前没有任何关于unity或 ...

  4. Unity三维游戏开发C#编程大师班 Masterclass In C# Programing Unity 3D Game Development FPS

    本课程采用现代游戏开发(Unity 2021)的最新内容和最新技术 学习任何东西的最好方法是以一种真正有趣的方式去做,这就是这门课程的来源.如果你想了解你看到的这些不可思议的游戏是如何制作的,没有比这 ...

  5. Unity 3D为策略游戏创建地图学习教程

    MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz,2 Ch 语言:英语+中英文字幕(根据原英文字幕机译更准确) |时长:30节课(7h 42m) |大小:5 GB 含项目文 ...

  6. Unity 3D游戏代码编程学习教程 Full Guide To Unity 3D C#: Learn To Code Making 3D Games

    Unity 3D游戏代码编程学习教程 Full Guide To Unity 3D & C#: Learn To Code Making 3D Games Full Guide To Unit ...

  7. 聊聊在博客园写博客的这两年《Unity 3D脚本编程:使用C#语言开发跨平台游戏》正式出版...

    版本状态: 2016.9 第一次印刷 (2016.11 输出到台湾) 2017.1 第二次印刷 2017.5 第三次印刷 2017.5 电子书上线:Unity 3D脚本编程--使用C#语言开发跨平台游 ...

  8. 《Unity 3.x游戏开发实例》一1.5 欢迎来到Unity 3D

    本节书摘来异步社区<Unity 3.x游戏开发实例>一书中的第1章,第1.5节,作者: [加]Ryan Henson Creighton 译者: 师蓉 责编: 陈冀康,更多章节内容可以访问 ...

  9. Unity 3D:在现有的Android游戏场景中显示AdMob的横幅

    2019独角兽企业重金招聘Python工程师标准>>> 关于如何在现有的Android项目现场显示AdMob的横幅,在一个Android项目中使用一个简单的Android JAR文件 ...

  10. Unity 3D 离线协议

    在联网状态下,获得离线协议,然后导入到Untiy的协议管理器里. 以后在断网的情况下,也能离线使用Unity. 步骤: 1.生成 Request 文件.(Unity_v5.3.1f1.alf) 1) ...

最新文章

  1. Java中的注解到底是如何工作的?
  2. python hdfs初体验
  3. [机器学习] Coursera ML笔记 - 神经网络(Representation)
  4. python调用perl_在Perl、Shell和Python中传参与输出帮助文档
  5. Python之XML解析详解
  6. TRUNCATE和DELETE有以下几点区别
  7. 笔记 编写可读性代码的艺术
  8. mysql 转int_MySQL索引凭什么能让查询效率提高这么多?
  9. Cisco ppp链路单双认证
  10. PHP 模拟库存出库商品
  11. 头歌Educoder——大数据Hadoop开发环境搭建
  12. 无线网络常用软件与工具大全
  13. 关于OBS无法捕获图像的解决方案
  14. 外卖优惠券小程序源码,美团外卖,饿了么外卖红包
  15. pngimg 可以商用吗_推荐几个个人收藏的外国高清、免费、无版权可商用的网站...
  16. GoogleTest系列:TEST_P的基本用法
  17. Button 点击没有反应
  18. 网络数据请求(unity)
  19. 《活法》读后感--发paper思想准备
  20. 2021年全球汽车安全带行业现状及未来发展趋势分析,汽车安全带增长基本同步汽车行业增长「图」

热门文章

  1. 2022年高压电工操作证考试题库及答案
  2. background-size属性详解
  3. java作业中数据分析与设计_Java课程设计——博客作业教学数据分析系统(201521123091 李嘉廉)...
  4. 如何精简ttf字库文件
  5. 服务器503网页报错,网页为什么出现503错误?网页503错误的解决方法
  6. GEE学习笔记 七十七:GEE学习方法简介
  7. 密码箱忘记密码解决方法
  8. 高拍仪拍照SDK开发(良田影像S300L|S500L)
  9. android开发教程 电驴资源下载地址分享
  10. IB心理学社会文化介绍