游戏规则:设置了若干个静止靶和运动靶,以及两个射击位。只有站在射击位上才能进行射击。长按鼠标蓄力拉弓,松开鼠标射出箭矢。每个射击位有五次射击机会,射中运动靶一次两分,静止靶一次一分。当玩家控制弩碰到树以及靶子会游戏结束,可以重新开始游戏。
脚本及挂载对象:
①PlayerMove.cs 控制弩的第一人称视角移动,挂载在crossbow对象上
using UnityEngine;
public class PlayerMove : MonoBehaviour
{
// Start is called before the first frame update
private CharacterController cc;
public float moveSpeed=10;
public float jumpSpeed;
private float horizontalMove, verticalMove;
private Vector3 dir;
public float gravity = 9.8f;
private Vector3 velocity;
public Transform groundcheck;
public float checkRadius;
public LayerMask groundLayer;
public bool isGround;
// Update is called once per frame
private void Start()
{
cc = GetComponent<CharacterController>();
}
void Update()
{
isGround = Physics.CheckSphere(groundcheck.position, checkRadius, groundLayer);
if (isGround && velocity.y < 0)
{
velocity.y = 0;
}
horizontalMove = Input.GetAxis("Horizontal") * moveSpeed;
verticalMove = Input.GetAxis("Vertical") * moveSpeed;
dir = transform.forward * verticalMove + transform.right * horizontalMove;
cc.Move(dir*Time.deltaTime);
velocity.y -= gravity * Time.deltaTime;
cc.Move(velocity * Time.deltaTime);
}
}
②控制第一人称视角的摄像机跟随,挂载在camera上(camera作为crossbow的子对象)
using UnityEngine;
public class CameraMove : MonoBehaviour
{
// Start is called before the first frame update
public Transform player;
private float mouseX, mouseY;
public float 鼠标灵敏度;
public float xRotation;
// Update is called once per frame
void Update()
{
mouseX = Input.GetAxis("Mouse X")*鼠标灵敏度*Time.deltaTime;//鼠标左右移动的值
mouseY = Input.GetAxis("Mouse Y") * 鼠标灵敏度*Time.deltaTime;//鼠标上下移动的值
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, -70f, 70f);
player.Rotate(Vector3.up * mouseX);//Vector3.up=0 1 0的三维向量
transform.localRotation = Quaternion.Euler(xRotation, 0, 0);
}
}
③SkyboxSwitcher.cs 切换天空盒的脚本 挂载在空对象上
using UnityEngine;
public class SkyboxSwitcher : MonoBehaviour
{
public Material[] skyboxMaterials; // 存储不同天空盒的材质
private int currentSkyboxIndex = 0; // 当前天空盒的索引
void Start()
{
RenderSettings.skybox = skyboxMaterials[currentSkyboxIndex]; // 初始设置天空盒
}
void Update()
{
// 检测按下 'P' 键
if (Input.GetKeyDown(KeyCode.P))
{
// 切换到下一个天空盒
SwitchSkybox();
}
}
void SwitchSkybox()
{
// 增加索引,确保循环切换
currentSkyboxIndex = (currentSkyboxIndex + 1) % skyboxMaterials.Length;
// 设置新的天空盒材质
RenderSettings.skybox = skyboxMaterials[currentSkyboxIndex];
}
}
④AtkPoint.cs 判断玩家是否站在射击位上 挂载在射击位对象上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AtkPoints : MonoBehaviour
{
public int atkNum = 5;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter(Collider other)
{
BowController.instance.firtxt.gameObject.SetActive(true);
BowController.instance.isAtk = true;
BowController.instance.num = atkNum;
}
private void OnTriggerExit(Collider other)
{
BowController.instance.firtxt.gameObject.SetActive(false);
atkNum = BowController.instance.num;
BowController.instance.isAtk = false;
}
}
⑤BowController.cs 控制弩的射击(动画、得分规则...),挂载在crossbow上
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 Text txtScore;
private int scroeValue;
public int num = 0;
public bool isAtk;
public GameObject panel;
public Text firtxt;
private void Awake()
{
instance = this;
}
public void AddScore()
{
scroeValue++;
txtScore.text = "得分: " + scroeValue;
}
public void AddScore2()
{
scroeValue+=2;
txtScore.text = "得分: " + scroeValue;
}
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
animator = GetComponent<Animator>();
}
public void RestartGame()
{
SceneManager.LoadScene(0);
}
void Update()
{
firtxt.text = "子弹: "+num.ToString();
if (!isAtk || num <= 0) return;//如果没有站在射击位上/子弹数等于0 无法进行射击
if (Input.GetMouseButtonDown(0))
{
// 当玩家按下鼠标按钮时,开始拉弓
animator.SetBool("Fire", true);
isHoldingBow = true;
}
if (Input.GetMouseButtonUp(0))
{
// 当玩家释放鼠标按钮时,松弓并射击
if (isHoldingBow)
{
isHoldingBow = false;
animator.SetBool("Fire", false);
//animator.SetTrigger("Shoot");
ShootArrow();
num--;
}
}
}
void ShootArrow()
{
// 检查箭矢预制体是否存在
if (arrowPrefab != null)
{
// 实例化箭矢
GameObject arrow = Instantiate(arrowPrefab, transform.position, transform.rotation);
// 获取箭矢上的刚体组件
Rigidbody arrowRigidbody = arrow.GetComponent<Rigidbody>();
Destroy(arrow, 10f);
// 检查刚体组件是否存在
if (arrowRigidbody != null)
{
// 为箭矢添加力,以使其沿着当前朝向射出
arrowRigidbody.AddForce(transform.forward * 10f, ForceMode.Impulse);
}
}
}
}
⑥TAD.cs TAD2.cs 控制击中靶子时的加分 挂载在静止靶/运动靶对象上
using UnityEngine;
public class TAD : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Arrow"))
{
Destroy(other.gameObject);
BowController.instance.AddScore();
}
}
}
using UnityEngine;
public class TAD2 : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Arrow"))
{
Destroy(other.gameObject);
BowController.instance.AddScore2();
}
}
}
⑦TriggerAC.cs 控制玩家碰到靶或树时游戏结束,挂载在树和靶子的预制体上
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"))
{
Cursor.lockState = CursorLockMode.Confined;
BowController.instance.panel.SetActive(true);
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Player"))
{
Cursor.lockState = CursorLockMode.Confined;
BowController.instance.panel.SetActive(true);
}
}
public void LoadS()
{
SceneManager.LoadScene(0);
}
}