下面我们通过一个具体的实例来了解如何使用物理引擎,该实例通过第三人称视角控制游戏中的小球对象,游戏通过是否与钻石碰撞来界定是否寻找到钻石并获得积分,获得积分满10分后,赢得游戏,当小球冲出跑道时,游戏失败,并提示是否重新开始游戏。
依次打开文件夹Assets-》object,在object文件夹下找到Runway.fbx文件,拖进场景中,如下图:
选择Runway游戏对象,修改Transform组件的Position(88,48.5,57),Rotation(270,350,0),Scale(1,1,1),然后选择Main Camera对象,修改Transform组件的Position(88,60,45),Rotation(55,0,0),Scale(1,1,1),如下图:
然后下面我们添加一个平行光源,依次打开菜单栏中的GameObject->Create Other->Directional light,修改该对象的Transform组件的Position(87,57,58),Rotation(48,-29,1),Scale(1,1,1),如下图:
然后我们添加一个球体,依次打开菜单栏GameObject->Create Other->Sphere,并命名为Ball,设置它的position(84,50,48),Rotation(0,0,0),Scale(1,1,1),然后打开菜单栏Component->Physics->Rigidbody,给Ball对象添加刚体组件,如下图:
下面给小球添加材质文件,如下图:
现在小球无法移动,所以我们得给小球绑定一个脚本,新建一个文件夹,命名为Scripts,在Scripts文件夹里新建一个C#文件,并命名为BallControl.cs,代码如下:
1. using UnityEngine;
2. using System.Collections;
3.
4. public class BallControl : MonoBehaviour {
5.
6. //小球运动的速率
7. public float movementSpeed=6.0f;
8. //小球的水平运动
9. private Vector3 horizontalMovement;
10. //小球的前后运动
11. private Vector3 verticalMovement;
12.
13.
14. // Use this for initialization
15. void Start ()
16. {
17.
18.
19.
20.
21.
22. }
23.
24. // Update is called once per frame
25. void Update ()
26. {
27.
28. //Vector3.right x zhou
29. "Horizontal")*Vector3.right*movementSpeed;
30.
31. //z zhou
32. "Vertical")*Vector3.forward*movementSpeed;
33.
34. //小球的运动
35. Vector3 movement=horizontalMovement+verticalMovement;
36.
37. //为小球施加力
38. rigidbody.AddForce(movement,ForceMode.Force);
39.
40.
41. }
42. }
然后绑定到Ball对象上,如下图:
点击Play按钮,我们发现可以用键盘控制小球移动了,如下图:
下面我们添加钻石游戏对象,将Gem.fbx文件拖进场景中,复制10个这样的对象,然后依次命名Gem1--Gem10,依次打开菜单栏创建一个空游戏对象,命名Gems,然后把Gem1-10都拖进Gems对象中,如下图:
依次设置Gem1-Gem10对象的Transform组件属性,Gem1的Position(78,50,55),Rotation(-90,0,0),Scale(0.27,0.27,0.27),并再Mesh Collider组件下勾选Is Trigger,设置tag为Pickup,依次设置剩下的gem对象,设好后如下图:
我们修改下BallControl.cs脚本,当小球与钻石碰撞时,让钻石消失,添加代码如下:
1. void OnTriggerEnter(Collider other)
2. {
3. //判断小球是否与钻石对象碰撞
4. if (other.tag == "Pickup")
5. {
6.
7. //销毁对象
8. Destroy(other.gameObject);
9.
10.
11.
12.
13. }
14.
15.
16.
17.
18. }
接下来,我们创建一个平面,依次打开菜单栏GameObject->Create Other->Cune,命名为GameOverTrigger,该对象用于判断小球是否与其碰撞,如果是,表示小球冲出了跑道,游戏失败,我们设置Transform组件属性,Position(90,40,55),Rotation(0,0,0),Scale(165,1,118),如下图:
勾选Box Collider下的Is Trigger复选框,并取消勾选Mesh Renderer组件,创建一个c#脚本,叫GameOverTrigger.cs,代码如下:
1. using UnityEngine;
2. using System.Collections;
3.
4. public class GameOverTrigger : MonoBehaviour {
5.
6. void OnTriggerEnter()
7. {
8.
9.
10. "over");
11. }
12. }
把脚本绑定到GameOverTrigger对象上,预览游戏,当小球冲出跑道后,我们打印over字样。接下来我们在新建一个脚本,叫CrayBallManager.cs,用来处理一些输赢得分之类的逻辑,代码如下:
1. using UnityEngine;
2. using System.Collections;
3.
4. //枚举
5. public enum CrazyBallState { playing, won, lost };
6.
7. public class CrazyBallManager : MonoBehaviour
8. {
9.
10. //单例
11. public static CrazyBallManager CB;
12.
13. //按钮
14. public GUIStyle buttonStyle;
15.
16. //标签
17. public GUIStyle labelStyle;
18.
19. //钻石总共的数量
20. private int totalGems;
21.
22. //找到钻石的数量
23. private int foundGems;
24.
25. //游戏的状态
26. private CrazyBallState gameSate;
27.
28. void Awake()
29. {
30.
31.
32. this;
33. foundGems = 0;
34. gameSate = CrazyBallState.playing;
35.
36. "Pickup").Length;
37.
38. //开始游戏
39. Time.timeScale = 1.0;
40.
41. }
42.
43.
44. void OnGUI()
45. {
46.
47.
48. GUI.skin.label = labelStyle;
49.
50. GUI.skin.button = buttonStyle;
51.
52. //显示找到的钻石数量
53. "Found gems:"+foundGems+"/"+totalGems);
54.
55. if (gameSate == CrazyBallState.lost)
56. {
57.
58. //提示游戏失败
59. "You Lost");
60.
61. if(GUI.Button(new Rect(Screen.width/2,Screen.height/2,113,84),"Play again"))
62. {
63.
64. //重新加载场景
65. Application.LoadLevel(Application.loadedLevel);
66.
67.
68. }
69.
70.
71. }
72. else if(gameSate==CrazyBallState.won)
73. {
74. "You won");
75.
76.
77. if(GUI.Button(new Rect(Screen.width/2,Screen.height/2,113,84),"Play again"))
78. {
79.
80. //重新加载场景
81. Application.LoadLevel(Application.loadedLevel);
82.
83.
84. }
85.
86. }
87.
88. }
89.
90.
91. public void FoundGem()
92. {
93.
94.
95. foundGems++;
96. if(foundGems>=totalGems)
97. {
98.
99.
100. WonGame();
101.
102.
103. }
104.
105.
106.
107. }
108.
109.
110. public void WonGame()
111. {
112.
113. //暂停游戏
114. Time.timeScale = 0.0;
115.
116.
117. gameSate = CrazyBallState.won;
118.
119. }
120.
121. public void SetGameOver()
122. {
123.
124. //暂停游戏
125. Time.timeScale = 0.0;
126.
127. gameSate = CrazyBallState.lost;
128.
129. }
130.
131.
132. }
CrayBallManager脚本文件中,每调用一次FoundGem()函数,对FoundGems变量累加一次,所以我们在BallControl.cs中修改如下代码:
1. {
2. //判断小球是否与钻石对象碰撞
3. if (other.tag == "Pickup")
4. {
5.
6.
7. CrazyBallManager.CB.FoundGem();
8.
9. //销毁对象
10. Destroy(other.gameObject);
11.
12.
13.
14.
15. }
16.
17.
18.
19.
20. }
GameOverTrigger.cs修改如下:
1. void OnTriggerEnter()
2. {
3.
4.
5. CrazyBallManager.CB.SetGameOver ();
6. //
将CrayBallManager.cs脚本绑定到Main Camera对象上,然后我们单击Main Camera对象,单击ButtonStyle属性,设置Background属性,放入一张图片,设置FontSize为18,Alignment为Middle Center,设置Fixed Width为113,Height为84,如下图:
运行游戏,如下图:
游戏中的摄像机并没有跟随小球,造成了游戏难以操作的现象,所以我新建一个脚本,叫BallCamera.cs,代码如下:
1. using UnityEngine;
2. using System.Collections;
3.
4. public class BallCamera : MonoBehaviour
5. {
6. //跟随的目标物体
7. public Transform target;
8. //与目标物体的相对高度
9. public float relativeHeigth = 10.0f;
10. //与目标物体的相对距离
11. public float zDistance = 5.0f;
12. //阻尼速度
13. public float dampSpeed = 2;
14.
15. void Update()
16. {
17.
18. new Vector3(0, relativeHeigth, -zDistance);
19. //像弹簧一样跟随目标物体
20. transform.position = Vector3.Lerp(transform.position, newPos, Time.deltaTime * dampSpeed);
21. }
22. }
绑定到Main Camera对象上,target为ball对象,运行游戏,如下图: