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

Unity自学之旅04

Unity自学之旅04

  • Unity自学之旅④
    • 📝 跳跃
    • 🐯 攻击
    • 🦄 GUI
      • GUI前置,显示收集物品数量和角色Hp
      • UGUI
      • 游戏暂停和重新开始
  • 🤗 总结归纳

Unity自学之旅④

📝 跳跃

public class PlayerBehaviorRigid : MonoBehaviour
{
    //...
    // 跳跃速度
    public float JumpVelocity = 5f;
    // 是否跳跃
    private bool _isJumping;

    void Start()
    {
        // 将当前player的刚体组件获取并设置
        _rb = GetComponent<Rigidbody>();    
    }

    void Update()
    {
        //...
        // 按位或
        _isJumping |= Input.GetKeyDown(KeyCode.J);
    }

    void FixedUpdate()
    {
		    //...
        if (_isJumping)
        {
            // 如果按下J键,瞬间力向上跳跃
            _rb.AddForce(Vector3.up*JumpVelocity,ForceMode.Impulse);
        }
        _isJumping = false;
    }
}

在这里插入图片描述

在这里插入图片描述

如何解决连续跳跃的问题,保证角色只可以进行一次跳跃。落地之后才可以接着进行跳跃。这个时候,需要使用一个遮罩层来完成。

Player会在场景中的Environment进行跳跃,也就是ground层,只需要计算Player与Ground层之间的距离,达到某个阈值视为触地。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

public class PlayerBehaviorRigid : MonoBehaviour
{
		// ...
    // 跳跃速度
    public float JumpVelocity = 5f;
    // 是否跳跃
    private bool _isJumping;

    // 角色和地面之间的距离 
    public float DistanceToGround = 0.1f;

    // Ground Layer 层
    public LayerMask GroundLayer;

    // 胶囊碰撞体
    public CapsuleCollider _col; 

    void Start()
    {
        // 将当前player的刚体组件获取并设置
        _rb = GetComponent<Rigidbody>();
        // 获取当前角色的胶囊碰撞体
        _col = GetComponent<CapsuleCollider>();
    }

    void Update()
    {
        // ...
        // 按位或
        _isJumping |= Input.GetKeyDown(KeyCode.J);
    }

    void FixedUpdate()
    {

        //...
        if (IsGrounded() && _isJumping)
        {
            // 如果按下J键,瞬间力向上跳跃
            _rb.AddForce(Vector3.up*JumpVelocity,ForceMode.Impulse);
        }

        _isJumping = false;
    }

    // 是否触地
    private bool IsGrounded()
    {
        // 胶囊体的最底部位置 (碰撞器的中心坐标x,z,以及最小y轴坐标)
        Vector3 capsuleBottom = new Vector3(_col.bounds.center.x,
            _col.bounds.min.y, _col.bounds.center.z);

        // 检查胶囊体中心到胶囊体底部之间的区域是否与地面层发生碰撞
        // 距离如果小于 DistanceToGround 0.1f则视为碰撞触地
        bool grounded = Physics.CheckCapsule(_col.bounds.center,
            capsuleBottom,DistanceToGround,GroundLayer,QueryTriggerInteraction.Ignore);

        return grounded;
    }
}

🐯 攻击

在这里插入图片描述

在这里插入图片描述

遗漏了一个问题,给子弹添加RigidBody刚体组件

在这里插入图片描述

编写一个射击子弹的逻辑(在此之前,清除掉场景中的Bullet)

在这里插入图片描述

public class PlayerBehaviorRigid : MonoBehaviour
{
   
		// ...
    // 子弹GameObject
    public GameObject Bullet;

    // 子弹攻击速度
    public float BulletSpeed = 100f;

    // 是否攻击
    public bool _isShooting;

    void Start()
    {
        // 将当前player的刚体组件获取并设置
        _rb = GetComponent<Rigidbody>();
        // 获取当前角色的胶囊碰撞体
        _col = GetComponent<CapsuleCollider>();
    }

    void Update()
    {
        //...
        // 按下空格键 进行射击
        _isShooting |= Input.GetKeyDown(KeyCode.Space);
    }

    void FixedUpdate()
    {

        //...
        if (_isShooting)
        {
            // 每次空格键按下都会在Player的z轴前一个单位产生一颗子弹
            GameObject newBullet = Instantiate(Bullet,this.transform.position
                +new Vector3(0,0,1),this.transform.rotation) as GameObject;

            Rigidbody BulletRb = newBullet.GetComponent<Rigidbody>();   

            // 直线射击子弹,子弹速度=player角色的面向方向*子弹速度
            BulletRb.velocity = this.transform.forward * BulletSpeed;
        }

        _isShooting = false;    
    }
}

