unity3d-4

unity3d 工厂类
游戏实践 无动作管理 打飞碟

Hit UFO

仓库地址

视频地址


无动作管理是因为飞碟的运动只需要

  • 设置起点
  • 初速度
  • 启用重力

即可达到想要的效果(抛物线运动), 而后面两项需要用到组件 Rigidbody
Rigidbody, 当然设置在预设中就OK了, 就不必重复创建

上一下 FirstController 的代码, 十分简单..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// FirstController.cs

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

public class FirstController : MonoBehaviour, ISceneController, UserAction {

public bool Playing;
private int Round = 1;
private float time = 0;
private int DiskFlyOneTime;
UserGUI userGUI;
private Queue<GameObject> Disks = new Queue<GameObject>();

private static int max = 9;
private static int min = 2;
private Vector3[] position = new Vector3[max];

public DiskFactory Factory;

// public CCActionManager actionManager;

void Awake()
{
Director director = Director.GetInstance();
director.CurrentScenceController = this;
director.CurrentScenceController.LoadResources();
userGUI = gameObject.AddComponent<UserGUI>() as UserGUI;
for (int i = 0; i < max; i++)
{
position[i] = new Vector3(4-2*i, 4-2*i, -7);
}
}

// 加载资源
public void LoadResources()
{

}

public void restart()
{
this.Round = 1;
this.Playing = false;
this.time = 0;
}


// 获取工厂单实例
void Start () {
Factory = Singleton<DiskFactory>.Instance;
}

// Update is called once per frame
void Update () { // 控制飞碟发出
if (userGUI.status == 1)
{
if (time > 4f)
{
RoundOver();
} else
{
time += Time.deltaTime;
if (this.Playing == false)
{
DiskFlyOneTime = Random.Range(min, max);
//Debug.Log(DiskFlyOneTime);
GameObject temp;
for (int i = 0; i < DiskFlyOneTime; i++)
{
//Debug.Log(Factory+"here");
temp = Factory.GetDisk(this.Round);
temp.transform.position = position[i];
temp.transform.GetComponent<Rigidbody>().velocity = temp.GetComponent<Disk>().direction * temp.GetComponent<Disk>().speed;
Disks.Enqueue(temp);
}
this.Playing = true;
}
}
}
}

private void RoundOver() // 下一回合
{
while(Disks.Count > 0)
{
Factory.FreeDisk(Disks.Dequeue());
}
this.Round++;
this.time = 0;
this.Playing = false;
if (Round > 10)
{
userGUI.status = 0;
}
}

public void hit(Vector3 pos) // 点击发射射线打飞碟, 记录分数
{
Ray ray = Camera.main.ScreenPointToRay(pos);

RaycastHit[] hits;
hits = Physics.RaycastAll(ray);
for (int i = 0; i < hits.Length; i++)
{
RaycastHit hit = hits[i];

if (hit.collider.gameObject.GetComponent<Disk>() != null)
{
Debug.Log("hit");
hit.collider.gameObject.SetActive(false);
userGUI.Score += (0.1f * Round + 1) * (0.1f * Round + 1);
// 分数大约跟回合数的平方成正比
}

}
}
}

还有本节课主要学习的内容, 工厂类
主要是因为频繁的创建和销毁对象会显著的降低性能, 所以我们可以把用完的游戏对象(GameObject)保留,
以便下一次需要时传递过去使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// DiskFactory.cs

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


namespace Mygame
{
public class DiskFactory : MonoBehaviour
{
public GameObject DiskPrefab;// 读预制, 加快复制

private List<GameObject> used = new List<GameObject>();
// 存正在用的
private List<GameObject> free = new List<GameObject>();
// 存空闲的

private void Awake() // 加载资源
{
DiskPrefab = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("DiskPrefab"), Vector3.zero, Quaternion.identity);
DiskPrefab.SetActive(false);
}

public GameObject GetDisk(int Round) //传递游戏对象给 FirstController
{
GameObject NewDisk = null;
if (free.Count > 0)
{
NewDisk = free[0];
free.Remove(free[0]);
}
else
{
NewDisk = GameObject.Instantiate<GameObject>(DiskPrefab, Vector3.zero, Quaternion.identity);
NewDisk.name = NewDisk.GetInstanceID().ToString();
}

// 设置UFO难度
NewDisk.GetComponent<Disk>().SetLevel(Round);

return NewDisk;
}

public void FreeDisk(GameObject UsedDisk) // 将用完的对象回收
{
if (UsedDisk != null)
{
UsedDisk.SetActive(false);
free.Add(UsedDisk);
used.Remove(UsedDisk);
}
}

// Use this for initialization
void Start()
{

}

// Update is called once per frame
void Update()
{

}
}
}

还有一个亮点的地方就是飞碟各种设置, 都是跟回合数有关的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// Disk.cs

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


namespace Mygame
{
public class Disk : MonoBehaviour
{
public float size;
public Color color;
public float speed;
public Vector3 direction;

public void SetLevel(int Round = 1) // 根据回合数设置数据
{
this.SetRandomSize(Round);
this.SetRandomColor();
this.SetRandomSpeed(Round);
this.SetRandomDireation();
this.gameObject.SetActive(true);
}

private void SetRandomColor() // 随机颜色
{
float r = Random.Range(0f, 1f);
float g = Random.Range(0f, 1f);
float b = Random.Range(0f, 1f);
this.color = new Color(r, g, b);
this.gameObject.transform.GetComponent<Renderer>().material.color = this.color;
}

private void SetRandomSize(int Round = 1) // 随机size, 是等比例的, (3.5,0.4,3.5)是我设置的预制的大小
{
float Level = 0.1f * (Round - 1) + 1;
Level *= Level;
this.size = Random.Range(0.7f / Level, 1f);
this.gameObject.transform.localScale = (new Vector3(3.5f, 0.4f, 3.5f))*this.size;
this.gameObject.transform.rotation = Quaternion.identity;
}

private void SetRandomSpeed(int Round = 1) // 随机速度, 同时决定了飞出去的方向
{
this.speed = Random.Range(4f,6f) * (0.09f * (Round - 1) + 1);
}

private void SetRandomDireation()
{
this.direction = new Vector3(Random.Range(-3.5f, 3.5f), Random.Range(2f, 3f), Random.Range(3f, 6f));
}
}
}

其他代码日后再贴
(一些关于分数统计的GUI, 导演类, 单实例模板类)