Unity大作业——第一人称射击游戏

这次作业是要做第一人称射击游戏,我按要求下载了CrossBow的asset,另外下载了场景、天空盒和靶子的资源,整体场景设置如下所示,红色区域是射击区域,右上角显示分数、剩余子弹数量和状态(是否允许射击),按p可切换天空盒,以显示不同时间,主角碰到靶子会死亡。

下面是每一环节具体的代码

1.主角移动

我把弓箭资源和main camera都放在一个空对象player下,以实现相机的移动跟随

角色移动逻辑,挂载在player对象

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

public class PlayerMovement : MonoBehaviour
{
    public CharacterController controller;

    public float speed = 5;
    public float gravity = -9.18f;

    public Transform groundCheck;
    public float groundDistance = 0.4f;
    public LayerMask groundMask;

    Vector3 velocity;
    bool isGrounded;
    bool allowMovement = true;

    void Update()
    {
        if (!allowMovement) return;
        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);

        if (isGrounded && velocity.y < 0)
        {
            velocity.y = -2f;
        }

        if (Input.GetKey("left shift") && isGrounded)
        {
            speed = 10;
        }
        else
        {
            speed = 5;
        }

        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        Vector3 move = transform.right * x + transform.forward * z;

        controller.Move(move * speed * Time.deltaTime);

        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
        }

        velocity.y += gravity * Time.deltaTime;

        controller.Move(velocity * Time.deltaTime);
    }


    public void DisableMovement()
    {
        allowMovement = false;
    }
}

弓箭控制逻辑,挂载在弓箭对象上,并将prefab中的arrow拖入arrowPrefab中

using UnityEngine;

using UnityEngine.SceneManagement;

using UnityEngine.UI;




public class BowController : MonoBehaviour

{

    private Animator animator;

    private bool isHoldingBow = false;

    public GameObject arrowPrefab;  // 预制体



    public static BowController instance;
    public int scoreValue = 0;
    public int num = 0;
    public bool isAtk;
    public GameObject panel;



    private void Awake()

    {
        instance = this;
    }

    public void AddScore()

    {
        scoreValue++;

        UiController uiController = FindObjectOfType<UiController>();

        if (uiController != null)
        {
            uiController.UpdateScoreAndBullets(scoreValue, num);
        }
        else
        {
            Debug.LogError("UiController not found in the scene.");
        }

    }




    void Start()

    {

        Cursor.lockState = CursorLockMode.Locked;

        animator = GetComponent<Animator>();

        UiController uiController = FindObjectOfType<UiController>();

        if (uiController != null)
        {
            uiController.UpdateScoreAndBullets(scoreValue, num);
            uiController.UpdateState(isAtk);
        }
        else
        {
            Debug.LogError("UiController not found in the scene.");
        }

    }


    public void RestartGame()

    {
        SceneManager.LoadScene(0);
    }


    void Update()

    {

        UiController uiController = FindObjectOfType<UiController>();

        uiController.UpdateScoreAndBullets(scoreValue, num);

        if (!isAtk || num <= 0) { return; }


        if (Input.GetMouseButtonDown(0))

        {

            animator.SetBool("Fire", true);

            isHoldingBow = true;

        }



        if (Input.GetMouseButtonUp(0))

        {

            if (isHoldingBow)

            {

                isHoldingBow = false;

                animator.SetBool("Fire", false);

                ShootArrow();

                num--;


            }

        }

    }



    void ShootArrow()

    {
        if (arrowPrefab != null)

        {

            // 实例化箭矢

            GameObject arrow = Instantiate(arrowPrefab);
            arrow.transform.SetParent(transform);
            arrow.transform.localPosition = transform.GetChild(4).transform.localPosition;
            arrow.transform.localRotation = transform.GetChild(4).transform.localRotation;

            // 获取箭矢上的刚体组件

            Rigidbody arrowRigidbody = arrow.GetComponent<Rigidbody>();

            //Destroy(arrow, 10f);

            arrowRigidbody.useGravity = true;


            // 检查刚体组件是否存在

            if (arrowRigidbody != null)

            {
                arrowRigidbody.AddForce(transform.up * 60f, ForceMode.Impulse);
            }

        }

    }

}

2. 设计区域逻辑

根据要求,在固定红色区域才可以射击,别的地方禁止射击,这部分代码如下

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

public class ShootPoint : MonoBehaviour
{
    public int atkNum = 10;
    void Start()
    {

    }
    void Update()
    {


    }
    private void OnTriggerEnter(Collider other)

