Unity游戏开发之双人坦克

爱上游戏开发

共 12439字,需浏览 25分钟

 ·

2021-06-22 23:33

作者: 虚拟喵

来源: https://blog.csdn.net/qq_35361471/article/details/79321304

开发版本:unity 5.3.5f

适合人群:初学Unity者

源文件链接请见文末!

开启学习之旅吧!

玩法:双方分别用WSAD键或上下左右键来控制两个坦克移动,用空格键或回车键来控制发射炮弹,当一方血条为0,则重新开始

场景搭建

新建3D工程TankWar,新建MainScene场景,导入Assets资源,将Prefabs文件夹中LevelArt预制体拖入场景中。

场景预制体中已经包含方向光,可以将场景原有的方向光删除。

如果出现如下场景,由于渲染原因

Window-lighting窗口 build一下场景 等右下的进度结束就可了,时间稍微有点长~

开发坦克

将Models中Tank模型拖入场景,并设为预制体,标签设置为Play

注意,对场景中的Tank进行一些操作后,需要Apply一下,才可以将这些操作映射到其他预制体上。

给Tank添加BoxCollider,并对Collider大小进行调节,可以切换到正交视图进行调节

刚体需要冻结Y轴移动,X轴和Z轴的旋转

为Tank添加拖尾效果,将Prefabs文件夹中的DustTrail粒子特效,放在Tank左右后轮

将拖尾粒子特效分别作为左右后轮的子物体,方便随Tank一起移动

在Tank身上挂载TankController.cs脚本

添加Move方法,在FixedUpdate()内调用,FixedUpdate是固定帧时间调用

void Move()
    {
        //Input.GetAxis("Vertical")在键盘按下W/S键或上下键时候,会返回范围在-1到1的值
        float v = Input.GetAxis("Vertical");
        //修改刚体速度,transform.forward控制物体在Z轴移动
        _rigidbody.velocity = transform.forward * v * speed;
        //Input.GetAxis("Horizontal")在键盘按下A/D键或左右键时候,会返回范围在-1到1的值
        float h = Input.GetAxis("Horizontal");
        //angularVelocity是刚体角速度向量,可以控制物体旋转,transform.up是物体旋转的轴
        _rigidbody.angularVelocity = transform.up * h * rotateSpeed;
    }

开发子弹

控制Tank子弹发射

Models文件夹中的Shell拖入场景,添加Rigidbody和CapsuleCollider,并设为预制体

为坦克添加一个发射子弹的位置ShootPos,设为Tank的子物体,要注意这个位置不要在坦克自身的碰撞体内

在PlayerController.cs中添加发射子弹的方法Attack(),在FixedUpdate()方法内调用

void Attack()
    {
       //发射键_keyCode可以在Inspector面板设置
        if (Input.GetKeyDown(_keyCode))
        {
             //在发射位置ShootPos实例化子弹
            GameObject go = GameObject.Instantiate(shellPrefab, shootPos.position, shootPos.rotation) as GameObject;
            //方法一:可以通过修改刚体速度
            //go.GetComponent<Rigidbody>().velocity = go.transform.forward * shellSpeed;
            //方法二:可以给物体添加一个方向的力
            go.GetComponent<Rigidbody>().AddForce(go.transform.forward * shellSpeed);
        }
    }

可以玩家一设置发射键为空格键,玩家二设置发射键为回车键

在子弹身上挂载脚本ShellController.cs

public class ShellController : MonoBehaviour 
{
    //prefabs文件夹中的爆炸预设
    public GameObject explosionPrefabs;
 
    private void OnTriggerEnter(Collider other)
    {
        //实例化爆炸效果,并赋值给go 
        GameObject go = GameObject.Instantiate(explosionPrefabs, transform.position, transform.rotation) as GameObject;
        //在爆炸效果实例化1.5s后销毁,因为这个爆炸效果的时长就是1.5s
        Destroy(go, 1.5f);
        //立即销毁该子弹
        Destroy(this.gameObject);
        //如果子弹碰到的是坦克,则调用对象身上的TakeDamage()方法
        if (other.CompareTag("Player"))
        {
            //SendMessage()消息推送,可以调用该对象身上的私有或公有方法
            other.SendMessage("TakeDamage");
        }
    }
}

TakeDamage()方法请看下文。微信搜索公众号 [爱上游戏开发],回复 “资料”,免费领取 200G 学习资料

优化坦克控制

由于游戏中需要有两个坦克,目前的代码会让两个Tank控制方式一致

我们希望一台Tank由WSAD键控制,另一台由上下左右来控制

在InputManager里添加两个新的虚拟键

Edit-Project Setting-Input