在这里插入图片描述

出现的新问题,子弹一直在创建新的对象,我们应该给其加入一个自动销毁策略,如:发射出三秒后销毁。为子弹添加一个脚本,3秒后销毁。

public class BulletBehavior : MonoBehaviour
{

    public float OnScreenDelay = 3f;

    void Start()
    {
        Destroy(this.gameObject, OnScreenDelay);
    }

}

在这里插入图片描述

🦄 GUI

GUI前置,显示收集物品数量和角色Hp

创建一个管理类脚本,以及一个空对象,将管理类脚本挂载到空对象上。

public class GameBehavior : MonoBehaviour
{
    private int _itemsCollected = 0;
    private int _playerHp = 10;

    public int Items 
    { 
        get { return _itemsCollected; } 
        set 
        { 
            _itemsCollected = value; 
            Debug.LogFormat("收集了:{0}",_itemsCollected);
        }
    }

    public int HP
    {
        get { return _playerHp; }
        set
        {
             _playerHp = value;
            Debug.LogFormat("HP:{0}", _playerHp);
        }
    }
}

在这里插入图片描述

修改之前的逻辑,捡到Health_Pickup时给物品收集数量+1,然后运行游戏注意观察日志输出

public class ItemBehavior : MonoBehaviour
{
		// 获取刚刚的GameManager脚本对象
    public GameBehavior GameManager;

     void Start()
     {
        GameManager = GameObject.Find("Game_Manager")
        .GetComponent<GameBehavior>();
     }

    // 发生碰撞时被调用
    void OnCollisionEnter(Collision collision)
    {
        if(collision.gameObject.name == "Player")
        {
            // 销毁当前物体
            Destroy(this.transform.gameObject);
            Debug.Log("碰撞,销毁");
            // 发生碰撞时意味着捡到了物品
            GameManager.Items += 1;
        }
    }
}

在这里插入图片描述

UGUI

在这里插入图片描述

在这里插入图片描述

很简单,打开Inspect然后修改文字UI的位置以及字体颜色,运行观察一下效果

在这里插入图片描述

在这里插入图片描述

接着再绘制一个是否获胜的文字UI

在这里插入图片描述

编辑GameManager的脚本GameBehavior,很简单的逻辑,在项目启动时,赋予对应HP,Item初始的文字UI,然后当Item≥4时代表游戏获胜,将Progress设为win.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class GameBehavior : MonoBehaviour
{
    private int _itemsCollected = 0;
    

    public int Items 
    { 
        get { return _itemsCollected; } 
        set 
        { 
            _itemsCollected = value;
            ItemsText.text = "Items Collected:" + Items;
            Debug.LogFormat("收集了:{0}",_itemsCollected);

            if(_itemsCollected >= MaxItems)
            {
                ProgressText.text = "win";
            }
            else
            {
                ProgressText.text = "Item found,only" + (MaxItems - _itemsCollected) + "more!";
            }
        }
    }

    private int _playerHp = 10;
    public int HP
    {
        get { return _playerHp; }
        set
        {
             _playerHp = value;
            HealthText.text = "Player Health:" + HP;
            Debug.LogFormat("HP:{0}", _playerHp);
        }
    }

    // 游戏中一共存在四个可以收集的Health_pickup
    public int MaxItems = 4;

    // 三个UI文字
    public TMP_Text HealthText;
    public TMP_Text ItemsText;
    public TMP_Text ProgressText;

     void Start()
    {
        HealthText.text += _playerHp;
        ItemsText.text += _itemsCollected;
    }

}

在这里插入图片描述

在这里插入图片描述

光是文字的UI看着很low,或者说呈现方式并不是很好,现在改换思路,当游戏获胜时,弹出一个按钮之类的显示获胜。

在这里插入图片描述

绘制好了,然后默认情况下它不应该显示,将InSepct里面的复选框取消勾选,然后修改代码逻辑,当获胜时,显示该UI

在这里插入图片描述

记得在GameManager的脚步中将Button按钮挂载上去

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.UI;

public class GameBehavior : MonoBehaviour
{
    //...
    public int Items 
    { 
        get { return _itemsCollected; } 
        set 
        { 
            //...
            if(_itemsCollected >= MaxItems)
            {
	              //..
                WinButton.gameObject.SetActive(true);
            }
           //...
        }
    }

