用unity完成地图射箭小游戏

用unity设计地图射箭的小游戏,用了对象池,单实例等方法,暂存,会详细补充

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

// 射箭动作
public class CCShootAction : SSAction
{
    private Vector3 pulseForce;  //射箭提供的冲量
    private CCShootAction(){}

    public static CCShootAction GetSSAction(Vector3 impulseDirection,float power)      //获得一个射箭动作实例
    {
        CCShootAction shootarrow = CreateInstance<CCShootAction>();
        
        shootarrow.pulseForce = impulseDirection.normalized * power;          // 射箭提供的冲量(方向*力度)
        return shootarrow;
    }

    public override void Start()
    {
        gameobject.transform.parent = null;        // 摆脱跟随弓移动
        gameobject.GetComponent<Rigidbody>().useGravity = true;                  //  发射的时候才开启重力
        gameobject.GetComponent<Rigidbody>().velocity = Vector3.zero;               // 初速度为0
        gameobject.GetComponent<Rigidbody>().AddForce(pulseForce,ForceMode.Impulse);        //添加冲量
        //关闭运动学控制
        gameobject.GetComponent<Rigidbody>().isKinematic = false;      // 此时箭的运动由物理引擎控制
    }

    public  override void Update(){
        
    }

    public override void FixedUpdate(){   // 判断箭是否飞出场景、落在地上或者射中靶子
        if(!gameobject || this.gameobject.tag == "ground" || this.gameobject.tag == "onTarget"  )  
        {
            this.destroy = true;     // 摧毁动作
            this.callback.SSActionEvent(this);
        }
    }
}


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

// 射箭动作的管理器
public class CCShootManager : SSActionManager, ISSCallback
{
    //箭飞行的动作
    private CCShootAction shoot;                                
    protected new void Start(){
    }

    public void SSActionEvent(SSAction source,  
        SSActionEventType events = SSActionEventType.Completed,
        int intParam = 0,
        string strParam = null,
        Object objectParam = null) {
    }

    //箭飞行
    public void ArrowShoot(GameObject arrow, Vector3 impulseDirection, float power)          // 游戏对象、力的方向、力的大小
    {
        shoot = CCShootAction.GetSSAction(impulseDirection, power);        //实例化一个射箭动作。
        RunAction(arrow, shoot, this);                  //调用SSActionmanager的方法运行动作。
    }
}


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

public enum SSActionEventType:int {Started, Completed}   // 枚举动作事件类型
public interface ISSCallback
{
    //回调函数
    void SSActionEvent(SSAction source,
        SSActionEventType events = SSActionEventType.Completed,
        int intParam = 0,
        string strParam = null,
        Object objectParam = null);
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 模板代码
// 动作的基类
public class SSAction : ScriptableObject
{
    public bool enable = true;                      //是否正在进行此动作
    public bool destroy = false;                    //是否需要被销毁
    public GameObject gameobject;                   //动作对象
    public Transform transform;                     //动作对象的transform
    public ISSCallback callback;              //动作完成后的消息通知者

    protected SSAction() { }
    //子类可以使用下面这两个函数
    public virtual void Start()
    {
        throw new System.NotImplementedException();
    }
    public virtual void Update()
    {
        throw new System.NotImplementedException();
    }
    public virtual void FixedUpdate()
    {
        throw new System.NotImplementedException();
    }
}

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

// 模板代码
// 动作管理器的基类
public class SSActionManager : MonoBehaviour
{
    private Dictionary<int,SSAction> actions = new Dictionary<int,SSAction>();  //执行动作的字典集
    //等待添加的动作
    private List<SSAction> waitingAdd = new List<SSAction>();
    //等待销毁的动作
    private List<int> waitingDelete = new List<int>();

    protected void Start(){
    }

