unity3d-基础知识及简单工厂

unity3d-基础知识及简单工厂

主要介绍摄像机、左手法则、光源等unity一些基础只是和部件,以及简单的运动,简单工厂模式。

摄像机

Fieldof View

Fieldof View(FOV): 视野范围。只针对透视镜头,用于控制视角宽度与纵向角度。

通过操作我们可以发现,当FOV越大的时候,视角越大,物体看起来越小。FOV越小,视角越小,物体看起来越大。

左手法则

Unity3D采用的是左手坐标系:沿屏幕横向为x轴,沿屏幕纵向为y轴,垂直屏幕方向为z轴。右、上、背向观众的三个方向为正方向。(坐标系主要分成三类数学上的空间直角坐标系、右手坐标系、左手坐标系更多详细可以参考参考一)

通过修改摄像头的Transform参数,我们可以发现修改Position可以沿着所修改轴方向平移摄像机。修改Rotation可以让摄像机以该轴为法向量旋转相应角度。

继承类

Camera 继承了 MonoBehavior,MonoBehavior继承自Component,Component 继承自Object。

注意:Camera不是GameObject

静态属性

列表

Static Variables description
allCameras Returns all enabled cameras in the scene.
allCamerasCount The number of cameras in the current scene.
current The camera we are currently rendering with, for low-level render control only (Read Only).
main The first enabled camera tagged “MainCamera” (Read Only).
onPostRender Event that is fired after any camera finishes rendering.
onPreCull Event that is fired before any camera starts culling.
onPreRender Event that is fired before any camera starts rendering.

程序验证

首先我们另外创建了两个摄像机,然后新建一段脚本,挂载到任意一个摄像机执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using UnityEngine;
using System.Collections;
public class AboutCamera : MonoBehaviour {
// Use this for initialization
void Start () {
CameraCount ();
print (Camera.current);
print (Camera.main);
}
// Update is called once per frame
void Update () {
}
public int count = Camera.allCameras.Length;
void CameraCount() {
print("We've got " + count + " cameras");
print(count == Camera.allCamerasCount);
}
}

得到结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using UnityEngine;
using System.Collections;
public class AboutCamera : MonoBehaviour {
// callback to be called after any camera finishes rendering
public void MyPostRender(Camera cam)
{
Debug.Log("PostRender " + gameObject.name + " from camera " + cam.gameObject.name);
}
public void OnEnable()
{
// register the callback when enabling object
Camera.onPostRender += MyPostRender;
}
public void OnDisable()
{
// remove the callback when disabling object
Camera.onPostRender -= MyPostRender;
}
}

onPreCull 和 onPreRender也是用相同的方法验证。

切换摄像机

找到摄像机对象

切换摄像机首先要找到摄像机,参考Finding Cameras的方法。摄像机虽然不是GameObject,但是可以通过挂载在游戏对象的camera找到,GameObject.Find().camera,但是该方法效率比较低, 而且不适用全部。可以使用foreach(Camera c in Camera.allCameras)来遍历所有的摄像机对象,具体要在什么时候切换,自己再添加判断条件

设置camera

在camera里面设置viewport Rect W代表width H代表height,1表示整个屏幕 0.5表示半个。X,Y代表所显示屏幕的坐标。其中depth用来设置显示的层次,depth数值越大,在越上层,可以覆盖住下层的东西。

切换摄像机

通过enable的设置来关掉我们不需要的层次的摄像机,让所需要的摄像机显示在最上层。可以达到切换画面的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 遍历所有摄像机对象,关闭非主摄像机外的摄像机
using UnityEngine;
using System.Collections;
public class AboutCamera : MonoBehaviour {
void Start() {
foreach(Camera c in Camera.allCameras) {
if (c.name != "Main Camera") {
print (c.name);
c.enabled = false;
}
}
}
}

切换前

切换后:

光源

光源不是GameObject。光源可以照亮别人但是自己不会发光。

类型

类型 描述
Directional 方向光 A light placed infinitely far away. It affects everything in the scene.
Point 点光 A light that shines equally in all directions from its location, affecting all objects within its Range.
Spot 聚光 A light that shines everywhere within a cone defined by Spot Angle and Range. Only objects within this region are affected by the light.

给摄像机添加一个Spot光源跟随他移动之后

有一个椎状的光源会跟随着摄像机移动,但是在屏幕上看只有一个圈圈。

给太阳添加点光源之后,自己并不会发光。在周围放上物体可以照亮周围的物体。

不是游戏对象的好处

Light在unity中并没有被设计成GameObject,而是作为一个Component,这样子Light就能被添加到游戏对象上。既可以固定位置,也可以跟随着物体一起移动。更加便于实现一些需求。

面向对象语言接口和超类

面向对象语言接口

接口:让规范和实现相分离;接口只是一个规范,不再是一个有具体功能的类