    //...
    // 按钮UI
    public Button WinButton;
	  
	  //...
}

在这里插入图片描述

获胜了,但是还没有理想的效果,当获胜时,应该暂停游戏或者出现一个重新开始的功能,最主要的是当获胜时,我们应该停止角色的控制权限,不能再进行移动,跳跃,射击等功能。

游戏暂停和重新开始

游戏暂停:Time.timeScale = 0f; 时间流速设置为0,暂停游戏。当timeScale>=1 时,为正常时间流速。

游戏重新开始:一般通过重新加载第一个场景来完成,即SceneManager.LoadScene(0) .

逻辑是,当获胜时暂停游戏,点击You Win 按钮时,重新开始游戏。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class GameBehavior : MonoBehaviour
{
    //...
    public int Items 
    { 
        get { return _itemsCollected; } 
        set 
        { 
	          //...
            if(_itemsCollected >= MaxItems)
            {
                //...
                Time.timeScale = 0f;
            }
            //...
        }
    }

    //...
    
    // 重置场景
    public void RestartScene()
    {
        SceneManager.LoadScene(0);
        Time.timeScale = 1f;
    }
}

需要注意的点:在Unity中不可以凭空运行,任何脚本都需要挂个GameObject来完成。

在这里插入图片描述

🤗 总结归纳

本文主要介绍了在 Unity 中实现角色跳跃、攻击以及游戏界面(GUI)相关功能的代码实现过程。包括解决角色连续跳跃问题、编写射击子弹逻辑并添加自动销毁策略、使用管理类脚本显示收集物品数量和角色 HP、通过 UGUI 修改文字 UI 以及绘制获胜按钮、实现游戏暂停和重新开始功能等。

重要亮点

  • 角色跳跃功能实现:通过定义跳跃速度、是否跳跃等变量,在按下特定键时给角色添加向上的瞬间力实现跳跃。为解决连续跳跃问题,使用遮罩层计算角色与地面层之间的距离,只有落地后才能再次跳跃。
  • 攻击功能实现:编写射击子弹的逻辑,按下特定键时在角色前方产生一颗子弹,并为子弹添加刚体组件和自动销毁策略,发射三秒后销毁。
  • GUI 显示物品数量和 HP:创建管理类脚本,挂载到空对象上,实现收集物品数量和角色 HP 的显示。当角色捡到物品时,物品收集数量加一,并在日志中输出。
  • UGUI 优化界面:通过修改文字 UI 的位置和字体颜色,绘制是否获胜的文字 UI。当物品收集数量达到一定值时,游戏获胜,显示 “win”,并可弹出按钮显示获胜。
  • 游戏暂停和重新开始:当游戏获胜时,暂停游戏,时间流速设置为 0。点击获胜按钮可重新开始游戏,通过重新加载第一个场景实现,同时恢复时间流速为正常状态。

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

相关文章:

  • 2025/1/21 学习Vue的第四天
  • 如何使用 Pytest 断言测试 Python 异常处理
  • Tcl教程
  • JavaScript语言的多线程编程
  • @LoadBalanced注解的实现原理
  • 海康工业相机的应用部署不是简简单单!?
  • 缓存系统(redis)测试体系
  • 智慧脚下生根,智能井盖监测终端引领城市安全新革命
  • Mybatis 进阶 / Mybatis—Puls (详细)
  • 升级《在线写python》小程序的分享功能。昨天忘了...
  • Keil5 IDE使用笔记
  • C#调用c++dll的两种方法(静态方法和动态方法)
  • 大华相机DH-IPC-HFW3237M支持的ONVIF协议
  • Apache SeaTunnel 2.3.9 正式发布:多项新特性与优化全面提升数据集成能力
  • 【Python项目】小区监控图像拼接系统
  • Spring 6 第5章——面向切面:AOP
  • Spring Boot框架下的上海特产销售商城网站开发之旅
  • Java复习第四天
  • 如何写出优秀的提示词?ChatGPT官方的六种方法
  • 【科研建模】Pycaret自动机器学习框架使用流程及多分类项目实战案例详解
  • 【蓝桥杯】43694.正则问题
  • Axios发起HTTP请求时的先后执行顺序
  • 1/20赛后总结
  • 22. C语言 输入与输出详解
  • 云计算、AI与国产化浪潮下DBA职业之路风云变幻,如何谋破局启新途?
  • docker load报错(unexpected EOF)