首页 > 编程语言 > Unity实现3D射箭小游戏
2021
05-23

Unity实现3D射箭小游戏

Unity 小游戏:3D射箭,供大家参考,具体内容如下

前两周因为实训太忙,再加上自己对老师所讲的设计模式并不是很理解,所以就没有写博客。这次博客是记录3D射箭游戏的实现过程。

1. 准备资源

我是在网上找的弓与箭的资源,至于靶子,创建五个不同大小的同心圆柱体,如图所示:

需要注意的是,五个圆柱体并不在同一个平面上,这样才能够看清每一环的颜色,并且在检测碰撞时不会出现各种问题。

另外,如果靶子放得离相机太近,就没有射箭的感觉了;离相机太远,好像又看不清靶子了,然后我试着把靶子MaterialShader改为 Sprites/Default ,这样靶子离相机远一点也能看得很清晰。

2. 布置场景

把弓箭作为Main Camera的子物体,这样我们可以在用鼠标控制镜头移动时,使弓箭一直指向屏幕中心,以达到第一人称控制器的效果。

在此项目中,没有选择使用GUI来做UI界面,而是创建了一个Canvas,在这里面添加了一个Image用来显示弓箭的准心,以及四个Text来显示得分、风向、风力、提示等。

3. 编辑脚本

游戏采用MVC架构,大部分功能是自己实现的,也有一小些函数是借鉴大神的。整体上感觉有很多缺陷,但是又不知道怎么修改才好,我也很无奈啊!°(°?Д?°) °

下面是我的UML图:

以下是完整代码:

SSDirector.cs

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

public class SSDirector : System.Object {

    private static SSDirector _instance;

    public ISceneCotroller currentScenceCotroller {
        get;
        set;
    }

    public bool running {
        get;
        set;
    }

    public static SSDirector getInstance() {
        if (_instance == null) {
            _instance = new SSDirector ();
        }
        return _instance;
    }
}

ISceneCotroller.cs

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

public interface ISceneCotroller {
    void LoadResources ();
}

IUserAction.cs

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

public interface IUserAction {
    string getMyScore ();
    float getWind ();
    void Openbow ();
    void Draw ();
    void Shoot ();
}

ActionManager.cs

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

public class ActionManager : MonoBehaviour {

    private float Force = 0f;
    private int maxPower = 2500;
    private float power;
    public Transform arrowSpawn;
    public Transform myArrow;
    public Transform bow;

    //播放拉弓动画
    public void Openbow () {
        bow.GetComponent<Animation>().Play("Draw");
        bow.GetComponent<Animation>()["Draw"].speed = 1;
        bow.GetComponent<Animation>()["Draw"].wrapMode = WrapMode.Once;

        arrowSpawn.GetComponent<MeshRenderer>().enabled = true;

        //重置 power 为 0
        power = 0;
    }

    //拉弓,从power为0到power为3000
    public void Draw () {
        if(power < maxPower) {
            power += maxPower * Time.deltaTime;
        }
    }

    //射箭
    public void Shoot () {
        float percent = bow.GetComponent<Animation>()["Draw"].time / bow.GetComponent<Animation>()["Draw"].length;
        float shootTime = 1 * percent;

        bow.GetComponent<Animation>().Play("Shoot");
        bow.GetComponent<Animation>()["Shoot"].speed = 1;
        bow.GetComponent<Animation>()["Shoot"].time = shootTime;
        bow.GetComponent<Animation>()["Shoot"].wrapMode = WrapMode.Once;

        arrowSpawn.GetComponent<MeshRenderer>().enabled = false;
        Transform arrow= Instantiate (myArrow, arrowSpawn.transform.position, transform.rotation);
        arrow.transform.GetComponent<Rigidbody>().AddForce(transform.forward * power);

        wind (arrow);
        Force = Random.Range (-100, 100);
    }

    //产生风
    private void wind(Transform arrow) {
        arrow.transform.GetComponent<Rigidbody> ().AddForce (new Vector3 (Force, 0, 0), ForceMode.Force);
    }

    //返回风
    public float getWindForce() {
        return Force;
    }  
}

ScoreRecorder.cs

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

public class ScoreRecorder : MonoBehaviour {

    private string Score = "0";

    //判断得分
    public void countScore(string type) {
        Score = type;
    }

    //返回分数
    public string getScore () {
        return Score;
    }
}

FirstScene.cs

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

public class FirstScene : MonoBehaviour, ISceneCotroller, IUserAction {

    private ActionManager actionManager;
    private ScoreRecorder scoreRecorder;

