123 第1页 | 共3 页下一页
返回列表 发新帖
查看: 7663|回复: 20
打印 上一主题 下一主题

[其他] unity3d中Trigger的使用探讨(二)

[复制链接]

5552

主题

2

听众

8万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
11

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

跳转到指定楼层
楼主
发表于 2011-12-14 14:43:50 |只看该作者 |倒序浏览
What’s In This Space?



Another great use of triggers is to the answer a question for your game logic: What’s in this space? Perhaps you want your spawn points to fire only if they’re empty, or you want to see if two objects are near enough to count for something.
Here’s a concerete example: One of our games, Crane Wars, is a stacking game. In order to determine if different building pieces are stacked on top of one another, and should count as one building, we use triggers:

The slim box outlines on the top of the building pieces are the triggers. White indicates that nothing is in the trigger, and green–the bottom two floors of the stack–indicate that another building piece is in the trigger and is considered the “upstairs” piece in the sequence. The light blue box is a spawn point; it will spawn another piece as soon as it is empty.
In order to facilitate this game logic, we have generic scripts that track objects as they enter and leave a trigger. Unfortunately, there is no function available like collider.GetCollidersInsideTrigger(). Fear not, though, it’s fairly easy logic. The following script will track all objects that enter, and store them in a list based on their layer:
#pragma strict

@script AddComponentMenu(“Library/Physics/Trigger Track By Layer”)

/**

* Keep a list of all objects inside this trigger, available by layer

*

* Layer -1 is a list of all objects

*/
// should we track triggers too?

var trackOtherTriggers:boolean = false;
// objects we aren’t tracking

var ignoreColliders:Collider[];
// hashtable of arraylists for our objects

private var objects:Hashtable = new Hashtable();
/**

* Initialize internals

*/

function Awake()

{

   // -1 is all layers

   objects[-1] = new ArrayList();

}
/**

* Return an arraylist for a layer–if no layer, just make an empty one

*/

function GetObjects(layer:int):ArrayList

{

   var list:ArrayList = objects[layer];

   

   // scrub any nulls when scripts request a list

   if(list)

   {

      Helpers.ClearArrayListNulls(list);

      return list;

   }

   else

      return new ArrayList();

}
/**

* Record when objects enter

*/

function OnTriggerEnter(other:Collider)

{

   if(!trackOtherTriggers && other.isTrigger)

      return;  

   

   // is this collider in our ignore list?

   for(var testIgnore:Collider in ignoreColliders)

      if(testIgnore == other)

         return;

   

   var go:GameObject = other.gameObject;

   var layer:int = go.layer;

   

   // create our list if none exists

   if(!objects[layer])

      objects[layer] = new ArrayList();

      

   var list:ArrayList = objects[layer];

   

   // add if not present

   if(!list.Contains(go))

      list.Add(go);

      

   // add to all

   list = objects[-1];

   if(!list.Contains(go))

      list.Add(go);

}
/**

* Update when objects leave

*/

function OnTriggerExit(other:Collider)

{

   if(!trackOtherTriggers && other.isTrigger)

      return;  

   

   // is this collider in our ignore list?

   for(var testIgnore:Collider in ignoreColliders)

      if(testIgnore == other)

         return;  

   

   var go:GameObject = other.gameObject;

   var layer:int = go.layer;

   

   

   // remove from all

   var list:ArrayList = objects[-1];

   list.Remove(go);

   

   // Remove from layer’s list if it’s present

   if(objects[layer])

   {

      list = objects[layer];

      list.Remove(go);

   }

}
/**

* Spew our list as an overlay in debug mode

*/

function OnGUI()

{

   if(!Global.use.debug)

      return;

   

   var debug:String = “”;

   

   for(var deictionaryEntry in objects)

   {

      var list:ArrayList = de.Value;

      var layer:int = de.Key;

      

      if(layer == -1)

         continue;

      

      debug += String.Format(“{0} : {1}
“, LayerMask.LayerToName(de.Key), list.Count);

   }

   

   var screen:Vector3 = Camera.main.WorldToScreenPoint(transform.position);

   GUI.contentColor = Color.red;

   GUI.Label(new Rect(screen.x, Screen.height - screen.y, 256, 128), debug);

}
An object destroyed inside of a trigger will not send OnTriggerExit events, so we must scrub our list of any null values before returning it.
Rather than poll this list continuously, our game logic script only checks for an update when things may have changed–when something enters or exits our trigger (the same trigger, as both the generic tracker script and our game logic script are on the same object). We separate scripts like this in order to keep the tracking script generic and reusable between projects. It is easy for our gameplay script to ask the tracker script for all of the objects in our BuildingPieces layer, for instance:
// should we do a calculation next update?

