Unity开发——Crossbow Shooting Terrain

附录

https://github.com/jASONSDFDSA/Game_4_Crossbow_Shooting_Terrain

Crossbow Shooting Terrain——Unity课程作业演示视频_哔哩哔哩_bilibili

项目介绍

使用Classical Crossbow以及动画来制作一个射击游戏。玩家可以操控弩弓在地图上移动,但只能在白色区域内射击,并有一定次数限制。玩家可以按下0来生成固定靶,按下1来生成移动靶。击中固定靶获得10分,击中移动靶获得20分。

如果玩家操控弩弓撞上树或者靶子则游戏结束。

代码简介

没有对代码进行规范化的整理,但对资源做了整理。其中Main Camera使用了天空盒组件,并且被绑在了弩弓上面。

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

public class Crowssbow : MonoBehaviour
{
    public Transform target; // 这是你要跟随的目标模型的Transform组件
    public Vector3 offset;
    void Update()
    {
        if (target != null)
        {
            // 设置相机的位置与目标模型的位置一致
            transform.position = target.position + offset;
        }
    }
}

然后,编写脚本让弩弓能够在地图上游走、鼠标操控视角,并显示射击次数。

using System;
using UnityEngine;
using UnityEngine.UIElements;

public class PlayerController : MonoBehaviour
{
    public float moveSpeed = 5f; // 移动速度
    public float sensitivity = 1f; // 鼠标灵敏度
    public float bulletSpeed = 10f;
    public GameObject bulletPrefab; // 子弹预制体
    public Vector3 fireOffset;
    public Transform firePoint;
    public int movingTargetChance = 100;
    public int fixedTargetChance = 6;
    private int movingShoot = 0;
    private int fixedShoot = 0;
    private Animator animator;
    private bool isHolding;
    private int inRange;
    private float coolDown;
    private float castAnimation;
    private bool canControl;
    private GUIStyle fontStyle; 
    private GUIStyle fontStyle2; 

    void Start()
    {
        fontStyle = new GUIStyle();
        fontStyle.normal.background = null;    //设置背景填充
        fontStyle.normal.textColor= new Color(1,0,0);   //设置字体颜色
        fontStyle.fontSize = 40; 
        fontStyle2 = new GUIStyle();
        fontStyle2.normal.background = null;    //设置背景填充
        fontStyle2.normal.textColor= new Color(0,0,0);   //设置字体颜色
        fontStyle2.fontSize = 30; 
        // 获取Animator组件
        animator = GetComponent<Animator>();
        isHolding = false;
        canControl = true;
        inRange = 0;
        coolDown = 0;
    }
    void Update()
    {
        if (canControl)
        {
            inRange = CheckRange();
            if (inRange != 0)
            {
                // 长按鼠标时处于 "holding" 状态
                if ((inRange == 1 && fixedShoot < fixedTargetChance) ||
                    (inRange == 2 && movingShoot < movingTargetChance))
                {
                    if (Input.GetMouseButton(0) && coolDown - Time.time <= -1) // 0 表示左键
                    {
                        isHolding = true;
                        castAnimation = Time.time;
                    }
                    else
                    {
                        // 松开鼠标时切换到 "fire" 状态
                        if (isHolding && Time.time - castAnimation >= 0.5)
                        {
                            isHolding = false;
                            coolDown = Time.time;
                            SetFireState();
                            ShootBullet();
                            if (inRange == 1)
                            {
                                fixedShoot++;
                            }
                            else if (inRange ==2)
                            {
                                movingShoot++;
                            }
                        }
                    }
                }

                // 更新Animator Controller 中的参数
                UpdateAnimatorParameters();
            }
        
            // 获取键盘输入
            float horizontalInput = Input.GetAxisRaw("Horizontal");
            float verticalInput = Input.GetAxisRaw("Vertical");

            // 计算移动方向
            Vector3 movement = new Vector3(-verticalInput, 0f, horizontalInput).normalized;

            // 移动模型
            Move(movement);
        
            // 获取鼠标移动输入
            float mouseX = Input.GetAxisRaw("Mouse X");
            float mouseY = Input.GetAxisRaw("Mouse Y");

            // 根据鼠标输入调整摄像机的旋转
            RotateCamera(mouseX, mouseY);
        }
    }

    void Move(Vector3 movement)
    {
        // 根据输入移动模型
        Vector3 targetPosition = transform.position + movement * moveSpeed * Time.deltaTime;
        
        // 移动模型到目标位置
        transform.position = targetPosition;
    }

    void OnCollisionEnter(Collision other)
    {
        GameOver();
    }

    void RotateCamera(float mouseX, float mouseY)
    {
        // 获取当前摄像机的旋转
        Vector3 currentRotation = transform.eulerAngles;

        // 水平旋转(左右移动)
        currentRotation.y += mouseX * sensitivity;

        // 垂直旋转(上下移动),限制在-90到90度之间
        currentRotation.x = Mathf.Clamp(currentRotation.x - mouseY * sensitivity, -90f, 90f);

        // 应用旋转
        transform.eulerAngles = currentRotation;
    }
    
    void SetFireState()
    {
        // 触发 "fire" 状态
        animator.SetTrigger("Fire");
    }
    
