对于射箭小游戏来说,新增加了物理引擎的运用。物理引擎主要包括三个方面: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());
//方法二:
GameObject.GetComponent().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().velocity = dir * speed;//设置箭矢速度
//Debug.Log(arrow.GetComponent().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().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().Sleep();
foreach (CapsuleCollider i in comp)
{
i.enabled = false;
}
//使得箭矢不会触发靶子上的箭
GetComponent().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 : 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.Instance as IQuery;
scene = Singleton.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.Instance;
arrowFactory = Singleton.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 usedArrow; //储存使用中的箭矢
private List freeArrow; //储存空闲箭矢
private GameObject arrowPrefab;
void Awake()
{
//arrowPrefab = Instantiate(Resources.Load("Arrows/Arrows")) as GameObject;
//arrowPrefab.SetActive(false);
freeArrow = new List();
usedArrow = new List();
//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() == null)
obj.AddComponent();
Component[] comp = obj.GetComponentsInChildren();
foreach (CapsuleCollider i in comp)
{
i.enabled = true;
}
obj.GetComponent().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.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.Instance;
}
public void shoot(GameObject arrow, Vector3 dir)
{
arrow.transform.up = dir;//弓箭的朝向
//Debug.Log("arrow_shoot");
arrow.GetComponent().velocity = dir * speed;//设置箭矢速度
//Debug.Log(arrow.GetComponent().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().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());//使得箭矢停留在靶子上
GetComponent().Sleep();
/*Component[] comp = GetComponentsInChildren();
foreach (CapsuleCollider i in comp)
{
i.enabled = false;
}
*/
//使得箭矢不会触发靶子上的箭
GetComponent().isTrigger = false;
judge.countPoint(bartNum);//记录分数
}
}
void Awake()
{
time = 0;
bartNum = " ";
judge = Singleton.Instance;
}
void Update()
{
time += Time.deltaTime;
if(time >= LIMITTIME)
{
this.gameObject.SetActive(false);
time = 0;
bartNum = " ";
}
}
}
学习了这么久,终于有空来写篇博客,记录下自己的学习过程,感觉也蛮开心的。