var isDirty:boolean = false;

// cache our tracker reference

private var tracker:TriggerTrackByLayer;

tracker = GetComponent(TriggerTrackByLayer);
/**

* Recalculate status every object

*/

function OnTriggerEnter()

{  

   isDirty = true;

}

function OnTriggerExit()

{

   isDirty = true;

}
/**

* Check for dirty every FixedUpdate (after OnTrigger* calls)

*/

function FixedUpdate()

{

   if(isDirty)

   {

      // do our game logic, ie:

      var objectsInside = tracker.GetObjects(someLayerNumber);

   }

   

   // unset to prevent logic every frame

   isDirty = false;

}
We use another variant that only tracks objects that match a certain LayerMask, which lets you avoid the overhead of tracking all objects in and out. The example project includes both scripts.
By the way, visualizing the status of your triggers via Gizmos is a very useful debugging tool. In the crane wars example you can draw box colliders like:
/**

* Debug display of our trigger state

*/

function OnDrawGizmos()

{

   // set to whatever color you want to represent

   Gizmos.color = Color.green

   

   // we’re going to draw the gizmo in local space

   Gizmos.matrix = transform.localToWorldMatrix;   

   

   // draw a box collider based on its size

   var box:BoxCollider = GetComponent(BoxCollider);

   Gizmos.DrawWireCube(box.center, box.size);

}
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

462

主题

1

听众

31万

积分

首席设计师

Rank: 8Rank: 8

纳金币
2
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

沙发
发表于 2012-1-25 23:19:09 |只看该作者
在新的一年里,愿您分分秒秒平平安安朝朝暮暮开开心心日日夜夜健健康康岁岁年年潇潇洒洒永永远远快快乐乐时时刻刻风风光光生生世世顺顺当当 新的一年愿所有的好梦依偎着你!入睡是甜,醒来成真;愿所有的爱情笼罩着你!
回复

使用道具 举报

1023

主题

3

听众

359

积分

设计实习生

Rank: 2

纳金币
335582
精华
0

最佳新人

板凳
发表于 2012-3-9 23:32:47 |只看该作者
跑着去顶朋友滴铁
回复

使用道具 举报

5969

主题

1

听众

39万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

地板
发表于 2012-4-1 23:31:06 |只看该作者
既来之,则看之!
回复

使用道具 举报

tc    

5089

主题

1

听众

33万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

5#
发表于 2012-5-1 23:19:10 |只看该作者
很经典,很实用,学习了!
回复

使用道具 举报

462

主题

1

听众

31万

积分

首席设计师

Rank: 8Rank: 8

纳金币
2
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

6#
发表于 2012-5-13 23:19:53 |只看该作者
已阵亡的 蝶 随 风 舞 说过  偶尔按一下 CTRL A 会发现 世界还有另一面
回复

使用道具 举报

1023

主题

3

听众

359

积分

设计实习生

Rank: 2

纳金币
335582
精华
0

最佳新人

7#
发表于 2012-5-23 23:24:41 |只看该作者
好铁多多发,感激分享
回复

使用道具 举报

462

主题

1

听众

31万

积分

首席设计师

Rank: 8Rank: 8

纳金币
2
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

8#
发表于 2012-7-5 23:24:24 |只看该作者
跑着去顶朋友滴铁
回复

使用道具 举报

643

主题

1

听众

9937

积分

高级设计师

Rank: 6Rank: 6

纳金币
9935
精华
1

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

9#
发表于 2012-7-6 15:12:05 |只看该作者
好好好好好好好好好好好好好好好
回复

使用道具 举报

643

主题

1

听众

9937

积分

高级设计师

Rank: 6Rank: 6

纳金币
9935
精华
1

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

10#
发表于 2012-7-6 15:12:15 |只看该作者
好好好好好好好好好好好好好好好
回复

使用道具 举报

123 第1页 | 共3 页下一页
返回列表 发新帖
您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2024-11-29 13:41 , Processed in 0.097649 second(s), 31 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部