    // Update每一帧都执行,执行的帧率取决于电脑性能
    protected void Update() 
    {
        //添加新增的动作
        for(int i = 0; i < waitingAdd.Count; ++i)
        {
            actions[waitingAdd[i].GetInstanceID()] = waitingAdd[i];
        }
        waitingAdd.Clear();
        //销毁需要删除的动作
        foreach (KeyValuePair<int,SSAction> kv in actions){
            SSAction ac = kv.Value;
            if(ac.destroy){
                waitingDelete.Add(ac.GetInstanceID());
            }
            //动作不需要销毁则更新
            else if(ac.enable){
                ac.Update();
            }
        }
        //销毁动作
        foreach (int key in waitingDelete){
            SSAction ac = actions[key];
            actions.Remove(key);
            Object.Destroy(ac);
        }
        waitingDelete.Clear();
    }
    // FixedUpdate每秒调用50次,适合用来写物理引擎相关的代码
    protected void FixedUpdate()
    {
        for(int i = 0; i < waitingAdd.Count; ++i)
        {
            actions[waitingAdd[i].GetInstanceID()] = waitingAdd[i];
        }
        waitingAdd.Clear();
        foreach (KeyValuePair<int,SSAction> kv in actions){
            SSAction ac = kv.Value;
            if(ac.destroy){
                waitingDelete.Add(ac.GetInstanceID());
            }
            else if(ac.enable){
                ac.FixedUpdate();
            }
        }

        foreach (int key in waitingDelete){
            SSAction ac = actions[key];
            actions.Remove(key);
            Object.Destroy(ac);
        }
        waitingDelete.Clear();
    }

    //新增一个动作,运行该动作
    public void RunAction(GameObject gameobject, SSAction  action, ISSCallback manager)
    {
        action.gameobject = gameobject;
        action.transform = gameobject.transform;
        action.callback = manager;
        waitingAdd.Add(action);
        action.Start();

    }

    //回调新的动作类型
    public void SSActionEvent(SSAction source, int param = 0,GameObject arrow = null)
    {
        //执行完飞行动作
    }
}

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

public class ArrowController : MonoBehaviour, ISceneController, IUserAction
{
    public GameObject main_camera;       // 主相机
    public CCShootManager arrow_manager;    //箭的动作管理者
    public ArrowFactory factory;    //箭的工厂
    public ScoreRecorder recorder;        // 计分对象
    public GameObject bow;     // 弓弩
    public GameObject target1, target2, target3, target4, large_target; // 四种不同的靶子和一个巨型靶子
    public GameObject arrow;       // 当前射出的箭
    public string message = "";   // 用于显示的信息
    private int arrow_num = 0;    // 装载的箭的数量
    public Animator ani;          // 动画控制器
    private List<GameObject> arrows = new List<GameObject>();    // 箭的队列
    private List<GameObject> flyed = new List<GameObject>();    // 飞出去的箭的队列

    public float longPressDuration = 2.0f; // 设置长按持续时间
    private bool isLongPressing = false;       // 是否正在长按
    private float pressTime = 0f;         // 长按的时间
    public int state = 0;  // 0-普通状态,1-拉弓状态,2-蓄力状态
    public float power = 0f;  // 拉弓的力度

    //加载箭和靶子
    public void LoadResources() {
        main_camera = transform.parent.GetChild(0).gameObject; // 获取摄像机
        bow = this.gameObject;

        // 获取地形对象
        Terrain terrain = GameObject.Find("Terrain").GetComponent<Terrain>();

        // 加载随机靶子
        for (int i = 0; i < 15; ++i) {
            LoadTargetOnTerrain("target", 10 + i, terrain);
        }
    }


    GameObject LoadTargetOnTerrain(string name, int score, Terrain terrain) {
        // 随机生成靶子在地形上的位置
        float terrainWidth = terrain.terrainData.size.x;
        float terrainLength = terrain.terrainData.size.z;

        // 随机生成 (x, z) 坐标
        float randomX = Random.Range(0, terrainWidth);
        float randomZ = Random.Range(0, terrainLength);

        // 获取地形在 (x, z) 的高度
        float terrainHeight = terrain.SampleHeight(new Vector3(randomX, 0, randomZ));

        // 靶子的位置在地形表面上方 3f
        Vector3 targetPosition = new Vector3(randomX, terrainHeight + 3f, randomZ);

        // 加载靶子
        GameObject target = GameObject.Instantiate(Resources.Load(name, typeof(GameObject))) as GameObject;
        target.transform.position = targetPosition;
        target.AddComponent<TargetController>();
        target.GetComponent<TargetController>().RingScore = score;

        return target;
    }


    //进行资源加载
    void Start()
    {
        arrow = null;   
        SSDirector director = SSDirector.getInstance();
        director.currentSceneController = this;
        director.currentSceneController.LoadResources();
        gameObject.AddComponent<ArrowFactory>();
        gameObject.AddComponent<ScoreRecorder>();
        gameObject.AddComponent<UserGUI>(); 
        gameObject.AddComponent<BowController>();
        factory = Singleton<ArrowFactory>.Instance;
        recorder = Singleton<ScoreRecorder>.Instance;
        arrow_manager = this.gameObject.AddComponent<CCShootManager>() as CCShootManager; 
        ani = GetComponent<Animator>();

    }