    void Awake () {
        SSDirector director = SSDirector.getInstance ();
        director.currentScenceCotroller = this;
        director.currentScenceCotroller.LoadResources ();
        actionManager = (ActionManager)FindObjectOfType (typeof(ActionManager));
        scoreRecorder = (ScoreRecorder)FindObjectOfType (typeof(ScoreRecorder));
    }

    //加载预制物体靶子
    public void LoadResources () {
        Debug.Log ("loading...\n");
        GameObject target = Instantiate<GameObject> (
                                Resources.Load<GameObject> ("Prefabs/target"));
        target.name = "target";
    }

    //获得分数
    public string getMyScore () {
        return scoreRecorder.getScore ();
    }

    //获得风向和风力
    public float getWind () {
        return actionManager.getWindForce ();
    }

    //拉弓
    public void Openbow () {
        actionManager.Openbow ();
    }

    //蓄力
    public void Draw () {
        actionManager.Draw ();
    }

    //射箭
    public void Shoot () {
        actionManager.Shoot ();
    }
}

UserGUI.cs

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

public class UserGUI : MonoBehaviour {

    private IUserAction userAction;
    private FirstScene scene;
    private Quaternion m_CharacterTargetRot;

    public Text Score;
    public Text WindDirection;
    public Text WindForce;

    // Use this for initialization
    void Start () {
        userAction = SSDirector.getInstance ().currentScenceCotroller as IUserAction;
    }

    void Awake () {
        m_CharacterTargetRot = transform.localRotation;
    }

    void Update () {
        //镜头跟随鼠标
        float xRot = Input.GetAxis ("Mouse X") * 3f;
        float yRot = Input.GetAxis ("Mouse Y") * -3f;
        m_CharacterTargetRot *= Quaternion.Euler (yRot, xRot, 0f);
        transform.localRotation = Quaternion.Slerp (transform.localRotation, m_CharacterTargetRot,
            5f * Time.deltaTime);

        //按空格键使弓箭瞄准靶心
        if (Input.GetKeyDown (KeyCode.Space)) {
            m_CharacterTargetRot = Quaternion.Euler (0f, 0f, 0f);
            transform.localRotation = Quaternion.Slerp (transform.localRotation, m_CharacterTargetRot,
                5f * Time.deltaTime);
        }

        //鼠标左键按下,开始拉弓
        if (Input.GetMouseButtonDown (0)) {
            userAction.Openbow ();
        }

        //鼠标左键按住不放,蓄力
        if (Input.GetMouseButton (0)) {
            userAction.Draw ();
        }

        //鼠标左键抬起。射箭
        if (Input.GetMouseButtonUp (0)) {
            userAction.Shoot ();
        }

        Score.text = "Score : " + userAction.getMyScore ();     //显示上一轮分数
        float force = userAction.getWind ();
        if (force < 0) {
            WindDirection.text = "Wind Direction : <---";       //显示风向
        } else if (force > 0) {
            WindDirection.text = "Wind Direction : --->";
        } else {
            WindDirection.text = "Wind Direction : No";
        }
        WindForce.text = "Wind Force : " + Mathf.Abs (userAction.getWind ()); //显示风力
    }
}

Arrow.cs

using UnityEngine;
using System.Collections;

public class Arrow : MonoBehaviour {

    private RaycastHit hit;

    void  Update (){
        //检测在移动的箭
        if(GetComponent<Rigidbody>().velocity.magnitude > 0.5f) {
            CheckForHit();
        } else {
            enabled = false;
        }
        if (transform.position.y < -5) {
            Destroy (this.gameObject);      //将掉出地面以下的箭销毁
        }
    }

    //检测是否碰撞
    void CheckForHit (){
        float myVelocity = GetComponent<Rigidbody>().velocity.magnitude;
        float raycastLength = myVelocity * 0.03f;

        if(Physics.Raycast(transform.position, transform.forward, out hit, raycastLength)) {
            GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeAll;     //使箭停留在靶子上
            transform.position = hit.point;
            transform.parent = hit.transform;
            enabled = false;
        } else {
            Quaternion newRot = transform.rotation;
            newRot.SetLookRotation(GetComponent<Rigidbody>().velocity);
            transform.rotation = newRot;    //箭没中靶,则继续做抛物线运动
        }
    }
}

Target.cs

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

public class Target : MonoBehaviour {

    private ScoreRecorder scoreRecorder;

    public string score;    //对应靶环的分数

    public void Start() {
        scoreRecorder = (ScoreRecorder)FindObjectOfType (typeof(ScoreRecorder));
    }

    void OnTriggerEnter(Collider other) {
        if (other.gameObject.tag == "Arrow") {
            scoreRecorder.countScore (score);       //记录分数
        }
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自学编程网。

编程技巧