“开火”就是发射子弹的意思,在战争类型的电影或者电视剧中,主角们就爱这么说!本节打算为精灵添加发射子弹的能力。因为本游戏在后面会引入敌人,而精灵最好具备开火的能力,否则会被敌人轻易干掉!具体的实现方法是:
(1)导入一个表示子弹的图片到Unity,本示例中选用的子弹图片,名为PlayerBullet,如图2-23所示。
图2-23 导入到游戏项目的表示子弹的图片
(2)拖动此图片到Scene视图,即可在当前的游戏场景中添加此对象,为此对象添加RigidBody 2D组件,并设置组件的下列属性,如图2-24所示。
q Gravity Scale:0。表示子弹对象将不受重力的影响,所以不会偏离预定的发射轨道;
图2-24 设置子弹对象上各组件的属性
(3)在Project视图里,新建一个C#脚本,命名为PlayerBulletController,为此脚本添加下面的代码:
01 using UnityEngine;
02 using System.Collections;
03
04 public class PlayerBulletController : MonoBehaviour
05 {
06 public GameObject playerObject = null; //表示精灵对象
07 public float bulletSpeed = 15.0f; //表示子弹的速度
08 private float selfDestructTimer = 0.0f; //表示子弹自我销毁的时间
09 void Update()
10 {
11 //在一段时间以后销毁子弹对象
12 if(selfDestructTimer > 0.0f)
13 {
14 if(selfDestructTimer < Time.time)
15 Destroy(gameObject);
16 }
17 }
18 //调用此函数发射子弹
19 public void launchBullet()
20 {
21 //确定精灵对象的朝向
22 float mainXScale = playerObject.transform.localScale.x;
23 Vector2 bulletForce; //对子弹施加的力的方向
24 //如果精灵对象面朝左,则向左发射子弹
25 if(mainXScale < 0.0f)
26 {
27 bulletForce = new Vector2(bulletSpeed * -1.0f,0.0f);
28 }
29 //如果精灵对象面朝右,则向右发射子弹
30 else
31 {
32 bulletForce = new Vector2(bulletSpeed,0.0f);
33 }
34 //施加给子弹对象一个指定方向的力
35 rigidbody2D.velocity = bulletForce;
36 //在1秒后销毁子弹对象
37 selfDestructTimer = Time.time + 1.0f;
38 }
39 }
将此脚本赋予场景中的子弹对象,选中后者,然后在Inspector视图里可以设置此脚本组件的Bullet Speed属性,用于修改子弹的发射速度,如图2-25所示。
图2-25 脚本组件的属性设置
将Hierarchy视图里的子弹对象,拖动到Project视图,即可创建一个子弹对象的预置资源,以备后面脚本中的代码使用。
(4)在PlayerStateController脚本中,添加精灵开火的状态,且指定当玩家按下鼠标左键的时候,精灵将进入开火状态,要添加的代码如下:
01 using UnityEngine;
02 using System.Collections;
03
04 public class PlayerStateController : MonoBehaviour
05 {
06 //定义游戏人物的各种状态
07 public enum playerStates
08 {
09 … //省略
10 falling, //表示降落过程
11 firingWeapon //表示开火
12 }
13 //定义委托和事件
14 public delegate void playerStateHandler(PlayerStateController.playerStates newState);
15 public static event playerStateHandler onStateChange;
16 void LateUpdate ()
17 {
18 … //省略
19 //当玩家按下鼠标的左键时,进入开火状态
20 float firing = Input.GetAxis("Fire1");
21 if(firing > 0.0f)
22 {
23 if(onStateChange != null)
24 onStateChange(PlayerStateController.playerStates.firingWeapon);
25 }
26 }
27 }
(5)在Hierarchy视图里,新建一个Empty对象,命名为BulletSpawnPoint。拖动它到Player对象下,使其成为Player对象的子对象。然后调整BulletSpawnPoint对象的位置,使其位于精灵发射子弹时,子弹的出现位置。在本示例中,它们的相对位置如图2-26所示。
图2-26 设置开火时,子弹的发射位置
(6)在PlayerStateListener脚本中,添加代码用于处理精灵进入开火状态时,开火的游戏逻辑,要添加的代码如下:
01 using UnityEngine;
02 using System.Collections;
03
04 [RequireComponent(typeof(Animator))]
05 public class PlayerStateListener : MonoBehaviour
06 {
07 … //省略
08 public GameObject bulletPrefab = null; //表示子弹对象
09 public Transform bulletSpawnTransform; //表示创建子弹的位置
10 … //省略
11 //当角色的状态发生改变的时候,调用此函数
12 public void onStateChange(PlayerStateController.playerStates newState)
13 {
14 //如果状态没有发生变化,则无需改变状态
15 if(newState == currentState)
16 return;
17 //判断精灵能否由当前的动画状态,直接转换为另一个动画状态
18 if(!checkForValidStatePair(newState))
19 return;
20 //通过修改Parameter中Walking的值,修改精灵当前的状态
21 switch(newState)
22 {
23 … //省略
24 case PlayerStateController.playerStates.firingWeapon:
25 //实例化一个子弹对象
26 GameObject newBullet = (GameObject)Instantiate(bulletPrefab);
27 //设置子弹的起始位置
28 newBullet.transform.position = bulletSpawnTransform.position;
29 //建立与子弹对象上PlayerBulletController组件的联系
30 PlayerBulletController bullCon = newBullet.GetComponent<PlayerBulletController>();
31 //设定子弹对象上的PlayerBulletController组件的player object属性
32 bullCon.playerObject = gameObject;
33 //发射子弹
34 bullCon.launchBullet();
35 break;
36 }
37 //记录角色当前的状态
38 currentState = newState;
39 }
40 //用于确认当前的动画状态能否直接转换为另一动画状态的函数
41 bool checkForValidStatePair(PlayerStateController.playerStates newState)
42 {
43 bool returnVal = false;
44 //比较两种动画状态
45 switch(currentState)
46 {
47 … //省略
48 case PlayerStateController.playerStates.jump:
49 if( newState == PlayerStateController.playerStates.landing
50 || newState == PlayerStateController.playerStates.kill
51 || newState == PlayerStateController.playerStates.firingWeapon
52 )
53 returnVal = true;
54 else
55 returnVal = false;
56 break;
57 case PlayerStateController.playerStates.landing:
58 if( newState == PlayerStateController.playerStates.left
59 || newState == PlayerStateController.playerStates.right
60 || newState == PlayerStateController.playerStates.idle
61 || newState == PlayerStateController.playerStates.firingWeapon
62 )
63 returnVal = true;
64 else
65 returnVal = false;
66 break;
67 case PlayerStateController.playerStates.falling:
68 if(
69 newState == PlayerStateController.playerStates.landing
70 || newState == PlayerStateController.playerStates.kill
71 || newState == PlayerStateController.playerStates.firingWeapon
72 )
73 returnVal = true;
74 else
75 returnVal = false;
76 break;
77 case PlayerStateController.playerStates.firingWeapon:
78 returnVal = true;
79 break;
80 }
81 return returnVal;
82 }
83 }
对于此脚本,有以下几点需要说明:
q 脚本08、09行的代码,使得脚本组件中多出了两个属性设置框,如图2-27所示。需要依次设置为子弹预置对象和子弹的生成位置。
图2-27 脚本组件上增加的两个属性,需要手动设置属性值
q 脚本12行,定义的方法onStateChange()里面添加的代码,表示精灵处于开火状态时,将在指定位置上实例化一个子弹的预置对象,然后通过给子弹施加一个力来将它发射出去。
q 脚本41行,定义的方法checkForValidStatePair()里面添加的代码,表示处于jump、landing和falling状态的精灵,可以转换为firingWeapon,即开火状态。
(7)运行游戏,当按下鼠标的左键时,精灵将发射子弹,而且精灵可以在任何状态下发射子弹,如图2-28所示。
图2-28 精灵开火状态的运行效果
本文选自:Unity 2D游戏开发快速入门大学霸内部资料,转载请注明出处,尊重技术尊重IT人!