    void ShootBullet()
    {
        // 检查是否设置了子弹预制体和发射位置
        if (bulletPrefab != null)
        {
            Quaternion existingRotation = transform.rotation;

            // 获取 existingRotation 的欧拉角
            Vector3 existingEulerAngles = existingRotation.eulerAngles;

            // 增加 x 值
            existingEulerAngles.x -= 90f;

            // 创建一个新的 Quaternion
            Quaternion newRotation = Quaternion.Euler(existingEulerAngles);
            
            // 生成子弹
            GameObject bullet = Instantiate(bulletPrefab, firePoint.position + fireOffset, newRotation);

            // 获取子弹上的刚体组件
            Rigidbody bulletRigidbody = bullet.GetComponent<Rigidbody>();

            // 检查刚体组件是否存在
            if (bulletRigidbody != null)
            {
                // 为子弹添加速度
                bulletRigidbody.velocity = bullet.transform.forward * bulletSpeed;
            }
        }
    }

    void UpdateAnimatorParameters()
    {
        // 更新Animator Controller 中的参数
        animator.SetBool("Holding", isHolding);
    }

    void GameOver()
    {
        canControl = false;
    }

    int CheckRange()
    {
        Vector3 p = transform.position;
        float px = p.x;
        float pz = p.z;
        int plane = 0;
        if (px <= 2.5f && px >= -7.5f)
        {
            if (pz >= -5 && pz <= 5)
            {
                plane = 1;
            }
            else if (pz >= 10 && pz <= 20)
            {
                plane = 2;
            }
        }
            
        return plane;
    }

    void OnGUI()
    {
        GUI.Label(new Rect(0, Screen.height - 40, 200, 40), "Shoot " + fixedShoot +  "/" + fixedTargetChance +" times in plane 1", fontStyle2);
        GUI.Label(new Rect(Screen.width - 400, Screen.height - 40, 200, 40), "Shoot " + movingShoot +  "/" + movingTargetChance +" times in plane 2", fontStyle2);
        if (!canControl)
        {

            GUI.Label(new Rect(Screen.width/2 - 60, Screen.height/2 - 40, 100, 80), "Game Over!", fontStyle);
        }
    }
}

给弓箭加点简单的物理逻辑,让其被射出后能够正常运动。

using UnityEngine;

public class ProjectileController : MonoBehaviour
{
    private Rigidbody rb;
    public int scoreValue = 10;
    public int movingScoreValue = 20;

    void Start()
    {
        // 获取刚体组件
        rb = GetComponent<Rigidbody>();
    }

    void OnCollisionEnter(Collision collision)
    {
        // 在碰撞发生时停止刚体运动
        rb.velocity = Vector3.zero;
        rb.angularVelocity = Vector3.zero;

        // 可以添加其他的停止逻辑,比如播放停止动画或者触发其他事件
        if (collision.gameObject.CompareTag("Target"))
        {
            // 处理计分逻辑
            ScoreManager.Instance.AddScore(scoreValue);

            // 销毁弩箭对象
            Destroy(gameObject);
        }
        if (collision.gameObject.CompareTag("Moving Target"))
        {
            // 处理计分逻辑
            ScoreManager.Instance.AddScore(movingScoreValue);

            // 销毁弩箭对象
            Destroy(gameObject);
        }
    }
}

然后,用ScoreManager来计分与显示分数。

using UnityEngine;
using UnityEngine.UI;

public class ScoreManager : MonoBehaviour
{
    public static ScoreManager Instance; // 单例实例

    private GUIStyle fontStyle;
    private int score = 0; // 分数

    void Awake()
    {
        // 创建单例
        if (Instance == null)
        {
            Instance = this;
        }
        else
        {
            Destroy(gameObject);
        }
    }

    void Start()
    {
        score = 0;
        
        fontStyle = new GUIStyle();
        fontStyle.normal.background = null;    //设置背景填充
        fontStyle.normal.textColor= new Color(1,0,0);   //设置字体颜色
        fontStyle.fontSize = 40;       //字体大小
    }

    public void AddScore(int value)
    {
        score += value;
    }

    void OnGUI()
    {
        GUI.Label(new Rect(0, 0, 100, 30), "Score: " + score, fontStyle);
    }
}

用TargetCreator来生成靶子

using UnityEngine;

public class TargetCreator: MonoBehaviour
{
    public GameObject myPrefab1; // 引用你的预制体
    public GameObject myPrefab2;
    public float spawnRadius = 5f;

    void Update()
    {
        // 在Update函数中检测用户输入,例如按下空格键
        if (Input.GetKeyDown(KeyCode.Keypad0))
        {
            Vector3 randomPosition = transform.position + Random.onUnitSphere * spawnRadius;
            
            randomPosition.y = 2f;

            // 使用Instantiate生成预制体的实例
            Instantiate(myPrefab1, randomPosition, myPrefab1.transform.rotation);
            // 使用Instantiate生成预制体的实例
        }

        if (Input.GetKeyDown(KeyCode.Keypad1))
        {
            Vector3 randomPosition = transform.position;
            
            randomPosition.y = 2f;
            
            // 使用Instantiate生成预制体的实例
            Instantiate(myPrefab2, randomPosition, myPrefab2.transform.rotation);
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值