news 2025/12/28 7:43:23

Unity教学 项目3 3D坦克大战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Unity教学 项目3 3D坦克大战

视频教程:

https://www.bilibili.com/video/BV11D5QzgEpw?spm_id_from=333.788.videopod.sections&vd_source=25b783f5f945c4507229e9dec657b5bb

1. 场景搭建

  1. 创建工程文件
  2. 素材导入
  3. 将游戏场景预制体实例化
  4. 设置场景光颜色为(29, 26, 00)

  1. 设置天空颜色为(128, 110, 36)

  1. 设置 camera 位置为(-31, 25, -20)
  2. 设置 camera 旋转角度为(37, 53, 6)
  3. 设置 camera 为正交视野,Size 为 8

正交投影:常用于 2D 游戏开发、UI 设计、建筑图纸绘制等,这些场景更关注物体实际尺寸和相对位置,不需要模拟真实 3D 空间深度感。比如 2D 横版过关游戏,正交投影能保证角色和场景元素大小一致,便于玩家把握距离和位置 。

透视投影:广泛用于 3D 游戏、虚拟现实(VR)和增强现实(AR)等场景,能营造逼真空间感和深度感,让玩家有身临其境的体验。如第一人称射击游戏,通过透视投影呈现真实远近效果,增强沉浸感。

2. 移动旋转

  1. 创建坦克实例

  2. 将烟拖动到坦克上,设置位置为(0.6, 0, -0.94)和(-0.5, 0, -0.94)

  3. 坦克添加刚体组件

  4. 坦克添加碰撞盒子,设置位置为(0, 0.95, 0),大小为(1.51, 1.71, 1.62)

    1. 注意:碰撞盒子不能紧挨地面,容易检测坦克与地面发生碰撞导致坦克无法移动。
  5. 将坦克做成预制体

  6. 创建脚本文件 Tank.cs

  7. 添加脚本,实现坦克的前后移动功能

  8. 约束刚体部分轴,位置冻结 Y 轴,旋转冻结 X 和 Z 轴

  1. 添加脚本,实现坦克旋转功能

2.1. Tank.cs

usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassTank:MonoBehaviour{publicfloatmoveSpeed;publicfloatangularSpeed;privateRigidbodyrb;// Start is called before the first frame updatevoidStart(){rb=GetComponent<Rigidbody>();}// Update is called once per framevoidUpdate(){}privatevoidFixedUpdate(){Move();}/// <summary>/// 移动/// </summary>voidMove(){floatv=Input.GetAxis("Vertical");floath=Input.GetAxis("Horizontal");rb.velocity=transform.forward*v*moveSpeed;rb.angularVelocity=transform.up*h*angularSpeed;}}

3. 两个玩家控制

进入输入设置

  1. 复制 Horizontal 轴
  2. 修改 Horizontal 控制按键
  3. 复制 Vertical 轴
  4. 修改 Vertical 控制按键

  1. 修改代码,实现通过编号区分不同的控制

3.1. Tank.cs

usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassTank:MonoBehaviour{publicfloatmoveSpeed;publicfloatangularSpeed;publicintplayerNum;privateRigidbodyrb;// Start is called before the first frame updatevoidStart(){rb=GetComponent<Rigidbody>();}// Update is called once per framevoidUpdate(){}privatevoidFixedUpdate(){Move();}/// <summary>/// 移动/// </summary>voidMove(){floatv=Input.GetAxis("VerticalP"+playerNum);floath=Input.GetAxis("HorizontalP"+playerNum);rb.velocity=transform.forward*v*moveSpeed;rb.angularVelocity=transform.up*h*angularSpeed;}}

4. 发射炮弹

子弹、爆炸预设体,发射位置,脚本

子弹预设体

爆炸预设体

4.1. PreShell.cs

usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassPreShell:MonoBehaviour{publicfloatspeed=2f;publicGameObjectpreShellExplosionGo;privateRigidbodyrb;// Start is called before the first frame updatevoidStart(){rb=GetComponent<Rigidbody>();rb.velocity=transform.forward*speed;}// Update is called once per framevoidUpdate(){}privatevoidOnCollisionEnter(Collisioncollision){GameObjectshellExplosionGo=Instantiate(preShellExplosionGo,transform.position,transform.rotation);Destroy(gameObject);Destroy(shellExplosionGo.gameObject,1.5f);}}

4.2. Tank.cs

usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassTank:MonoBehaviour{publicfloatmoveSpeed;publicfloatangularSpeed;publicintplayerNum;publicKeyCodeattackKey;publicTransformshootPointTr;publicGameObjectpreShellGo;privateRigidbodyrb;// Start is called before the first frame updatevoidStart(){rb=GetComponent<Rigidbody>();attackKey=KeyCode.Space;}// Update is called once per framevoidUpdate(){if(Input.GetKeyDown(attackKey)){Shoot();}}privatevoidFixedUpdate(){Move();}/// <summary>/// 移动/// </summary>voidMove(){floatv=Input.GetAxis("VerticalP"+playerNum);floath=Input.GetAxis("HorizontalP"+playerNum);rb.velocity=transform.forward*v*moveSpeed;rb.angularVelocity=transform.up*h*angularSpeed;}/// <summary>/// 攻击/// </summary>voidShoot(){GameObjectshellGo=Instantiate(preShellGo,shootPointTr.position,shootPointTr.rotation);//shellGo.GetComponent<Rigidbody>().velocity = shellGo.transform.forward * 5;}}

5. 产生伤害

5.1. PreShell.cs

usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassPreShell:MonoBehaviour{publicfloatspeed=2f;publicGameObjectpreShellExplosionGo;privateRigidbodyrb;// Start is called before the first frame updatevoidStart(){rb=GetComponent<Rigidbody>();rb.velocity=transform.forward*speed;}// Update is called once per framevoidUpdate(){}privatevoidOnCollisionEnter(Collisioncollision){GameObjectshellExplosionGo=Instantiate(preShellExplosionGo,transform.position,transform.rotation);Destroy(gameObject);Destroy(shellExplosionGo.gameObject,1.5f);//造成伤害Tanktank=collision.gameObject.GetComponent<Tank>();if(tank==null)return;tank.currentBlood-=10;//死亡if(tank.currentBlood<0){tank.currentBlood=0;Destroy(collision.gameObject);}}}

5.2. Tank.cs

usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassTank:MonoBehaviour{publicfloatmoveSpeed;publicfloatangularSpeed;publicintplayerNum;publicintcurrentBlood;publicintmaxBlood=100;publicKeyCodeattackKey;publicTransformshootPointTr;publicGameObjectpreShellGo;privateRigidbodyrb;// Start is called before the first frame updatevoidStart(){rb=GetComponent<Rigidbody>();attackKey=KeyCode.Space;currentBlood=maxBlood;}// Update is called once per framevoidUpdate(){if(playerNum==1&&Input.GetKeyDown(attackKey)){Shoot();}elseif(playerNum==2&&Input.GetKeyDown(KeyCode.Keypad9)){Shoot();}}privatevoidFixedUpdate(){Move();}/// <summary>/// 移动/// </summary>voidMove(){floatv=Input.GetAxis("VerticalP"+playerNum);floath=Input.GetAxis("HorizontalP"+playerNum);rb.velocity=transform.forward*v*moveSpeed;rb.angularVelocity=transform.up*h*angularSpeed;}/// <summary>/// 攻击/// </summary>voidShoot(){GameObjectshellGo=Instantiate(preShellGo,shootPointTr.position,shootPointTr.rotation);//shellGo.GetComponent<Rigidbody>().velocity = shellGo.transform.forward * 5;}}

6. 摄像机跟随坦克

6.1. MainCamera.cs

usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassMainCamera:MonoBehaviour{publicTransformtank1;// 第一辆坦克的TransformpublicTransformtank2;// 第二辆坦克的TransformprivateVector3offset;// 摄像机相对于两辆坦克中心的偏移量privateCameramainCamera;// 主摄像机组件privatefloatdistance;// 两辆坦克之间的距离privatefloatcameraSize;// 正交摄像机的尺寸// Start is called before the first frame updatevoidStart(){// 检查是否正确赋值了两个坦克的Transformif(tank1==null||tank2==null)return;// 计算摄像机的初始偏移量Vector3tanksCenter=(tank1.position+tank2.position)/2;offset=transform.position-tanksCenter;// 获取主摄像机组件mainCamera=GetComponent<Camera>();}// Update is called once per framevoidUpdate(){// 如果任意一个坦克不存在,则直接返回if(tank1==null||tank2==null)return;// 更新摄像机的位置Vector3tanksCenter=(tank1.position+tank2.position)/2;transform.position=tanksCenter+offset;// 计算两辆坦克之间的距离distance=Vector3.Distance(tank1.position,tank2.position);// 根据距离调整摄像机的正交尺寸cameraSize=distance*0.875f;mainCamera.orthographicSize=cameraSize;}}

7. 添加血条

7.1. 设置血条物体

新增血条物体

设置 Canvas

设置 Slider

设置 Background

设置 Fill

7.2. 编写代码

7.2.1. PreShell.cs

usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassPreShell:MonoBehaviour{publicfloatspeed=5f;//速度publicintdamage=10;//伤害值publicGameObjectpreShellExplosionGo;//爆炸预设体对象privateRigidbodyrb;//刚体// Start is called before the first frame updatevoidStart(){rb=GetComponent<Rigidbody>();rb.velocity=transform.forward*speed;}// Update is called once per framevoidUpdate(){}/// <summary>/// 碰撞则产生爆炸并自我销毁/// </summary>/// <param name="collision"></param>privatevoidOnCollisionEnter(Collisioncollision){GameObjectshellExplosionGo=Instantiate(preShellExplosionGo,transform.position,transform.rotation);//生成爆炸效果Destroy(gameObject);//销毁炮弹Destroy(shellExplosionGo,1.5f);//销毁爆炸效果Tanktank=collision.gameObject.GetComponent<Tank>();if(tank!=null){tank.currentBlood-=damage;//造成了伤害tank.hpSlider.value=(float)tank.currentBlood/tank.maxBlood;//更新血量滑动条if(tank.currentBlood<=0)Destroy(collision.gameObject);//销毁坦克}}}

7.2.2. Tank.cs

usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;usingUnityEngine.UI;publicclassTank:MonoBehaviour{publicfloatmoveSpeed=5f;//移动速度publicfloatangularSpeed=2f;//旋转角度publicintplayerNum=1;//玩家编号publicintcurrentBlood;//当前血量publicintmaxBlood=100;//最大血量publicGameObjectpreShellGo;//炮弹预设游戏对象publicSliderhpSlider;//血量滑动条privateTransformshootPoint;//发射位置privateRigidbodyrb;//刚体// Start is called before the first frame updatevoidStart(){currentBlood=maxBlood;rb=GetComponent<Rigidbody>();shootPoint=transform.Find("ShootPoint");}// Update is called once per framevoidUpdate(){//如果按下空格键则发射炮弹if(playerNum==1&&Input.GetKeyDown(KeyCode.Space)){Shoot();}elseif(playerNum==2&&Input.GetKeyDown(KeyCode.P)){Shoot();}}privatevoidFixedUpdate(){Move();}/// <summary>/// 移动/// </summary>privatevoidMove(){floatv=Input.GetAxis("VerticalP"+playerNum);floath=Input.GetAxis("HorizontalP"+playerNum);rb.velocity=transform.forward*v*moveSpeed;//前后移动rb.angularVelocity=transform.up*h*angularSpeed;//左右旋转}/// <summary>/// 发射炮弹/// </summary>privatevoidShoot(){Instantiate(preShellGo,shootPoint.position,shootPoint.rotation);}}

7.2.3. MainCamera.cs

usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassMainCamera:MonoBehaviour{publicTransformtank1;// 第一辆坦克的TransformpublicTransformtank2;// 第二辆坦克的TransformprivateVector3offset;// 摄像机相对于两辆坦克中心的偏移量privateCameramainCamera;// 主摄像机组件privatefloatdistance;// 两辆坦克之间的距离privatefloatcameraSize;// 正交摄像机的尺寸// Start is called before the first frame updatevoidStart(){// 检查是否正确赋值了两个坦克的Transformif(tank1==null||tank2==null)return;// 计算摄像机的初始偏移量Vector3tanksCenter=(tank1.position+tank2.position)/2;offset=transform.position-tanksCenter;// 获取主摄像机组件mainCamera=GetComponent<Camera>();}// Update is called once per framevoidUpdate(){// 如果任意一个坦克不存在,则直接返回if(tank1==null||tank2==null)return;// 更新摄像机的位置Vector3tanksCenter=(tank1.position+tank2.position)/2;transform.position=tanksCenter+offset;// 计算两辆坦克之间的距离distance=Vector3.Distance(tank1.position,tank2.position);// 根据距离调整摄像机的正交尺寸cameraSize=distance*0.875f;mainCamera.orthographicSize=cameraSize;}}

7.3. 少量细节

8. 音效

8.1. 坦克静止、行驶音效

调正摄像机位置靠近坦克,使摄像机录制到坦克音效

8.2. 坦克销毁音效

8.3. 炮弹发射音效

8.4. 炮弹爆炸音效

8.5. 背景音乐

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/28 4:47:53

Neovim代码补全终极指南:极速配置与智能提示

Neovim代码补全终极指南&#xff1a;极速配置与智能提示 【免费下载链接】neovim 一个基于 Vim 编辑器的衍生版本&#xff0c;其主要改进和优化方向是提升编辑器的扩展能力和用户使用体验。 项目地址: https://gitcode.com/GitHub_Trending/ne/neovim 想要在Neovim中享受…

作者头像 李华
网站建设 2025/12/22 23:35:06

【Kubernetes】使用Helm简化k8s部署、管理

确定你安装版本的安全配置安装和配置Helm。安装HelmmacOSbrew install helmWindowschoco install kubernetes-helmDebian/Ubuntusudo apt-get install curl gpg apt-transport-https --yescurl -fsSL https://packages.buildkite.com/helm-linux/helm-debian/gpgkey | gpg --de…

作者头像 李华
网站建设 2025/12/27 22:18:58

零基础也能搭建企业官网:Halo开源建站工具实战指南

你是否在为创业初期的线上形象而烦恼&#xff1f;面对高昂的SaaS建站费用和技术门槛&#xff0c;很多创业者望而却步。本文将通过Halo开源建站工具&#xff0c;为你提供一套完整的解决方案&#xff0c;让你在30分钟内搭建专业企业官网&#xff0c;实现零成本起步。 【免费下载链…

作者头像 李华
网站建设 2025/12/25 22:33:44

Open-SaaS邮件系统性能优化实战:构建高并发异步处理架构

Open-SaaS邮件系统性能优化实战&#xff1a;构建高并发异步处理架构 【免费下载链接】open-saas A free, open-source SaaS app starter for React & Node.js with superpowers. Production-ready. Community-driven. 项目地址: https://gitcode.com/GitHub_Trending/op/…

作者头像 李华
网站建设 2025/12/27 13:25:00

基于vue的考研信息共享平台_a5a399ip_springboot php python nodejs

目录具体实现截图项目介绍论文大纲核心代码部分展示项目运行指导结论源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作具体实现截图 本系统&#xff08;程序源码数据库调试部署讲解&#xff09;同时还支持java、ThinkPHP、Node.js、Spring B…

作者头像 李华
网站建设 2025/12/25 11:56:36

ROAPI零代码API构建完整指南:从入门到实战

ROAPI零代码API构建完整指南&#xff1a;从入门到实战 【免费下载链接】roapi Create full-fledged APIs for slowly moving datasets without writing a single line of code. 项目地址: https://gitcode.com/gh_mirrors/ro/roapi 你是否曾为数据文件创建API而烦恼&…

作者头像 李华