    void Update()
    {
        //Debug.Log("Update running"); // 检查 Update 是否正常执行
        Shoot();              // 射击
        HitGround();           // 检测箭是否射中地面
        for(int i = 0; i < flyed.Count; ++i)         // 用于维护已经射出去的箭的队列
        {   
            GameObject t_arrow = flyed[i];
            if(flyed.Count > 10 || t_arrow.transform.position.y < -10)   // 箭的数量大于10或者箭的位置低于-10
            {   // 删除箭
                flyed.RemoveAt(i);
                factory.RecycleArrow(t_arrow);
            }
        }
        if(Input.GetKeyDown(KeyCode.R))         // 按R换弹
        {   //从工厂得到箭
            LoadArrow();
            message = "弩箭已填充完毕";
        }
    }

    public void Shoot()   // 射击
    {
        if(arrows.Count > 0){    // 确保有箭
            if(!gameObject.GetComponent<BowController>().canshoot && (Input.GetMouseButtonDown(0) || Input.GetButtonDown("Fire2"))){
                //message = "请按1、2、3到指定地点射击";
            }
            else{
                aniShoot();
            } 
        }
        else{
            message = "请按R键以装载弓箭";
        }
    }

    public void aniShoot() { // 射击的动画
        if (Input.GetKeyDown(KeyCode.Space) && state == 0) {
            // 开始拉弓
            message = "";
            transform.GetChild(3).gameObject.SetActive(true);
            isLongPressing = true;
            ani.SetTrigger("pull");
            pressTime = Time.time;
            state = 1;
        }

        if (Input.GetKey(KeyCode.Space) && state == 1) {
            // 计算拉弓持续时间和力度
            float duration = Time.time - pressTime;
            power = Mathf.Clamp(duration / longPressDuration, 0, 1);
            ani.SetFloat("power", power);

            if (duration >= longPressDuration || power >= 1.0f) {
                // 达到最大蓄力,进入“hold”状态
                ani.SetTrigger("hold");
                state = 2;
            }
        }

        if (Input.GetKeyUp(KeyCode.Space)) {
            if (state == 1 || state == 2) {
                // 松开空格,执行射击
                isLongPressing = false;
                ani.SetTrigger("shoot");

                // 设置动作中的箭不可见
                transform.GetChild(3).gameObject.SetActive(false);

                // 发射箭矢
                arrow = arrows[0];
                arrow.SetActive(true);
                flyed.Add(arrow);
                arrows.RemoveAt(0);
                arrow_manager.ArrowShoot(arrow, main_camera.transform.forward, power);


                // 恢复力度
                ani.SetFloat("power", 1.0f);
                arrow_num -= 1;
                state = 0;
            }
        }
    }

    public void LoadArrow(){          // 获得10支箭
        arrow_num = 10;
        while(arrows.Count!=0){     // 清空队列   
            factory.RecycleArrow(arrows[0]);
            arrows.RemoveAt(0);
        }
        for(int i=0;i<10;i++){
            GameObject arrow = factory.GetArrow();
            arrows.Add(arrow);
        }
    }

    public void HitGround(){               // 检测箭是否射中地面
        RaycastHit hit;
        if (arrow!=null && Physics.Raycast(arrow.transform.position, Vector3.down, out hit, 0.2f))
        {
            // 如果射线与地面相交
            if (hit.collider.gameObject.name == "Terrain")
            {
                arrow.tag = "ground";
                //将箭的速度设为0
                arrow.GetComponent<Rigidbody>().velocity = new Vector3(0,0,0);
                //使用运动学运动控制
                arrow.GetComponent<Rigidbody>().isKinematic = true;
            }
        }
    }

    //返回当前分数
    public int GetScore(){
        return recorder.score;
    }

    //得到剩余的箭的数量
    public int GetArrowNum(){
        return arrow_num;
    }

    // 显示的信息
    public string GetMessage(){
        return message;
    }
}

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

// 箭的工厂,用于创建箭和回收箭
public class ArrowFactory : MonoBehaviour
{
    public ArrowController arrowCtrl;
    public GameObject arrow;
    void Start()
    {
        arrowCtrl = (ArrowController)SSDirector.getInstance().currentSceneController;
    }

    void Update(){
    }

    public GameObject GetArrow(){    // 获取空闲的箭
        arrow = GameObject.Instantiate(Resources.Load("Arrow", typeof(GameObject))) as GameObject;
        //得到弓箭上搭箭的位置                       
        Transform bow_mid = arrowCtrl.bow.transform.GetChild(3);   // 获得箭应该放置的位置

        arrow.transform.position = bow_mid.transform.position;               //将箭的位置设置为弓中间的位置
        arrow.transform.rotation = Quaternion.LookRotation(arrowCtrl.bow.transform.up);
        arrow.transform.parent = arrowCtrl.bow.transform;        //箭随弓的位置变化
        arrow.gameObject.SetActive(false);

        return arrow;
    }

