Unity3D学习之射箭小游戏

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Kiloveyousmile/article/details/69491549

一、了解基础知识

  对于射箭小游戏来说,新增加了物理引擎的运用。物理引擎主要包括三个方面:Rigidbody、Collide、PhysicMaterial。其中,Collider是最基本的触发物理的条件,例如碰撞检测。基本上,没有Collider物理系统基本没有意义(除了重力);Rigidbody是物体的基本物理属性设置,当检测碰撞完之后,就要计算物理效果,而Rigidbody就是提供计算基本参数的组件;PhysicMaterial则是附加的基本物理参数,是一个物理材质,UNITY3D有自带默认的物理材质的系数(在Edit/Project Settings/Physic下设置),它参与碰撞的计算例如反弹效果摩擦效果等。当然,我们这个游戏用到的只有前两个。
  要注意:

1.碰撞事件 = 大于等于一个刚体+两个碰撞器+istrigle为true
2.两个对象,一个具备刚体属性+碰撞器,另一个只具备碰撞器,拿前者碰撞后者,is Trigle为true,那么则会发生碰撞。如果脚本控制的是位移而不是物理加力的方式的话,将穿透过去;直接碰撞,则会被弹开。
3、禁用或者停用Rigidbody组件,两种方式:

//方法一:
Destroy(GameObject.GetComponent<Rigidbody>());
//方法二:
GameObject.GetComponent<Rigidbody>().Sleep();

当然,第一种方法直接删除,开销较大,不推荐。
4.碰撞触发事件的用法。is Trigle为true,在对象的脚本里调用函数:

void OnTriggerEnter(Collider other);

记住,千万不用弄错了函数名称的大小写。虽然不会报错,但是,会失效的。

二、游戏设计及代码

  游戏设计图:
  这里写图片描述
  游戏预设及效果:
  弓箭
  箭靶
  效果图
  具体的参数,可以自己慢慢尝试调整,这里就不一一列出了。
  代码设计实现
  这部分,首先需要实现的是箭矢的发射:

  public void shoot(GameObject arrow, Vector3 dir)
  {
        arrow.transform.up = dir;//弓箭的朝向
        //Debug.Log("arrow_shoot");
        arrow.GetComponent<Rigidbody>().velocity = dir * speed;//设置箭矢速度
        //Debug.Log(arrow.GetComponent<Rigidbody>().velocity);
        force = Random.Range(-80f, 80f);//获取随机风力
        Wind(arrow);//添加风效果
        scene.setForce(force);//设置风力

        if(force < 0)
        {
            scene.setDirection(Direction.Left);//设置风向
        }
        else if(force > 0)
        {
            scene.setDirection(Direction.Right);
        }
        else
        {
            scene.setDirection(Direction.Nowind);
        }
    }

    private void Wind(GameObject arrow)
    {
        Debug.Log("AddForce");
        arrow.GetComponent<Rigidbody>().AddForce(new           
        Vector3(force, 0, 0), ForceMode.Force);//对箭矢施加恒定风力
    }

  其中,朝向通过鼠标点击屏幕,获取射线的方向以作为弓箭方向:

if(Input.GetMouseButtonDown(0))
{
   Ray mouseRay = camera.ScreenPointToRay(Input.mousePosition);//获取射线,以射线方向作为箭矢方向
   scene.shootArrow(mouseRay.direction);//点击发射箭矢
}

  接着,需要实现弓箭插在箭靶上,并且再一段时间时间后回收箭靶:
  

void OnTriggerEnter(Collider other)//触发时间,取消箭矢刚体属性
{
     if (bartNum == " ")
     {
          bartNum = other.gameObject.name;
          GetComponent<Rigidbody>().Sleep();
          foreach (CapsuleCollider i in comp)
          {
              i.enabled = false;
          }
          //使得箭矢不会触发靶子上的箭
          GetComponent<MeshCollider>().isTrigger = false;
          judge.countPoint(bartNum);//记录分数
      }
}

//********************************
  void Update()
  {
         time += Time.deltaTime;
         if(time >= LIMITTIME)
         {
              this.gameObject.SetActive(false);
              time = 0;
              bartNum = " ";
        }
  }

以上基本都实现了,那么射箭小游戏也就完成了。
另外,注意一下,下面语句中的name指的是什么:

bartNum = other.gameObject.name;

这里写图片描述

