当前位置: 首页 > article >正文

Unity百游修炼(3)——Tank_Battle(双人对战)详细制作全流程

一.项目简介

        《Tank_Battle》是一款基于 Unity 引擎开发的 3D 双人对战坦克游戏。玩家在游戏中操控各自的坦克,通过灵活移动、旋转和发射子弹等操作,展开激烈的对战,旨在摧毁对方坦克以获得胜利。该项目结合了丰富的游戏元素和交互机制,为玩家带来沉浸式的游戏体验。

游戏画面如下:

Tank_battle


二.创建场景

1.创建3D工程(命名为Tank_Battle)

2.导入unity_package(资源包)到Project窗口中(资源在素材里面)

3.将文件夹Prefab中levelart场景)拖入到hierarchy窗口中

4.删除场景自带的直射光,因为levelart中自带了直射光

5.调节场景光线:Window——Reddering——Lighting——Environmentsource光源调成color颜色,颜色调成和环境贴合的颜色

6.Main camera改变天空场景颜色


三.添加坦克(加拖尾特效)

1.把models中Tank拖放到Hierarchy视图中

2.把prefab中的DustTrall拖入到Tank上,复制一个,选中两个拖尾,分别将两个拖尾移动到轮子履带处

3.拖尾位置如下

4.给tank添加Box collider组件

5.调节collider的大小

6.把tank变成prefab,直接把tank拖到Projectors——Prefab文件夹中(为了后面坦克多了统一管理)


四.控制坦克前后移动

1.创建控制坦克移动的脚本并命名为Tank_ Move(记得创建一个Scripst文件夹统一管理脚本)

2.选择Tank,添加刚体组件Rigidbody

3.进入Tank_Move脚本

4.获取Tank本身Rigidbody组件

4.1创建刚体变量,保存

public class TankMove : MonoBehaviour
{
    public Rigidbody Tank_body;//创建刚体变量接受Tank的刚体
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

4.2把脚本拖放到Tank身上,然后把Tank脚本的Tank_body变量指定为Tank本身的Rigidbody

5.按键控制tank前后移动

5.1按键ws控制移动

5.2检测按键ws按下并保存按下的返回值

 Input.GetAxisRaw();作用是:检测是否有按键按下,并返回float值

"Vertical"作用是:竖直方向
 

5.3按键使得坦克向前或者向后移动

transform.forward 的含义

     方向表示:它是一个三维向量(Vector3 类型),指向游戏对象所面向的正前方。这个方向是相对于游戏对象的旋转而言的,当游戏对象的旋转发生改变时,transform.forward 的方向也会随之改变


五.控制坦克旋转

1.按键ad控制旋转

2.检测按键ad按下并保存按下的返回值

3.绕Y轴移动

        这行代码的主要功能是设置坦克刚体(Tank_body)的角速度,从而让坦克绕着轴进行旋转。旋转的轴是游戏对象自身的向上方向(transform.up),即Y轴,旋转的速度由 r 和 TankRotate_Speed 共同决定。

4.完整代码展现


六.控制两辆坦克(实现双人一起玩)

1.打开Edit——Projectsettings——input Manger

2.保证ad只控制Player1的旋转,左右箭头只控制Player2的旋转

2.1光标放到Horizontal上,右击创建两个新的Horizontal,分别命名为Horizontal_Player1,Horizontal_Player2

2.2玩家一删除下图圈出来的内容,表示取消左右箭头控制前进

2.3玩家二删除下图圈出来的内容,表示取消ad按键控制旋转

3.保证ws只控制Player1的前进后退,上下箭头只控制Player2的前进后退

3.1光标放到Vertical上,右击创建两个新的Vertical,分别命名为Vertical_Player1,Vertical_Player2

3.2玩家一删除下图圈出来的内容,表示取消上下箭头控制前进

3.3玩家二删除下图圈出来的内容,表示取消ws按键控制旋转


七.控制坦克发射子弹

1.将子弹创建出来,并实例化

1.1将子弹素材拖入到Hierarchy中,并拖入Prefab成为预制体,并添加胶囊碰撞器

1.2修改碰撞体大小(记得按下图操作,一定要改成z轴)

1.3实例化子弹——确定位置。创建一个空物体,用来确定子弹发射位置,空物体是倾斜的(因为炮管是倾斜的),命名为fireposition

2.添加子弹攻击脚本Tank_Shoot——实例化子弹

2.1创建脚本

2.2创建变量接受位置,同时选中每次创建的子弹