将原有的Horizontal右键复制两个新的,并修改名称和监听按键

Vertical同样的操作

我们根据不同的虚拟键名来分别控制两个Tank

新建一个枚举类型,用来区别操作方式

public enum Player
{
    Player01,
    Player02
}
 
//public可以外部设置,默认为玩家一
    public Player player = Player.Player01;
    private int PlayerNum = 1;
    private Rigidbody _rigidbody;
 
    private void Start()
    {
        _rigidbody = gameObject.GetComponent<Rigidbody>();
 
        switch (player)
        {
            case Player.Player01:
                PlayerNum = 1;
                _keyCode = KeyCode.Space;
                break;
            case Player.Player02:
                PlayerNum = 2;
                _keyCode = KeyCode.Return;
                break;
        }
    }
 
private void FixedUpdate()
    {
        Move();
        //Attack();
    }
 
void Move()
    {
        float v = Input.GetAxis("VerticalPlayer0" + PlayerNum);
        float h = Input.GetAxis("HorizontalPlayer0" + PlayerNum);
        _rigidbody.velocity = transform.forward * v * speed;
        _rigidbody.angularVelocity = transform.up * h * rotateSpeed;
    }

在Inspector面板,玩家一可以设置为Player01,玩家二可以设置为Player02

修改两个坦克的颜色,可以将Materials文件夹中的不同颜色材质直接拖到场景中坦克对象上即可

摄像机跟随

public class CamFellowPlayer : MonoBehaviour
{
    public Transform player1;
    public Transform player2;
    public float maxSize = 20f;
    public float minSize = 6.5f;
 
    private Vector3 offset;
    private float ratio;
    private float distance;
 
    private void Start()
    {
        //计算摄像机距离两个坦克中心点的偏差值
        offset = transform.position - (player1.position + player2.position) / 2f;
        //计算初始的两个坦克的距离
        distance = Vector3.Distance(player1.position, player2.position);
        //计算初始正交大小和初始Tank距离的比例
        ratio = minSize / distance;
    }
 
    private void Update()
    {
        //防止因为坦克销毁后报错
        if (player1!=null&&player2!=null)
        {
            transform.position = (player1.position + player2.position) / 2f + offset;
            distance = Vector3.Distance(player1.position, player2.position);
            //计算当前的坦克距离和比例的乘积,则得到当前的正交大小
            float size = distance * ratio;
            //Mathf.Clamp可以限制Size的值在minSize和maxSize之间
            size = Mathf.Clamp(size, minSize, maxSize);
            //将得到的size赋值给主摄像机的正交大小
            //Camera.main返回的是主摄像机
            Camera.main.orthographicSize = size;
        }
    }
}

计算伤害并设计血条

为tank添加脚本TankHealth.cs

我们使用UGUI的滑动条来设计血条

因为涉及到UGUI一些知识,我先将血条做成了预制体

注意别忘记在Inspector面板,把血条hpSlider赋值

public class TankHealth : MonoBehaviour
{
    //设计血量为100,可以在Inspector面板调整
    public int hp = 100;
    //prefabs文件夹中的坦克爆炸效果预设
    public GameObject tankExplosion;
    public Slider hpSlider;
    private int hpTotal;
 
    private void Start()
    {
        //初始化hpTotal
        hpTotal = hp;
    }
 
    private void TakeDamage()
    {
        //如果当前hp值已经低于0,则返回
        if (hp <= 0) return;
        hp -= Random.Range(10, 20);
        //根据当前的hp和总血量hpTotal的比值还赋予滑动条的值
        hpSlider.value = (float)hp / hpTotal;
        //受到伤害之后,血量为零,则实例化爆炸效果,并销毁该坦克
        if (hp<=0)
        {
            //transform.position + Vector3.up因为坦克的中心点在坦克的底部,可以向上偏移一米,爆炸效果更好
            GameObject.Instantiate(tankExplosion, transform.position + Vector3.up, transform.rotation);
            //销毁该坦克对象
            Destroy(this.gameObject);
             //重新加载当前场景
            UnityEngine.SceneManagement.SceneManager.LoadScene("MainScene");
        }
    }
}

至此,游戏基本开发完成,如果觉得单调可以加一些音乐音效,可以参照我之前的案例,就不在此赘述啦!

喜欢我的,就关注我吧,你的关注,就是我的动力!

素材及工程链接:百度云盘链接 密码:ly74


-- END --


公众号后台回复「资料」获取超多学习福利

>>> 点击进入技术讨论群 <<<
▽想深入了解么?

长按/扫码关注我吧↑↑↑


觉得不错就点个在看吧!

浏览 19
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报