附上完整代码:
Singleton.cs

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

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{


    protected static T instance;

    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                instance = (T)FindObjectOfType(typeof(T));
                if (instance == null)
                {
                    Debug.LogError("An instance of" + typeof(T) +
                        "is need in the scene, but there is none.");
                }
            }
            return instance;
        }
    }
}

UserInterface.cs

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

public class UserInterface : MonoBehaviour {
    private IQuery query;
    private SceneController scene;
    public Camera camera;
    public Text Score;
    public Text WindForce;
    public Text WindDirection;

    void Start()
    {
        query = Singleton<SceneController>.Instance as IQuery;
        scene = Singleton<SceneController>.Instance;
    }

    void Update()
    {
        Score.text = "Score : " + query.getPoint();//显示分数

        WindForce.text = "Wind Force : " + query.getWindForce();//显示风力
        Direction dir = query.getWindDirection();//显示风向
        if(dir == Direction.Left)
        {
            WindDirection.text = "Wind Direction : left";
        }
        else if(dir == Direction.Right)
        {
            WindDirection.text = "Wind Direction : right";
        }
        else if(dir == Direction.Nowind)
        {
            WindDirection.text = "Wind Direction : No wind";
        }

        if (Input.GetMouseButtonDown(0))
        {
            Ray mouseRay = camera.ScreenPointToRay(Input.mousePosition);//获取射线,以射线方向作为箭矢方向
            scene.shootArrow(mouseRay.direction);//点击发射箭矢
        }
    }
}

SceneController.cs

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

/**
 * 用户查询接口
 * 查询分数
 * 查询风力
 * 查询风向
 * */
public interface IQuery
{
    int getPoint();
    float getWindForce();
    Direction getWindDirection();
}

public enum Direction { Left, Right, Nowind };
public class SceneController : MonoBehaviour, IQuery{
    //获取单实例
    private ActionManager actionManager;//动作管理员
    private ArrowFactory arrowFactory;//弓箭管理工厂

    public int point;//分数
    public float force;//风力
    public Direction dir;//风向

    private GameObject arrow;
    private GameObject bart;

    void Awake()
    {
        Director director = Director.getInstance();
        director.setFPS(60);
        director.scene = this;
        actionManager = Singleton<ActionManager>.Instance;
        arrowFactory = Singleton<ArrowFactory>.Instance;
    }

    //加载场景
    void Start()
    {
        loadScene();
    }

    //*******************类中其他函数*******************
    //实现射箭的动作
    public void shootArrow(Vector3 dir)
    {
        arrow = arrowFactory.getArrow(); //获得箭矢
        float x = Random.Range(-1f, 1f);
        float y = Random.Range(-1f, 1f);
        arrow.transform.position = new Vector3(x, y, 0); //设置箭矢初始位置 
        actionManager.shoot(arrow, dir);//调用ActionManager实现动作细节
    }
    //设置分数
    public void setPoint(int _point)
    {
        point = _point;
    }
    //设置风力
    public void setForce(float _force)
    {
        force = _force;
    }
    //设置风向
    public void setDirection(Direction _dir)
    {
        dir = _dir;
    }

    //*****************实现接口**************************
    //获取分数
    public int getPoint()
    {
        return point;
    }
    //获取风力
    public float getWindForce()
    {
        return force;
    }
    //获取风向
    public Direction getWindDirection()
    {
        return dir;
    }
    //*****************辅助函数**************************
    //加载箭靶
    void loadScene()
    {
        bart = Instantiate(Resources.Load("Gameobject/Gameobject")) as GameObject;

    }
}

ArrowFactory.cs

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

public class ArrowFactory : MonoBehaviour
{
    private List<GameObject> usedArrow; //储存使用中的箭矢  
    private List<GameObject> freeArrow; //储存空闲箭矢  
    private GameObject arrowPrefab;

    void Awake()
    {
        //arrowPrefab = Instantiate(Resources.Load("Arrows/Arrows")) as GameObject;
        //arrowPrefab.SetActive(false);
        freeArrow = new List<GameObject>();
        usedArrow = new List<GameObject>();
        //Debug.Log("ArrowFactory");
    }
    public GameObject getArrow()
    {
        GameObject obj;
        if (freeArrow.Count == 0)//如果无可使用弓箭,实例化一个
        {
            obj = GameObject.Instantiate(Resources.Load("Arrows/Arrows")) as GameObject;
            obj.SetActive(true);
        }

        else//否则,复用。且添加刚体属性
        {
            obj = freeArrow[0];
            obj.SetActive(true);
            if (obj.GetComponent<Rigidbody>() == null)
                obj.AddComponent<Rigidbody>();
            Component[] comp = obj.GetComponentsInChildren<CapsuleCollider>();
            foreach (CapsuleCollider i in comp)
            {
                i.enabled = true;
            }

            obj.GetComponent<MeshCollider>().isTrigger = true;
            freeArrow.RemoveAt(0);//空闲箭矢中有箭矢,初始化相关属性,加入使用 
        }
        usedArrow.Add(obj);
        return obj;
    }