 public Transform firePosition;//接受发射子弹的位置物体
 public GameObject ShellPrefab;//接受每次创建的实例化子弹

2.3把脚本拖到发射位置物体上,然后把发射位置和发射的子弹预制体选中

2.4把发射位置物体,拖到Tank物体上,作为其子对象,这样就可以保证相对位置不变了

2.5空格键控制子弹发射

2.6控制子弹飞行速度

八.子弹爆炸效果

1.创建子弹脚本Sheet

2.接受爆炸效果的预制体

3.当子弹触发器触碰到其他物体时,触发爆炸效果

4.我增加了一个开火也可以有爆炸效果,模仿后坐力很大

九.控制子弹造成伤害

1.给tank加tag标签,区分子弹是否触碰到了tank

2.写脚本——tank受到伤害处理的脚本

public class Tank_health : MonoBehaviour
{
    public int hp = 100;//坦克血量
    public GameObject Tankbaozha;//坦克爆炸效果
    public AudioSource TankbaozhaAudioSource;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    void HurtHealthy()
    {
        if (hp < 0)
        {
            return;
        }
        hp -= Random.Range(10, 20);//伤害是随机的 10  20
        if (hp < 0)//坦克没了
        {
            TankbaozhaAudioSource.Play();
            GameObject.Instantiate(Tankbaozha,transform.position+Vector3.up,transform.rotation);
            GameObject.Destroy(this.gameObject);
#if UNITY_EDITOR
            UnityEditor.EditorApplication.isPlaying = false;
#else
                Application.Quit();
#endif
        }
    }

3.tank触发到tank,调用2中生成的脚本

 public void OnTriggerEnter(Collider other)
 {
     if (SheelExplosionPrefab != null)
     {
         GameObject.Instantiate(SheelExplosionPrefab, transform.position, transform.rotation);
     }
     if(other.tag=="Tank")
     {
         other.SendMessage("HurtHealthy");//即调用的方法
     }
 }

十.相机跟随

原理:相机与两坦克的中心保持一定的向量关系,同时还有近大远小的视觉效果

1.算出两坦克的中心点与摄像机坐标的向量差。

2.保证摄像机始终与中心点有个相同向量差

3.当坦克间距变小时,摄像头视角变小;反之,摄像头变大


十一.添加音效,音乐

1.背景音乐

(1)创建一个空物体,命名为:Music

(2)在空物体上添加组件audio source

(3)在组件上添加背景音乐

(4)进行基础设置即可

2.子弹音效:每次发射都会启动
原理:一样的添加audio source组件用来存储音效,每次在实例化子弹的时候,启动音效

十二.问题

1.可能出现的问题1:Assembly-CSharp-Editor渲染函数老旧过时了。

解决方案:更换函数,下面是更换之后的代码:(复制粘贴即可)

using System;
using UnityEditor;
using UnityEngine;

namespace UnityStandardAssets.ImageEffects
{
    [CustomEditor(typeof(ColorCorrectionLookup))]
    class ColorCorrectionLookupEditor : Editor
    {
        SerializedObject serObj;

        void OnEnable()
        {
            serObj = new SerializedObject(target);
        }

        private Texture2D tempClutTex2D;


