标题: unity3d中Trigger的使用探讨(二) [打印本页] 作者: 会飞的鱼 时间: 2011-12-14 14:43 标题: unity3d中Trigger的使用探讨(二) 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
}
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:
/**