Unity 弓箭射靶游戏实践

一、实现思路

根据之前的飞碟工厂进行改变,在射出弓箭手上没有弓箭之后重新生成新的弓箭,并将射出的弓箭在一定时间后进行回收。在右下角通过小窗口展示靶子的情况,射中不同的环数给予不同得分。

二、主要涉及技术

物理引擎的使用、游戏对象的生产与回收、物体碰撞、刚体编程

三、图形设计

(一)靶子的实现

通过不同大小但是对称轴重合的圆柱体实现靶子。需要注意的是:当圆柱体的高完全相同时,外面更大的圆柱体会覆盖里面更小的圆柱体。所以需要进行一些设置:多个圆柱体从里往外高逐渐递减
在这里插入图片描述
如上图所示。
另外还需要对物体进行一些碰撞相关的设置:将根组件设为 Rigidbody ,其他子组件设置为 Mesh Renderer

(二)弓箭

弓箭主要引用Unity商店资源下载。
在这里插入图片描述
在这里插入图片描述

(三)加入天空特效

在引入 Fantasy Skybox 资源之后,在window属性进行设置并将相机添加skybox。
在这里插入图片描述

四、原理实现

1. FirstController.js

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

public class FirstSceneController : MonoBehaviour, IUserAction, ISceneController { 
    public Camera child_camera;
    public ScoreRecorder recorder;
    public ArrowFactory arrow_factory;
    public ArrowFlyActionManager action_manager;

    public GameObject bow;
    private GameObject arrow;                   
    private GameObject target;
    private int round = 0;

    private bool game_over = false;
    private bool game_start = false; 
    private string wind_name = "";  
    private Vector3 wind = new Vector3(0, 0, 0);
    private Vector3 force;

    void Start () {
        SSDirector director = SSDirector.GetInstance();
        arrow_factory = Singleton<ArrowFactory>.Instance;
        recorder = Singleton<ScoreRecorder>.Instance;
        director.CurrentScenceController = this;
        action_manager = gameObject.AddComponent<ArrowFlyActionManager>() as ArrowFlyActionManager;
        LoadResources();
        CreateWind();
    }

    void Update () {
        if(game_start) {
            Vector3 mpos = Camera.main.ScreenPointToRay(Input.mousePosition).direction;
            if (Input.GetButtonDown("Fire1")) {
                Shoot(mpos * 15 );
            }
            if (arrow == null) {
                arrow = arrow_factory.GetArrow();
                arrow.transform.position = bow.transform.position;
                arrow.gameObject.SetActive(true);
                arrow.GetComponent<Rigidbody>().isKinematic = true;
            }
            bow.transform.LookAt(mpos * 30);
            arrow.transform.LookAt(mpos * 30);
            arrow_factory.FreeArrow();
        }
    }
    
    public void LoadResources() {
        bow = Instantiate(Resources.Load("Prefabs/bow", typeof(GameObject))) as GameObject;
        target = Instantiate(Resources.Load("Prefabs/target", typeof(GameObject))) as GameObject;
    }
    
    public void Shoot(Vector3 force) {
        if (arrow != null) {
            arrow.GetComponent<Rigidbody>().isKinematic = false;
            action_manager.ArrowFly(arrow, wind, force);
            child_camera.GetComponent<ChildCamera>().StartShow();
            arrow = null;
            CreateWind();
            round++;
        }
    }

    public int GetScore() {
        return recorder.score;
    }

    public bool GetGameover() {
        return game_over;
    }

    public string GetWind() {
        return wind_name;
    }

    public void CreateWind() {
        float wind_directX = ((Random.Range(-10, 10) > 0) ? 1 : -1) * round;
        float wind_directY = ((Random.Range(-10, 10) > 0) ? 1 : -1) * round;
        Debug.Log(wind_directX);
        wind = new Vector3(wind_directX, wind_directY, 0);

        string Horizontal = "", Vertical = "", level = "";
        if (wind_directX > 0) {
            Horizontal = "西";
        } else if (wind_directX <= 0) {
            Horizontal = "东";
        }
        if (wind_directY > 0) {
            Vertical = "南";
        } else if (wind_directY <= 0) {
            Vertical = "北";
        }
        level = round.ToString();
        wind_name = Horizontal + Vertical + "风" + " " + level;
    }

    public void BeginGame() {
        Cursor.visible = false;
        game_start = true;
    }
}

2. 箭矢工厂

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

//工厂模式,箭工厂
public class ArrowFactory : MonoBehaviour {
    public GameObject arrow = null;                             
    private List<GameObject> used = new List<GameObject>();   
    private Queue<GameObject> free = new Queue<GameObject>();  
    public FirstSceneController sceneController;

    public void Start() {
        sceneController = (FirstSceneController)SSDirector.GetInstance().CurrentScenceController;
    }
    public GameObject GetArrow() {
        if (free.Count == 0) {
            arrow = Instantiate(Resources.Load<GameObject>("Prefabs/arrow"));
        } else {
            arrow = free.Dequeue();
            arrow.gameObject.SetActive(true);
        }
        used.Add(arrow);
        return arrow;
    }

    public void FreeArrow() {
        for (int i = 0; i < used.Count; i++) {
            if (used[i].gameObject.transform.position.y < -30) {
                used[i].gameObject.SetActive(false);
                free.Enqueue(used[i]);
                used.Remove(used[i]);
                break;
            }
        }
    }
}

3. 箭矢运动

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

public class ArrowFlyAction : SSAction {
    public Vector3 _force;
    public Vector3 _wind;

    private ArrowFlyAction() { }
    public static ArrowFlyAction GetSSAction(Vector3 wind, Vector3 force) {
        ArrowFlyAction action = CreateInstance<ArrowFlyAction>();
        action._force = force;
        action._wind = wind;
        return action;
    }
    public override void Start() {
        gameobject.GetComponent<Rigidbody>().AddForce(_force, ForceMode.Impulse);
        gameobject.GetComponent<Rigidbody>().AddForce(_wind);
    }

    public override void Update() {}

    //使用物理引擎
    public override void FixedUpdate(){
        if (transform.position.y < -30) {
            this.destroy = true;
            this.callback.SSActionEvent(this);
        }
    }
}

4. 箭矢运动控制

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

//模仿飞碟游戏更改
public class ArrowFlyActionManager : SSActionManager {
    private ArrowFlyAction fly; 
    public FirstSceneController scene_controller; 
    protected void Start() {
        scene_controller = (FirstSceneController)SSDirector.GetInstance().CurrentScenceController;
        scene_controller.action_manager = this;
    }

    public void ArrowFly(GameObject arrow, Vector3 wind, Vector3 force) {
        fly = ArrowFlyAction.GetSSAction(wind, force);
        this.RunAction(arrow, fly, this);
    }
}


5. 碰撞检测

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

//碰撞检测器,检测碰撞
public class CollisionDetection : MonoBehaviour {
    public FirstSceneController scene_controller;
    public ScoreRecorder recorder;

    void Start() {
        scene_controller = SSDirector.GetInstance().CurrentScenceController as FirstSceneController;
        recorder = Singleton<ScoreRecorder>.Instance;
    }

    void OnTriggerEnter(Collider arrow_head) {
        Transform arrow = arrow_head.gameObject.transform.parent;
        if (arrow == null) return;
        arrow.GetComponent<Rigidbody>().isKinematic = true;
        arrow_head.gameObject.SetActive(false);
        recorder.Record(this.gameObject);
    }
}

项目原码: github
演示视频:bilibili

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值