    public void RecycleArrow(GameObject arrow)        // 回收箭
    {
        arrow.SetActive(false);
        DestroyImmediate(arrow);
    }
}


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

// 挂载在子对象上,控制父对象的移动、跳跃和视角旋转
public class BowController : MonoBehaviour     
{
    public float moveSpeed = 6f;              // 移动速度
    public float angularSpeed = 90f;         // 旋转速度
    public float horizontalRotateSensitivity = 5f; // 水平视角灵敏度
    public float verticalRotateSensitivity = 5f;   // 垂直视角灵敏度
    private float xRotation = 0f;            // X轴旋转角度
    public float jumpForce = 5f;             // 跳跃力度
    public bool isGrounded = true;          // 是否接触地面
    public bool canshoot = false;        // 是否可以射箭
    //private Rigidbody parentRb;              // 父对象的 Rigidbody

    void Start()
    {
        // parentRb = transform.parent.GetComponent<Rigidbody>();
        // if (parentRb == null)
        // {
        //     Debug.LogError("父对象缺少 Rigidbody 组件");
        // }
    }

    void FixedUpdate()        
    {
        Move();   // 控制移动
        View();   // 控制视角
    }

    void Move()      
    {
        float v = Input.GetAxis("Vertical");
        float h = Input.GetAxis("Horizontal");
 
        // 控制父对象移动
        transform.parent.Translate(Vector3.forward * v * Time.deltaTime * moveSpeed);
        transform.parent.Translate(Vector3.right * h * Time.deltaTime * moveSpeed);

        // 跳跃逻辑
        // if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
        // {
        //     parentRb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
        //     isGrounded = false; // 跳跃后设置为未接触地面
        // }
    }

    void SetCursorToCentre()   
    {
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.lockState = CursorLockMode.None;
        Cursor.visible = false;
    }

    void View()    
    {
        SetCursorToCentre(); // 锁定鼠标到屏幕中心
        
        float mouseX = Input.GetAxis("Mouse X") * Time.deltaTime * angularSpeed * horizontalRotateSensitivity;
        transform.parent.Rotate(Vector3.up * mouseX); // 水平旋转

        float mouseY = Input.GetAxis("Mouse Y") * Time.deltaTime * angularSpeed * verticalRotateSensitivity;
        xRotation -= mouseY;
        xRotation = Mathf.Clamp(xRotation, -45f, 45f); // 限制上下视角
        transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f); // 控制弓的上下视角
    }

    // private void OnCollisionEnter(Collision collision)
    // {
    //     if (collision.gameObject.name == "Terrain")
    //     {
    //         isGrounded = true;
    //     }
    // }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 场景控制器接口,与场景控制有关的函数都在这里
public interface ISceneController
{
    void LoadResources();    // 加载资源
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 计分器类
public class ScoreRecorder : MonoBehaviour
{
    public int score;
    void Start()
    {
        score = 0;
    }

    public void RecordScore(int ringscore)
    {
       score += ringscore;        //增加新的值
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UserGUI : MonoBehaviour
{
    private IUserAction action;
    GUIStyle style1 = new GUIStyle();
    GUIStyle style2 = new GUIStyle();
    public string message = "";        // 显示的信息
    int screenWidth, screenHeight;

    void Start()
    {
        action = this.transform.gameObject.GetComponent<IUserAction>();

        style1.normal.textColor = Color.red;
        style1.fontSize = 30;

        style2.normal.textColor = Color.yellow;
        style2.fontSize = 40;
    }

    void Update()
    {
        screenWidth = Screen.width;
        screenHeight = Screen.height;
    }

    private void OnGUI()
    {
        //显示各种信息
        GUI.Label(new Rect(20,10,150,50),"得分: ",style1);
        GUI.Label(new Rect(100,10,150,50),action.GetScore().ToString(),style2);
        
        GUI.Label(new Rect(20,50,150,50),"剩余箭矢数: ",style1);
        GUI.Label(new Rect(200,50,150,50),action.GetArrowNum().ToString(),style2);

        GUI.Label(new Rect(150,100,150,50),action.GetMessage(),style1);

        GUI.Label(new Rect(screenWidth/2+10,screenHeight/2,150,50),"o",style2);
    }
}