    {
        Debug.Log("OnTriggerEnter: " + other.name);
        if (other.gameObject.tag=="Player")
        {

            UiController uiController = FindObjectOfType<UiController>();
            uiController.UpdateState(true);
            BowController.instance.isAtk = true;
            BowController.instance.num = atkNum;
        }


    }

    private void OnTriggerExit(Collider other)

    {
        Debug.Log("OnTriggerExit: " + other.name);
        if (other.gameObject.tag=="Player")
        {
            UiController uiController = FindObjectOfType<UiController>();
            uiController.UpdateState(false);
            atkNum = BowController.instance.num;
            BowController.instance.isAtk = false;
        }
    
    }
 
}

3.  靶子销毁逻辑

弓箭射中靶子后,会加分并销毁靶子,挂载在靶子上面

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

public class TargetShoot : MonoBehaviour
{
    private void OnTriggerEnter(Collider other)

    {
        if (other.gameObject.tag == "Arrow")

        {
            BowController.instance.AddScore();
            Destroy(gameObject);
            Destroy(other.gameObject);
        }

    }

}

4. 死亡逻辑

角色触碰树后触发死亡逻辑,也挂载在树上

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

public class TriggerAC : MonoBehaviour
{
    public GameObject win;

    // Start is called before the first frame update

    private void OnTriggerEnter(Collider other)

    {

        if (other.CompareTag("Player"))

        {
            Debug.Log("trigger");

            UiController uiController = FindObjectOfType<UiController>();

            uiController.GameOver(BowController.instance.scoreValue);

            Cursor.lockState = CursorLockMode.Confined;

            BowController.instance.enabled = false;

            BowController.instance.panel.SetActive(true);

            PlayerMovement playerMovement = other.GetComponent<PlayerMovement>();
            if (playerMovement != null)
            {
                playerMovement.DisableMovement();
            }

        }
        else print(other.name);


    }

    private void OnCollisionEnter(Collision collision)

    {

        if (collision.gameObject.CompareTag("Player"))

        {
            Debug.Log("collision");

            UiController uiController = FindObjectOfType<UiController>();

            uiController.GameOver(BowController.instance.scoreValue);

            Cursor.lockState = CursorLockMode.Confined;


        }
        else print("???");

    }

    public void LoadS()

    {

        SceneManager.LoadScene(0);

    }

}

5 ui控制逻辑

实现在对应区域更新分数、子弹数量、状态信息,死亡出现“Game over”提示

using UnityEngine.UI;
using UnityEngine;
using TMPro;
using UnityEngine.SocialPlatforms.Impl;

public class UiController : MonoBehaviour
{
    public TextMeshProUGUI scoreText;
    public TextMeshProUGUI bulletsText;
    public TextMeshProUGUI stateText;
    public TextMeshProUGUI overText;

    void UpdateUI(int score, int bullets)
    {
        scoreText.text = "Score: " + score.ToString();
        bulletsText.text = "Bullets: " + bullets.ToString();
    }

    public void UpdateScoreAndBullets(int score, int bullets)
    {
        UpdateUI(score, bullets);
    }

    public void UpdateState(bool st)
    {
        if (st)
            stateText.text = "State: OK";
        else
            stateText.text = "State: illegal";
    }
    public void GameOver(int score)
    {
        overText.text = "Game over!\nYour final score is" + score.ToString();
    }

}

6. 天空盒逻辑

5s一次天空盒的转化,要将天空盒材质提前拖入预设的列表中

using System.Collections;
using UnityEngine;

public class SkyboxSwitcher : MonoBehaviour
{
    public Material[] skyboxMaterials;
    private int currentSkyboxIndex = 0;

    void Start()
    {
        RenderSettings.skybox = skyboxMaterials[currentSkyboxIndex]; // 初始设置天空盒
        StartCoroutine(AutoSwitchSkybox(5f)); // 启动协程,每5秒切换一次
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.P))
        {
            SwitchSkybox();
        }
    }

    void SwitchSkybox()
    {
        currentSkyboxIndex = (currentSkyboxIndex + 1) % skyboxMaterials.Length;
        RenderSettings.skybox = skyboxMaterials[currentSkyboxIndex];
    }

    IEnumerator AutoSwitchSkybox(float interval)
    {
        while (true)
        {
            yield return new WaitForSeconds(interval);
            SwitchSkybox();
        }
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值