        public override void OnInspectorGUI()
        {
            serObj.Update();

            EditorGUILayout.LabelField("Converts textures into color lookup volumes (for grading)", EditorStyles.miniLabel);

            //EditorGUILayout.LabelField("Change Lookup Texture (LUT):");
            //EditorGUILayout.BeginHorizontal ();
            //Rect r = GUILayoutUtility.GetAspectRect(1.0ff);

            Rect r; Texture2D t;

            //EditorGUILayout.Space();
            tempClutTex2D = EditorGUILayout.ObjectField(" Based on", tempClutTex2D, typeof(Texture2D), false) as Texture2D;
            if (tempClutTex2D == null)
            {
                t = AssetDatabase.LoadMainAssetAtPath(((ColorCorrectionLookup)target).basedOnTempTex) as Texture2D;
                if (t) tempClutTex2D = t;
            }

            Texture2D tex = tempClutTex2D;

            if (tex && (target as ColorCorrectionLookup).basedOnTempTex != AssetDatabase.GetAssetPath(tex))
            {
                EditorGUILayout.Separator();
                if (!(target as ColorCorrectionLookup).ValidDimensions(tex))
                {
                    EditorGUILayout.HelpBox("Invalid texture dimensions!\nPick another texture or adjust dimension to e.g. 256x16.", MessageType.Warning);
                }
                else if (GUILayout.Button("Convert and Apply"))
                {
                    string path = AssetDatabase.GetAssetPath(tex);
                    TextureImporter textureImporter = AssetImporter.GetAtPath(path) as TextureImporter;
                    bool doImport = textureImporter.isReadable == false;
                    if (textureImporter.mipmapEnabled == true)
                    {
                        doImport = true;
                    }
                    // 修改:检查纹理压缩格式
                    if (textureImporter.textureCompression != TextureImporterCompression.Uncompressed)
                    {
                        doImport = true;
                    }

                    if (doImport)
                    {
                        textureImporter.isReadable = true;
                        textureImporter.mipmapEnabled = false;
                        // 修改:设置纹理压缩格式为无压缩
                        textureImporter.textureCompression = TextureImporterCompression.Uncompressed;
                        AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
                        //tex = AssetDatabase.LoadMainAssetAtPath(path);
                    }

                    (target as ColorCorrectionLookup).Convert(tex, path);
                }
            }

            if ((target as ColorCorrectionLookup).basedOnTempTex != "")
            {
                EditorGUILayout.HelpBox("Using " + (target as ColorCorrectionLookup).basedOnTempTex, MessageType.Info);
                t = AssetDatabase.LoadMainAssetAtPath(((ColorCorrectionLookup)target).basedOnTempTex) as Texture2D;
                if (t)
                {
                    r = GUILayoutUtility.GetLastRect();
                    r = GUILayoutUtility.GetRect(r.width, 20);
                    r.x += r.width * 0.05f / 2.0f;
                    r.width *= 0.95f;
                    GUI.DrawTexture(r, t);
                    GUILayoutUtility.GetRect(r.width, 4);
                }
            }

            //EditorGUILayout.EndHorizontal ();

            serObj.ApplyModifiedProperties();
        }
    }
}

十三.结语

        《Tank_Battle》不仅是一款具有娱乐性的游戏,也是一个优秀的 Unity 开发实践项目。对于初学者来说,它展示了如何利用 Unity 引擎进行场景搭建、对象控制、碰撞检测和特效实现等基础开发技术;对于有一定经验的开发者,也可以从中获取关于双人对战游戏设计和实现的思路和方法。同时,项目还提供了可能出现问题的解决方案,有助于开发者在遇到类似问题时快速解决。
 


http://www.kler.cn/a/562458.html

相关文章:

  • HTML邮件的制作以及可能遇到的问题
  • 【LeetCode20】有效的括号
  • LeetCodeHot100_0x02
  • Fisher散度:从信息几何到机器学习的隐藏利器
  • QT MD5校验文件和数据的完整性
  • 国内访问Github的四种方法(2025版)
  • 堆排序:高效的选择排序
  • selenium如何实现,开启浏览器的开发者工具模式,并且开启 toggle移动设备模拟模式
  • 视频编解码技术-3: H.264和VP9压缩效率和编码时延
  • Ubuntu22上安装MySQL8启动成功,远程无法连接
  • vue2中,打包报错ERROR in /node_modlules/@types/lodash/common/common.d.ts 26
  • 041集——选取若干点生成三角网(CAD—C#二次开发入门)
  • 贪心3 跳跃游戏 II
  • C++基础入门——Vetor与函数
  • 【行业解决方案篇九】【DeepSeek能源勘探:地震波数据智能解释】
  • WPS PPT插入各种线型形状(如画直线)的时候总是有箭头,如何还原成只画直线
  • Eclipse导入forge-1.21.x
  • 【深度学习】强化学习(RL)-PPO(Proximal Policy Optimization,近端策略优化)
  • github 推送的常见问题以及解决
  • 6.6.2 SQL数据定义