一、实现思路
根据之前的飞碟工厂进行改变,在射出弓箭手上没有弓箭之后重新生成新的弓箭,并将射出的弓箭在一定时间后进行回收。在右下角通过小窗口展示靶子的情况,射中不同的环数给予不同得分。
二、主要涉及技术
物理引擎的使用、游戏对象的生产与回收、物体碰撞、刚体编程
三、图形设计
(一)靶子的实现
通过不同大小但是对称轴重合的圆柱体实现靶子。需要注意的是:当圆柱体的高完全相同时,外面更大的圆柱体会覆盖里面更小的圆柱体。所以需要进行一些设置:多个圆柱体从里往外高逐渐递减
如上图所示。
另外还需要对物体进行一些碰撞相关的设置:将根组件设为 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);
}
}