Unity3D 從入門到放棄(五)----射箭遊戲
Unity3D 從入門到放棄(五)
—-射箭遊戲
填坑啊填坑,每週都補上週作業,啥時候才能到頭啊= =
作業需求
遊戲規則:
設計一個射箭小遊戲,點選滑鼠射箭:
靶物件為 5 環,按環計分;
箭物件,射中後要插在靶上;
遊戲僅一輪,無限 trials;
例項化部分
本次作業有箭,靶兩種例項,實現如下:
箭:
箭分為三個部分,箭頭,箭身,箭尾。
箭頭:通過一個圓錐和一個圓來實現。圓可以由高度為0的圓錐生成。箭頭加上Mesh碰撞器並設定為觸發器。(圓錐可以通過Editor資料夾中的CreateCone中創造的選單實現)
箭身:通過一個圓柱來實現。
箭尾:通過兩個雙面四邊形實現,由於unity3d預設渲染單面,因此要四個。(四邊形可以通過Editor資料夾中的CreateRectangle中創造的選單實現)
為了新增重力,箭總體加入一個剛體。
最後,將製作好的箭加入預設,作為初始物體。靶:
製作六個圓柱體,分別上不同顏色,並將內圈scale.Y的大小稍微調大一點以顯示顏色,調整好角度,加上Mesh碰撞器即可。文字框:
通過UI中的Text建立文字框,此處不再闡述。
效果如圖:
箭:
靶:
打地基部分:
由於這次用的圓錐和四邊形都不是unity3d自帶的結構,因此需要自己創造。
首先,先建立一個Editor資料夾:(unity3d預設在Editor資料夾中的內容不能掛載,用於實現一些自動呼叫的指令碼)
然後,在資料夾內新增CreateCone和CreateRectangle指令碼:
指令碼內容如下:
CreateCone:
/*
* 描 述:用於建立圓錐的檔案,我只是大自然的搬運工
* 作 者:hza
* 建立時間:2017/04/06 13:20:14
* 版 本:v 1.0
*/
using UnityEngine;
using UnityEditor;
using System.Collections;
public class CreateCone : ScriptableWizard
{
/**
* Num Vertices is the number of vertices each end will have.
* Radius Top is the radius at the top. The center point will be located at (0/0/0).
* Radius Bottom is the radius at the bottom. The center point will be located at (0/0/Length).(底圓的半徑大小)
* Length is the number of world units long the plane will be (+Z direction).
* Opening Angle If this is >0, the top radius is set to 0, and the bottom radius is computed depending on the length, so that the given opening angle is created.(貌似是底圓是多少邊形,即越大越接近圓形)
* Outside defines whether the outside is visible (default).
* Inside defines whether the inside is visible. Set both outside and inside to create a double-sided primitive.
* Add Collider creates a matching mesh collider for the cone if checked.
*/
public int numVertices = 10;
public float radiusTop = 0f;
public float radiusBottom = 1f;
public float length = 1f;
public float openingAngle = 0f; // if >0, create a cone with this angle by setting radiusTop to 0, and adjust radiusBottom according to length;
public bool outside = true;
public bool inside = false;
public bool addCollider = false;
[MenuItem("GameObject/Create Other/Cone")]
static void CreateWizard()
{
ScriptableWizard.DisplayWizard("Create Cone", typeof(CreateCone));
}
void OnWizardCreate()
{
GameObject newCone = new GameObject("Cone");
if (openingAngle > 0 && openingAngle < 180)
{
radiusTop = 0;
radiusBottom = length * Mathf.Tan(openingAngle * Mathf.Deg2Rad / 2);
}
string meshName = newCone.name + numVertices + "v" + radiusTop + "t" + radiusBottom + "b" + length + "l" + length + (outside ? "o" : "") + (inside ? "i" : "");
string meshPrefabPath = "Assets/Editor/" + meshName + ".asset";
Mesh mesh = (Mesh)AssetDatabase.LoadAssetAtPath(meshPrefabPath, typeof(Mesh));
if (mesh == null)
{
mesh = new Mesh();
mesh.name = meshName;
// can't access Camera.current
//newCone.transform.position = Camera.current.transform.position + Camera.current.transform.forward * 5.0f;
int multiplier = (outside ? 1 : 0) + (inside ? 1 : 0);
int offset = (outside && inside ? 2 * numVertices : 0);
Vector3[] vertices = new Vector3[2 * multiplier * numVertices]; // 0..n-1: top, n..2n-1: bottom
Vector3[] normals = new Vector3[2 * multiplier * numVertices];
Vector2[] uvs = new Vector2[2 * multiplier * numVertices];
int[] tris;
float slope = Mathf.Atan((radiusBottom - radiusTop) / length); // (rad difference)/height
float slopeSin = Mathf.Sin(slope);
float slopeCos = Mathf.Cos(slope);
int i;
for (i = 0; i < numVertices; i++)
{
float angle = 2 * Mathf.PI * i / numVertices;
float angleSin = Mathf.Sin(angle);
float angleCos = Mathf.Cos(angle);
float angleHalf = 2 * Mathf.PI * (i + 0.5f) / numVertices; // for degenerated normals at cone tips
float angleHalfSin = Mathf.Sin(angleHalf);
float angleHalfCos = Mathf.Cos(angleHalf);
vertices[i] = new Vector3(radiusTop * angleCos, radiusTop * angleSin, 0);
vertices[i + numVertices] = new Vector3(radiusBottom * angleCos, radiusBottom * angleSin, length);
if (radiusTop == 0)
normals[i] = new Vector3(angleHalfCos * slopeCos, angleHalfSin * slopeCos, -slopeSin);
else
normals[i] = new Vector3(angleCos * slopeCos, angleSin * slopeCos, -slopeSin);
if (radiusBottom == 0)
normals[i + numVertices] = new Vector3(angleHalfCos * slopeCos, angleHalfSin * slopeCos, -slopeSin);
else
normals[i + numVertices] = new Vector3(angleCos * slopeCos, angleSin * slopeCos, -slopeSin);
uvs[i] = new Vector2(1.0f * i / numVertices, 1);
uvs[i + numVertices] = new Vector2(1.0f * i / numVertices, 0);
if (outside && inside)
{
// vertices and uvs are identical on inside and outside, so just copy
vertices[i + 2 * numVertices] = vertices[i];
vertices[i + 3 * numVertices] = vertices[i + numVertices];
uvs[i + 2 * numVertices] = uvs[i];
uvs[i + 3 * numVertices] = uvs[i + numVertices];
}
if (inside)
{
// invert normals
normals[i + offset] = -normals[i];
normals[i + numVertices + offset] = -normals[i + numVertices];
}
}
mesh.vertices = vertices;
mesh.normals = normals;
mesh.uv = uvs;
// create triangles
// here we need to take care of point order, depending on inside and outside
int cnt = 0;
if (radiusTop == 0)
{
// top cone
tris = new int[numVertices * 3 * multiplier];
if (outside)
for (i = 0; i < numVertices; i++)
{
tris[cnt++] = i + numVertices;
tris[cnt++] = i;
if (i == numVertices - 1)
tris[cnt++] = numVertices;
else
tris[cnt++] = i + 1 + numVertices;
}
if (inside)
for (i = offset; i < numVertices + offset; i++)
{
tris[cnt++] = i;
tris[cnt++] = i + numVertices;
if (i == numVertices - 1 + offset)
tris[cnt++] = numVertices + offset;
else
tris[cnt++] = i + 1 + numVertices;
}
}
else if (radiusBottom == 0)
{
// bottom cone
tris = new int[numVertices * 3 * multiplier];
if (outside)
for (i = 0; i < numVertices; i++)
{
tris[cnt++] = i;
if (i == numVertices - 1)
tris[cnt++] = 0;
else
tris[cnt++] = i + 1;
tris[cnt++] = i + numVertices;
}
if (inside)
for (i = offset; i < numVertices + offset; i++)
{
if (i == numVertices - 1 + offset)
tris[cnt++] = offset;
else
tris[cnt++] = i + 1;
tris[cnt++] = i;
tris[cnt++] = i + numVertices;
}
}
else
{
// truncated cone
tris = new int[numVertices * 6 * multiplier];
if (outside)
for (i = 0; i < numVertices; i++)
{
int ip1 = i + 1;
if (ip1 == numVertices)
ip1 = 0;
tris[cnt++] = i;
tris[cnt++] = ip1;
tris[cnt++] = i + numVertices;
tris[cnt++] = ip1 + numVertices;
tris[cnt++] = i + numVertices;
tris[cnt++] = ip1;
}
if (inside)
for (i = offset; i < numVertices + offset; i++)
{
int ip1 = i + 1;
if (ip1 == numVertices + offset)
ip1 = offset;
tris[cnt++] = ip1;
tris[cnt++] = i;
tris[cnt++] = i + numVertices;
tris[cnt++] = i + numVertices;
tris[cnt++] = ip1 + numVertices;
tris[cnt++] = ip1;
}
}
mesh.triangles = tris;
AssetDatabase.CreateAsset(mesh, meshPrefabPath);
AssetDatabase.SaveAssets();
}
MeshFilter mf = newCone.AddComponent<MeshFilter>();
mf.mesh = mesh;
newCone.AddComponent<MeshRenderer>();
if (addCollider)
{
MeshCollider mc = newCone.AddComponent<MeshCollider>();
mc.sharedMesh = mf.sharedMesh;
}
Selection.activeObject = newCone;
}
}
CreateRectangle:
/*
* 描 述:用於建立四邊形的檔案,我只是大自然的搬運工
* 作 者:hza
* 建立時間:2017/04/06 13:50:10
* 版 本:v 1.0
*/
using UnityEngine;
using UnityEditor;
using System.Collections;
public class CreateRectangle : ScriptableWizard
{
/* 屬性含義:
* width: 四邊形寬度(x軸)
* length: 四邊形高度(z軸)
* angle: 兩邊的夾角,預設為90°[0, 180]
* addCollider: 是否需要新增碰撞器,預設為false
*/
public float width = 1;
public float length = 1;
public float angle = 90;
public bool addCollider = false;
[MenuItem("GameObject/Create Other/Rectangle")]
static void CreateWizard()
{
ScriptableWizard.DisplayWizard("Create Rectangle", typeof(CreateRectangle));
}
void OnWizardCreate()
{
GameObject newRectangle = new GameObject("Rectangle");
// 儲存mash的名字和路徑
string meshName = newRectangle.name + "w" + width + "l" + length + "a" + angle;
string meshPrefabPath = "Assets/Editor/" + meshName + ".asset";
// 對角度進行處理
while (angle > 180) angle -= 180;
while (angle < 0) angle += 180;
angle *= Mathf.PI / 180;
/* 1. 頂點,三角形,法線,uv座標, 絕對必要的部分只有頂點和三角形。
* 如果模型中不需要場景中的光照,那麼就不需要法線。
* 如果模型不需要貼材質,那麼就不需要UV
*/
Vector3[] vertices = new Vector3[4];
Vector3[] normals = new Vector3[4];
Vector2[] uv = new Vector2[4];
vertices[0] = new Vector3(0, 0, 0);
uv[0] = new Vector2(0, 0);
normals[0] = Vector3.up;
vertices[1] = new Vector3(0, 0, length);
uv[1] = new Vector2(0, 1);
normals[1] = Vector3.up;
vertices[2] = new Vector3(width * Mathf.Sin(angle), 0, length + width * Mathf.Cos(angle));
uv[2] = new Vector2(1, 1);
normals[2] = Vector3.up;
vertices[3] = new Vector3(width * Mathf.Sin(angle), 0, width * Mathf.Cos(angle));
uv[3] = new Vector2(1, 0);
normals[3] = Vector3.up;
/* 2. 三角形,頂點索引:
* 三角形是由3個整數確定的,各個整數就是角的頂點的index。
* 各個三角形的頂點的順序通常由下往上數, 可以是順時針也可以是逆時針,這通常取決於我們從哪個方向看三角形。
* 通常,當mesh渲染時,"逆時針" 的面會被擋掉。 我們希望保證順時針的面與法線的主向一致
*/
int[] indices = new int[6];
indices[0] = 0;
indices[1] = 1;
indices[2] = 2;
indices[3] = 0;
indices[4] = 2;
indices[5] = 3;
Mesh mesh = new Mesh();
mesh.name = meshName;
mesh.vertices = vertices;
mesh.normals = normals;
mesh.uv = uv;
mesh.triangles = indices;
mesh.RecalculateBounds();
AssetDatabase.CreateAsset(mesh, meshPrefabPath);
AssetDatabase.SaveAssets();
// 新增MeshFilter
MeshFilter filter = newRectangle.gameObject.AddComponent<MeshFilter>();
if (filter != null)
{
filter.sharedMesh = mesh;
}
// 新增MeshRendered
MeshRenderer meshRender = newRectangle.gameObject.AddComponent<MeshRenderer>();
Shader shader = Shader.Find("Standard");
meshRender.sharedMaterial = new Material(shader);
// 如果願意新增碰撞器,則新增碰撞器
if (addCollider)
{
MeshCollider mc = newRectangle.AddComponent<MeshCollider>();
mc.sharedMesh = filter.sharedMesh;
}
Selection.activeObject = newRectangle;
}
}
指令碼放進去後,可以在Hierarchy裡的create找到createother這個選項了,然後就可以自己創造圓錐和四邊形啦。
邏輯部分
老規矩,先放UML圖:
(和上次做業大體邏輯一樣,僅僅是多了幾個掛載指令碼)
程式碼如下:
BaseAction:
/*
* 描 述:基類動作檔案
* 作 者:hza
* 建立時間:2017/04/07 17:39:08
* 版 本:v 1.0
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Tem.Action
{
public enum SSActionEventType : int { STARTED, COMPLETED }
public interface ISSActionCallback
{
void SSEventAction(SSAction source, SSActionEventType events = SSActionEventType.COMPLETED,
int intParam = 0, string strParam = null, Object objParam = null);
}
public class SSAction : ScriptableObject // 動作的基類
{
public bool enable = true;
public bool destory = false;
public GameObject gameObject { get; set; }
public Transform transform { get; set; }
public ISSActionCallback callback { get; set; }
public virtual void Start()
{
throw new System.NotImplementedException("Action Start Error!");
}
public virtual void FixedUpdate()
{
throw new System.NotImplementedException("Physics Action Start Error!");
}
public virtual void Update()
{
throw new System.NotImplementedException("Action Update Error!");
}
}
public class CCMoveToAction : SSAction
{
public Vector3 target;
public float speed;
public static CCMoveToAction GetSSAction(Vector3 _target, float _speed)
{
CCMoveToAction currentAction = ScriptableObject.CreateInstance<CCMoveToAction>();
currentAction.target = _target;
currentAction.speed = _speed;
return currentAction;
}
public override void Start()
{
}
public override void Update()
{
this.transform.position = Vector3.MoveTowards(this.transform.position, target, speed * Time.deltaTime);
if (this.transform.position == target)
{
this.destory = true;
this.callback.SSEventAction(this);
}
}
}
public class CCBezierMoveAction : SSAction // 僅用於三次貝塞爾曲線
{
public List<Vector3> vectors;
public Vector3 target;
public float speed;
private Vector3 begin;
private float t;
private bool firstTime;
/*private Vector3 vector2begin;
private Vector3 vector2mid;
private Vector3 vector2end;
private Vector3 vector3begin;
private Vector3 vector3end;
private float timeBegin;
private float timeDiff;*/
public static CCBezierMoveAction GetCCBezierMoveAction(List<Vector3> _vectors, float _speed)
// vector裡面最後一個值是目標位置
{
CCBezierMoveAction action = ScriptableObject.CreateInstance<CCBezierMoveAction>();
action.vectors = _vectors;
action.target = _vectors[_vectors.Count - 1];
action.vectors.RemoveAt(action.vectors.Count - 1);
action.speed = _speed;
return action;
}
public override void Start() // 公式寫法
{
//timeDiff = 0;
firstTime = true;
t = 0;
}
public override void Update()
{
if (firstTime)
{
speed = speed / Vector3.Distance(this.transform.position, target) / 1.5f;
// 速度除以相對距離併除以2作為速度比
begin = this.transform.position;
firstTime = false;
}
t += Time.deltaTime * speed;
if (t > 1) t = 1;
float _t = 1 - t;
this.transform.position = begin * Mathf.Pow(_t, 3) + 3 * vectors[0] * Mathf.Pow(_t, 2) * t
+ 3 * vectors[1] * _t * Mathf.Pow(t, 2) + target * Mathf.Pow(t, 3);
if (this.transform.position == target)
{
this.destory = true;
this.callback.SSEventAction(this);
}
}
/*public override void Update() // 正常寫法
{
timeDiff += Time.deltaTime;
vector2begin = Vector3.Lerp(this.transform.position, vectors[0], speed * timeDiff);
vector2mid = Vector3.Lerp(vectors[0], vectors[1], speed * timeDiff);
vector2end = Vector3.Lerp(vectors[1], target, speed * timeDiff);
// 第一次計算差值
vector3begin = Vector3.Lerp(vector2begin, vector2mid, speed * timeDiff);
vector3end = Vector3.Lerp(vector2mid, vector2end, speed * timeDiff);
// 第二次計算差值
this.transform.position = Vector3.Lerp(vector3begin, vector3end, speed * timeDiff);
// 最後一次計算差值
if (this.transform.position == target)
{
this.destory = true;
this.callback.SSEventAction(this);
}
}*/
}
public class CCSequenceAction : SSAction, ISSActionCallback
{
public List<SSAction> sequence;
public int repeat = -1;
public int start = 0;
public static CCSequenceAction GetSSAction(List<SSAction> _sequence, int _start = 0, int _repead = 1)
{
CCSequenceAction actions = ScriptableObject.CreateInstance<CCSequenceAction>();
actions.sequence = _sequence;
actions.start = _start;
actions.repeat = _repead;
return actions;
}
public override void Start()
{
foreach (SSAction ac in sequence)
{
ac.gameObject = this.gameObject;
ac.transform = this.transform;
ac.callback = this;
ac.Start();
}
}
public override void Update()
{
if (sequence.Count == 0) return;
if (start < sequence.Count) sequence[start].Update();
}
public void SSEventAction(SSAction source, SSActionEventType events = SSActionEventType.COMPLETED,
int intParam = 0, string strParam = null, Object objParam = null) //通過對callback函式的呼叫執行下個動作
{
source.destory = false; // 當前動作不能銷燬(有可能執行下一次)
this.start++;
if (this.start >= this.sequence.Count)
{
this.start = 0;
if (this.repeat > 0) repeat--;
if (this.repeat == 0)
{
this.destory = true;
this.callback.SSEventAction(this);
}
}
}
private void OnDestroy()
{
this.destory = true;
}
}
public class SSActionManager : MonoBehaviour
{
private Dictionary<int, SSAction> dictionary = new Dictionary<int, SSAction>();
private List<SSAction> watingAddAction = new List<SSAction>();
private List<int> watingDelete = new List<int>();
protected void Start()
{
}
protected void Update()
{
foreach (SSAction ac in watingAddAction) dictionary[ac.GetInstanceID()] = ac;
watingAddAction.Clear();
// 將待加入動作加入dictionary執行
foreach (KeyValuePair<int, SSAction> dic in dictionary)
{
SSAction ac = dic.Value;
if (ac.destory) watingDelete.Add(ac.GetInstanceID());
else if (ac.enable) ac.Update();
}
// 如果要刪除,加入要刪除的list,否則更新
foreach (int id in watingDelete)
{
SSAction ac = dictionary[id];
dictionary.Remove(id);
DestroyObject(ac);
}
watingDelete.Clear();
// 將deletelist中的動作刪除
}
public void runAction(GameObject gameObject, SSAction action, ISSActionCallback callback)
{
action.gameObject = gameObject;
action.transform = gameObject.transform;
action.callback = callback;
watingAddAction.Add(action);
action.Start();
}
}
public class PYActionManager : MonoBehaviour
{
private Dictionary<int, SSAction> dictionary = new Dictionary<int, SSAction>();
private List<SSAction> watingAddAction = new List<SSAction>();
private List<int> watingDelete = new List<int>();
protected void Start()
{
}
protected void FixedUpdate()
{
foreach (SSAction ac in watingAddAction) dictionary[ac.GetInstanceID()] = ac;
watingAddAction.Clear();
// 將待加入動作加入dictionary執行
foreach (KeyValuePair<int, SSAction> dic in dictionary)
{
SSAction ac = dic.Value;
if (ac.destory) watingDelete.Add(ac.GetInstanceID());
else if (ac.enable) ac.FixedUpdate();
}
// 如果要刪除,加入要刪除的list,否則更新
foreach (int id in watingDelete)
{
SSAction ac = dictionary[id];
dictionary.Remove(id);
DestroyObject(ac);
}
watingDelete.Clear();
// 將deletelist中的動作刪除
}
public void runAction(GameObject gameObject, SSAction action, ISSActionCallback callback)
{
action.gameObject = gameObject;
action.transform = gameObject.transform;
action.callback = callback;
watingAddAction.Add(action);
action.Start();
}
}
}
BaseCode:
/*
* 描 述:設定遊戲基本資訊
* 作 者:hza
* 建立時間:2017/04/07 20:29:47
* 版 本:v 1.0
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BaseCode : MonoBehaviour
{
public string GameName;
public string GameRule;
void Start()
{
GameName = "Shoot";
GameRule = "左鍵點選射箭,射中靶子加分,靶心從內到外分別為60-10分,點選clear清除所有的箭";
}
}
ChangeCamera:
/*
* 描 述:射中後,攝像頭拉近,持續兩秒
* 作 者:hza
* 建立時間:2017/04/07 14:46:35
* 版 本:v 1.0
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ChangeCamera : MonoBehaviour {
public GameObject mainCamera;
public GameObject closeCamera;
// 引用兩個攝像機
bool active;
float beginTime;
private void Start()
{
active = false;
}
// Update is called once per frame
void Update () {
if (!active) return;
beginTime -= Time.deltaTime;
if (beginTime < 0)
{
resetCount();
}
}
// 顯示近身攝像機,持續2秒
public void ShowCloseCamera()
{
mainCamera.SetActive(false);
closeCamera.SetActive(true);
// 顯示close攝像機
runCount();
}
void runCount()
{
active = true;
beginTime = 2f;
// 啟用計數按鈕
}
void resetCount()
{
active = false;
mainCamera.SetActive(true);
closeCamera.SetActive(false);
}
}
MouseRotate:
/*
* 描 述:控制攝像機隨滑鼠移動的指令碼,掛載在攝像機上即可
* 作 者:hza
* 建立時間:2017/04/07 17:01:57
* 版 本:v 1.0
*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
//[AddComponentMenu("Camera-Control/Mouse Look")]
public class MouseRotate : MonoBehaviour {
public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 }
public RotationAxes axes = RotationAxes.MouseXAndY;
// 滑鼠移動方式
public float sensitivityX = 15F;
public float sensitivityY = 15F;
// 靈敏度
public float minimumX = -360F;
public float maximumX = 360F;
// X最大偏移
public float minimumY = -60F;
public float maximumY = 60F;
// Y最大偏移
public bool isVisible = true;
// 滑鼠是否可見
float rotationY = 0F;
float rotationX = 0F;
void Start()
{
// Make the rigid body not change rotation
if (GetComponent<Rigidbody>())
GetComponent<Rigidbody>().freezeRotation = true;
}
void Update()
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = isVisible;
// 滑鼠保持在螢幕中間
if (axes == RotationAxes.MouseXAndY)
{
rotationX += Input.GetAxis("Mouse X") * sensitivityX;
rotationX = Mathf.Clamp(rotationX, minimumX, maximumX);
rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
rotationY = Mathf.Clamp(rotationY, minimumY, maximumY);
this.transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0);
}
else if (axes == RotationAxes.MouseX)
{
rotationX += Input.GetAxis("Mouse X") * sensitivityX;
rotationX = Mathf.Clamp(rotationX, minimumX, maximumX);
this.transform.localEulerAngles = new Vector3(0, rotationX, 0);
}
else
{
rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
rotationY = Mathf.Clamp(rotationY, minimumY, maximumY);
this.transform.localEulerAngles = new Vector3(-rotationY, 0, 0);
}
}
}
RowActionManager:
/*
* 描 述:用於控制箭發射的動作類
* 作 者:hza
* 建立時間:2017/04/07 18:23:30
* 版 本:v 1.0
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Tem.Action;
using UnityEngine.UI;
public class RowAction : SSAction
{
private Vector3 beginV;
public static RowAction GetRowAction(Vector3 beginV)
{
RowAction currentAction = ScriptableObject.CreateInstance<RowAction>();
currentAction.beginV = beginV;
return currentAction;
}
public override void Start()
{
this.gameObject.GetComponent<Rigidbody>().velocity = beginV;
// 設定初始速度
}
public override void FixedUpdate()
{
// 如果掉下去,返回
if (this.transform.position.y < -2)
{
this.destory = true;
this.callback.SSEventAction(this);
// 進行回撥操作
}
}
}
public class RowActionManager : PYActionManager, ISSActionCallback {
public GameObject cam;
public GameObject target;
public Text scoretext;
private SceneController scene;
// 控制該動作的場景
// Use this for initialization
new void Start () {
scene = Singleton<SceneController>.Instance;
}
// Update is called once per frame
new void FixedUpdate () {
base.FixedUpdate();
if (cam.activeSelf && Input.GetMouseButtonDown(0))
// 左鍵點選
{
RowFactory fac = Singleton<RowFactory>.Instance;
GameObject row = fac.setObjectOnPos(cam.transform.position, cam.transform.localRotation);
if (row.GetComponent<Rigidbody>() == null) row.AddComponent<Rigidbody>();
row.transform.FindChild("RowHead").gameObject.SetActive(true);
Debug.Log(row.transform.FindChild("RowHead").gameObject.activeSelf);
Transform head = row.transform.FindChild("RowHead").FindChild("OutCone");
if (head.gameObject.GetComponent<RowHeadTrigger>() == null)
{
head.gameObject.AddComponent<RowHeadTrigger>();
head.gameObject.GetComponent<RowHeadTrigger>().Target = target;
head.gameObject.GetComponent<RowHeadTrigger>().scoretext = scoretext;
}
// 得到物體,如果未新增指令碼就設定指令碼,並設定active
RowAction action = RowAction.GetRowAction(cam.transform.forward * 30);
// 得到動作
this.runAction(row, action, this);
}
}
// 回撥函式
public void SSEventAction(SSAction source, SSActionEventType events = SSActionEventType.COMPLETED,
int intParam = 0, string strParam = null, Object objParam = null)
{
RowFactory fac = Singleton<RowFactory>.Instance;
fac.freeObject(source.gameObject);
}
}
RowFactory:
/*
* 描 述:用於載入Row的工廠
* 作 者:hza
* 建立時間:2017/04/07 17:31:37
* 版 本:v 1.0
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RowFactory : MonoBehaviour
{
private static List<GameObject> used = new List<GameObject>();
// 正在使用的物件連結串列
private static List<GameObject> free = new List<GameObject>();
// 正在空閒的物件連結串列
// 此函式表示將Target物體放到一個位置
public GameObject setObjectOnPos(Vector3 targetposition, Quaternion faceposition)
{
if (free.Count == 0)
{
GameObject aGameObject = Instantiate(Resources.Load("prefabs/Row")
, targetposition, faceposition) as GameObject;
// 新建例項,將位置設定成為targetposition,將面向方向設定成faceposition
used.Add(aGameObject);
}
else
{
used.Add(free[0]);
free.RemoveAt(0);
used[used.Count - 1].SetActive(true);
used[used.Count - 1].transform.position = targetposition;
used[used.Count - 1].transform.localRotation = faceposition;
}
return used[used.Count - 1];
}
public void freeObject(GameObject oj)
{
oj.SetActive(false);
used.Remove(oj);
free.Add(oj);
}
public void freeAllObject()
{
if (used.Count == 0) return;
for (int i = 0; i < used.Count; i++)
{
used[i].SetActive(false);
free.Add(used[i]);
}
used.Clear();
Debug.Log(used.Count);
Debug.Log(free.Count);
// 清除used裡面所有物體
}
}
RowHeadTrigger:
/*
* 描 述:放在rowhead物體上,寫觸發函式
* 作 者:hza
* 建立時間:2017/04/07 13:57:17
* 版 本:v 1.0
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RowHeadTrigger : MonoBehaviour