    private void FreeArrow()
    {
        for (int i = 0; i < usedArrow.Count; i++)
        {
            GameObject temp = usedArrow[i];
            if (!temp.activeInHierarchy)
            {
                usedArrow.RemoveAt(i);
                freeArrow.Add(temp);
            }
        }
    }

    void Update()
    {
        FreeArrow();
    }
}

Judge.cs

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

public class    Judge : MonoBehaviour {
    private SceneController scene;

    void Awake()
    {
        scene = Singleton<SceneController>.Instance;
    }

    //判断射中的靶并赋予相应的分数
    public void countPoint(string type)
    {
        if(type == "Cylinder1")
        {
            scene.setPoint(scene.getPoint() + 10);
        }
        else if(type == "Cylinder2")
        {
            scene.setPoint(scene.getPoint() + 8);
        }
        else if(type == "Cylinder3")
        {
            scene.setPoint(scene.getPoint() + 6);
        }
        else if(type == "Cylinder4")
        {
            scene.setPoint(scene.getPoint() + 4);
        }
        else if(type == "Cylinder5")
        {
            scene.setPoint(scene.getPoint() + 2);
        }
    }
}

ActionManager.cs

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

public class ActionManager : MonoBehaviour {
    private float speed = 30f;//箭矢的初速度
    private float force = 0f;//风力初始值
    private SceneController scene;

    void Awake()
    {
        scene = Singleton<SceneController>.Instance;
    }

    public void shoot(GameObject arrow, Vector3 dir)
    {
        arrow.transform.up = dir;//弓箭的朝向
        //Debug.Log("arrow_shoot");
        arrow.GetComponent<Rigidbody>().velocity = dir * speed;//设置箭矢速度
        //Debug.Log(arrow.GetComponent<Rigidbody>().velocity);
        force = Random.Range(-80f, 80f);//获取随机风力
        Wind(arrow);//添加风效果
        scene.setForce(force);//设置风力

        if(force < 0)
        {
            scene.setDirection(Direction.Left);//设置风向
        }
        else if(force > 0)
        {
            scene.setDirection(Direction.Right);
        }
        else
        {
            scene.setDirection(Direction.Nowind);
        }
    }

    private void Wind(GameObject arrow)
    {
        Debug.Log("AddForce");
        arrow.GetComponent<Rigidbody>().AddForce(new 
        Vector3(force, 0, 0), ForceMode.Force);//对箭矢施加恒定风力
    }
}

Director.cs

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

public class Director : System.Object {
    private static Director _instance;
    public SceneController scene { get; set; }

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

    public int getFPS()
    {
        return Application.targetFrameRate;
    }

    public void setFPS(int fps)
    {
        Application.targetFrameRate = fps;
    }
}

ArrowScipt.cs

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

public class ArrowScipt : MonoBehaviour {
    private string bartNum;
    private Judge judge;
    private float time;//计时器
    private static float LIMITTIME = 4;

    void OnTriggerEnter(Collider other)//触发时间,取消箭矢刚体属性
    {
        if (bartNum == " ")
        {
            bartNum = other.gameObject.name;

            //Destroy(GetComponent<Rigidbody>());//使得箭矢停留在靶子上
            GetComponent<Rigidbody>().Sleep();
            /*Component[] comp = GetComponentsInChildren<CapsuleCollider>();
            foreach (CapsuleCollider i in comp)
            {
                i.enabled = false;
            }
            */

            //使得箭矢不会触发靶子上的箭
            GetComponent<MeshCollider>().isTrigger = false;
            judge.countPoint(bartNum);//记录分数
        }
    }

    void Awake()
    {
        time = 0;
        bartNum = " ";
        judge = Singleton<Judge>.Instance;
    }

    void Update()
    {
         time += Time.deltaTime;
         if(time >= LIMITTIME)
         {
              this.gameObject.SetActive(false);
              time = 0;
              bartNum = " ";
        }
    }
}

  学习了这么久,终于有空来写篇博客,记录下自己的学习过程,感觉也蛮开心的。

展开阅读全文

没有更多推荐了,返回首页