超类

面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

通过继承创建的新类称为“子类”或“派生类”。

被继承的类称为“基类”、“父类”或“超类”。

相同

超类和接口都是抽象了具体事件,提取了共同信息,把他们集合起来,隐藏了具体的实现过程。提供了一种可以使用的方法。

不同

接口完成方法的定义,不实现具体的内容,只要接受到参数完成所需要的工作,完成对对象的创建即可。

超类,要完成对方法的定义和实现。

例子

IU3dActionCompleted

可以设计为超类,选取完成动作之后物体们的共同特点封装,做成超类。

U3dAction

个人感觉比较难以设计为接口,因为有各种个样不一样的U3dAction,很难通过单纯的传入参数完成对内部逻辑过程的设计。

修改简单工厂代码

####MoveToTargetAction

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
// 在ActionManager 添加如下方法
public U3dAction ApplyMoveToTargetAction(GameObject obj, GameObject target, int speed) {
MoveToTargetAction ac = obj.AddComponent <MoveToTargetAction> ();
ac.setting (target, speed);
return ac;
}
// 添加 MoveToTargetAction 类
public class MoveToTargetAction : U3dActionAuto {
public GameObject target;
public int speed;
public void setting(GameObject target, int speed){
this.target.transform.position = target.transform.position;
this.speed = speed;
}
void Update () {
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards (transform.position, target.transform.position, step);
}
}
// 修改U3dActions的Start函数
void Start () {
cube = GameObject.Find ("Cube");
x = GameObject.Find ("xx");
y = GameObject.Find ("yy");
ActionManager.GetInstance ().ApplyMoveToTargetAction (cube, x ,1);
}
// 就可以实现对x的追击了

MoveToAB_Action

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
// 在ActionManager 添加如下方法
public U3dAction ApplyMoveToAB_Action(GameObject obj, Vector3 A, Vector3 B, int speed){
MoveToAB_Action ac = obj.AddComponent <MoveToAB_Action> ();
ac.setting (A, B, speed);
return ac;
}
// 添加 MoveToAB_Action 类
public class MoveToAB_Action : U3dActionAuto {
public Vector3 A;
public Vector3 B;
public int speed;
private Vector3 target;
public void setting(Vector3 A, Vector3 B, int speed){
this.target = A;
this.A = A;
this.B = B;
this.speed = speed;
}
void Update () {
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, target, step);
// 到一边之后翻转目标
if (transform.position == A) {
target = B;
} else if (transform.position == B) {
target = A;
}
}
}
// 修改U3dActions的Start函数
void Start () {
cube = GameObject.Find ("Cube");
x = GameObject.Find ("xx");
y = GameObject.Find ("yy");
ActionManager.GetInstance ().ApplyMoveToAB_Action (cube, x.transform.position , y.transform.position, 1);
}

MoveToTargetAB_Action

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
// 在ActionManager 添加如下方法
public U3dAction ApplyMoveToTargetAB_Action(GameObject obj, GameObject A, GameObject B, int speed){
MoveToAB_Action ac = obj.AddComponent <MoveToAB_Action> ();
ac.setting (A, B, speed);
return ac;
}
// 添加 MoveToAB_Action 类
public class MoveToAB_Action : U3dActionAuto {
public GameObject A;
public GameObject B;
public int speed;
private GameObject target;
public void setting(Vector3 A, Vector3 B, int speed){
this.target = A;
this.A = A;
this.B = B;
this.speed = speed;
}
void Update () {
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, target.transform.position, step);
// 到一边之后翻转目标
if (transform.position == A.transform.position) {
target = B;
} else if (transform.position == B.transform.position) {
target = A;
}
}
}
// 修改U3dActions的Start函数
void Start () {
cube = GameObject.Find ("Cube");
x = GameObject.Find ("xx");
y = GameObject.Find ("yy");
ActionManager.GetInstance ().ApplyMoveToAB_Action (cube, x , y, 1);
}

简单工厂

简单工厂的优点

  • 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
  • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
  • 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

简单工厂的应用

游戏中可以提供多个外观不同的按钮(如圆形按钮、矩形按钮、菱形按钮等), 这些按钮都源自同一个基类,不过在继承基类后不同的子类修改了部分属性从而使得它们可以呈现不同的外观,如果我们希望在使用这些按钮时,不需要知道这些具体按钮类的名字,只需要知道表示该按钮类的一个参数,并提供一个调用方便的方法,把该参数传入方法即可返回一个相应的按钮对象,此时,就可以使用简单工厂模式。

参考

一个对Unity基础知识比较详细的介绍:Unity3D游戏开发初探—2.初步了解3D模型基础

Finding Cameras

简单工厂模式( Simple Factory Pattern )

UML类图符号 各种关系说明以及举例

您的支持将鼓励我继续创作!