<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>Blurst Technology</title>
	<atom:link href="http://technology.blurst.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://technology.blurst.com</link>
	<description>Tips, tricks, and tutorials from our Unity development experience.</description>
	<pubDate>Sun, 14 Feb 2010 21:41:22 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.3</generator>
	<language>en</language>
			<item>
		<title>&#8220;High-Speed, Off-Screen Particles&#8221; in Unity</title>
		<link>http://technology.blurst.com/off-screen-particle-optimization/</link>
		<comments>http://technology.blurst.com/off-screen-particle-optimization/#comments</comments>
		<pubDate>Sat, 13 Feb 2010 08:21:28 +0000</pubDate>
		<dc:creator>Shawn White</dc:creator>
		
		<category><![CDATA[Graphics]]></category>

		<category><![CDATA[Post Processing]]></category>

		<category><![CDATA[Raptor Safari]]></category>

		<category><![CDATA[Shaders]]></category>

		<guid isPermaLink="false">http://technology.blurst.com/?p=269</guid>
		<description><![CDATA[After running into fill-rate problems with dust/dirt particles in Raptor Safari we decided to implement High-Speed, Off-Screen Particles, as outlined by NVIDIA&#8217;s GPU Gems 3. Without getting too technical, the article shows how to render particles into a smaller render target (RenderTexture in Unity) and then blend the particles back into screen. This works well [...]]]></description>
			<content:encoded><![CDATA[<p>After running into fill-rate problems with dust/dirt particles in Raptor Safari we decided to implement High-Speed, Off-Screen Particles, as outlined by <a href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch23.html">NVIDIA&#8217;s GPU Gems 3</a>. Without getting too technical, the article shows how to render particles into a smaller render target (RenderTexture in Unity) and then blend the particles back into screen. This works well for dust, dirt, and smoke like particles because they have low frequency textures. This low frequency masks the natural &#8220;blurring&#8221; that occurs from upscaling the smaller render target to the screen&#8217;s resolution.</p>
<h3>Rendering Depth</h3>
<p>First thing we&#8217;ll need is a depth buffer. By rendering to a separate render texture we can no longer take advantage of the GPU&#8217;s built-in z-testing. Having a depth buffer will allow us to do our own z-testing. Unity made it stupid easy to get a depth buffer of the scene with version 2.6.0. On the main camera run this line somewhere in Awake:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw1">this</span>.<span class="me1">camera</span>.<span class="me1">depthTextureMode</span> = DepthTextureMode.<span class="me1">Depth</span>;</div>
</div>
<p>However, for our purposes the depth buffer given to us by Unity is a bit overkill. Unity will render everything that the main camera can see. We only have dust-like particles near the camera, so there&#8217;s no reason for Unity to render depth information at far distances. So instead of taking advantage of Unity&#8217;s one-liner solution, we render our own depth buffer with a different far-clip plane. This isn&#8217;t as straight forward as setting the camera&#8217;s far-clip plane and is slightly outside of this article&#8217;s scope. We&#8217;ll address this in a future article.</p>
<h3>Rendering the Particles</h3>
<p>Here comes the hard part. First we&#8217;ll outline the steps we need to take to render the particles. All of this happens in the camera&#8217;s OnRenderImage function.</p>
<ol>
<li>Create/Setup the render texture that we will render our particles into</li>
<li>Create/Setup the camera that will render our particles</li>
<li>Render the particles with a replacement shader</li>
<li>Blend the particles back into the screen with a composite shader</li>
</ol>
<p>First we&#8217;ll create and setup the render texture that will hold our particles.</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="co1">// get the downsample factor</span><br />
<span class="kw2">var</span> downsampleFactor:int = <span class="kw1">this</span>.<span class="me1">offScreenParticlesOptions</span>.<span class="me1">downsampleFactor</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<br />
<span class="co1">// create the off-screen particles texture</span><br />
<span class="kw2">var</span> particlesRT:RenderTexture = RenderTexture.<span class="me1">GetTemporary</span><span class="br0">&#40;</span>Screen.<span class="me1">width</span> <span class="re0">/ downsampleFactor, Screen.<span class="me1">height</span> /</span> downsampleFactor, <span class="nu0">0</span><span class="br0">&#41;</span>;</div>
</div>
<p>The downsampleFactor determines the quality of the off-screen particles. Higher numbers will give worse quality, but better performance.</p>
<p>Next, we&#8217;ll create and setup the camera.</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">var</span> ppCamera:Camera = PostProcessingHelper.<span class="me1">GetPPCamera</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
ppCamera.<span class="me1">depthTextureMode</span> = DepthTextureMode.<span class="me1">None</span>;<br />
ppCamera.<span class="me1">cullingMask</span> = <span class="kw1">this</span>.<span class="me1">offScreenParticlesOptions</span>.<span class="me1">layerMask</span>.<span class="me1">value</span>;<br />
ppCamera.<span class="me1">targetTexture</span> = particlesRT;<br />
ppCamera.<span class="me1">clearFlags</span> = CameraClearFlags.<span class="me1">SolidColor</span>;<br />
ppCamera.<span class="me1">backgroundColor</span> = Color.<span class="me1">black</span>;</div>
</div>
<p>And the PostProcessingHelper.GetPPCamera() function:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">private</span> static <span class="kw2">var</span> ppCameraGO:GameObject;</p>
<p>static <span class="kw2">function</span> GetPPCamera<span class="br0">&#40;</span><span class="br0">&#41;</span>:Camera<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// Create the shader camera if it doesn&#8217;t exist yet</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>!ppCameraGO<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;ppCameraGO = <span class="kw2">new</span> GameObject<span class="br0">&#40;</span><span class="st0">&#8220;Post Processing Camera&#8221;</span>, Camera<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;ppCameraGO.<span class="me1">camera</span>.<span class="me1">enabled</span> = <span class="kw2">false</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;ppCameraGO.<span class="me1">hideFlags</span> = HideFlags.<span class="me1">HideAndDontSave</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp;<span class="kw1">return</span> ppCameraGO.<span class="me1">camera</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>Notice how we are setting the layer that the particles are on. This is how the camera determines which renderers in the scene are the particles that we wish to render off-screen.</p>
<p>Next we render the actual particles. Telling the camera to render is easy enough.</p>
<div class="codesnip-container" >
<div class="codesnip">Shader.<span class="me1">SetGlobalVector</span><span class="br0">&#40;</span><span class="st0">&#8220;_CameraDepthTexture_Size&#8221;</span>, Vector4<span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">camera</span>.<span class="me1">pixelWidth</span>, <span class="kw1">this</span>.<span class="me1">camera</span>.<span class="me1">pixelHeight</span>, <span class="nu0">0</span>.<span class="nu0">0</span>, <span class="nu0">0</span>.<span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#41;</span>; <span class="co1">// some data about the depth buffer we need to send the shaders</span><br />
depthCamera.<span class="me1">RenderWithShader</span><span class="br0">&#40;</span>Shader.<span class="me1">Find</span><span class="br0">&#40;</span><span class="st0">&#8220;Hidden/Off-Screen Particles Replace&#8221;</span><span class="br0">&#41;</span>, <span class="st0">&#8220;RenderType&#8221;</span><span class="br0">&#41;</span>;</div>
</div>
<p>The replacement shader is a bit unwieldy, so here it is as a <a href="http://capnrat.com/stuff/blogfiles/RS64OffScreenParticles/Hidden-OffScreenParticlesReplace.shader">file</a>. Don&#8217;t worry too much about what&#8217;s going on in the replacement shader. Just make sure to place this shader in a Resources folder.</p>
<p>Lastly, we blend the particles back into the scene.</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">var</span> blendMaterial:Material = PostProcessingHelper.<span class="me1">GetMaterial</span><span class="br0">&#40;</span>Shader.<span class="me1">Find</span><span class="br0">&#40;</span><span class="st0">&#8220;Hidden/Off-Screen Particles Composite&#8221;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
<span class="kw2">var</span> texelOffset:Vector2 = Vector2.<span class="me1">Scale</span><span class="br0">&#40;</span>source.<span class="me1">GetTexelOffset</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, Vector2<span class="br0">&#40;</span>source.<span class="me1">width</span>, source.<span class="me1">height</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
Graphics.<span class="me1">BlitMultiTap</span><span class="br0">&#40;</span>particlesRT, source, blendMaterial, texelOffset<span class="br0">&#41;</span>;</div>
</div>
<p>And the Composite shader (again, place this in a Resources folder):</p>
<div class="codesnip-container" >Shader &#8220;Hidden/Off-Screen Particles Composite&#8221; {<br />
Properties {<br />
    _MainTex (&#8221;Base (RGB)&#8221;, RECT) = &#8220;white&#8221; {}<br />
}<br />
    SubShader {<br />
        Pass {<br />
            ZTest Always Cull Off ZWrite Off Fog { Mode Off }<br />
            Blend One SrcAlpha<br />
            SetTexture[_MainTex] {combine texture}<br />
        }<br />
    }<br />
    Fallback Off<br />
}</div>
<p>Don&#8217;t forget to release the particles render texture!</p>
<div class="codesnip-container" >
<div class="codesnip">RenderTexture.<span class="me1">ReleaseTemporary</span><span class="br0">&#40;</span>particlesRT<span class="br0">&#41;</span>;</div>
</div>
<p>And after you finish doing any other post processing effects you may be doing, output to the destination RenderTexture:</p>
<div class="codesnip-container" >
<div class="codesnip">Graphics.<span class="me1">Blit</span><span class="br0">&#40;</span>source, destination<span class="br0">&#41;</span>;</div>
</div>
<h3>PRETTY PICTURES!</h3>
<p>Click for bigger images. These all should be pixel perfect if you want to flip through or diff them.</p>
<div class="wp-caption aligncenter" style="width: 460px"><a href="http://capnrat.com/stuff/blogfiles/RS64OffScreenParticles/Disabled.JPG"><img alt="Off-Screen Particles Disabled" src="http://capnrat.com/stuff/blogfiles/RS64OffScreenParticles/DisabledThumb.jpg" title="Off-Screen Particles Disabled" width="450" height="296" /></a><p class="wp-caption-text">Off-Screen Particles Disabled</p></div><br />
<div class="wp-caption aligncenter" style="width: 460px"><a href="http://capnrat.com/stuff/blogfiles/RS64OffScreenParticles/Enabled.JPG"><img alt="Off-Screen Particles Enabled" src="http://capnrat.com/stuff/blogfiles/RS64OffScreenParticles/EnabledThumb.jpg" title="Off-Screen Particles Enabled" width="450" height="296" /></a><p class="wp-caption-text">Off-Screen Particles Enabled</p></div><br />
<div class="wp-caption aligncenter" style="width: 460px"><a href="http://capnrat.com/stuff/blogfiles/RS64OffScreenParticles/OffScreen.JPG"><img alt="Off-Screen Particles RGB" src="http://capnrat.com/stuff/blogfiles/RS64OffScreenParticles/OffScreenThumb.jpg" title="Off-Screen Particles RGB" width="450" height="296" /></a><p class="wp-caption-text">Off-Screen Particles RGB</p></div><br />
<div class="wp-caption aligncenter" style="width: 460px"><a href="http://capnrat.com/stuff/blogfiles/RS64OffScreenParticles/OffScreenAlpha.JPG"><img alt="Off-Screen Particles Alpha" src="http://capnrat.com/stuff/blogfiles/RS64OffScreenParticles/OffScreenAlphaThumb.jpg" title="Off-Screen Particles Alpha" width="450" height="296" /></a><p class="wp-caption-text">Off-Screen Particles Alpha</p></div>
<h3>Notes</h3>
<p><strike><b>Separate Alpha Blend Function:</b> As of Unity 2.6.1, there is no way to blend alpha channels with a different blending function. So this replacement shader takes two passes on the particles. Once to render to the RGB channel and once to render to the Alpha channel. Apparently, this will be <a href="http://forum.unity3d.com/viewtopic.php?t=40800">fixed</a> in a future release of Unity and the separate pass will not be necessary. I&#8217;ll update this replacement shader if someone reminds me when that happens.</strike> <b>Update:</b> Looks like this can be accomplished with a single blending function if you premultiply the alpha into the rgb channel in the pixel shader. The new blending function for rendering the particles is One OneMinusSrcAlpha. The new blending function for blending the particle RT back into the screen buffer is One OneMinusSrcAlpha. And your particle RT will need to be cleared to (0,0,0,0) instead of (0,0,0,1).</p>
<p><b>Mixed Resolution:</b> We decided that mixed resolution particles wasn&#8217;t necessary for us. The scene is too fast moving to notice the depth sampling artifacts. Plus the performance overhead from needing a second pass for the alpha channel made mixed resolution rendering just too expensive.</p>
<p><b>Soft Particles:</b> Soft Particles are extremely easy to implement with the off-screen particles, but we didn&#8217;t see much of a difference in the final render. We decided to just use discard instead of soft particles in the end.</p>
<p><b>Anti-aliasing:</b> This is untested with Anti-aliasing on directx. I really doubt it&#8217;ll work correctly as is. Shouldn&#8217;t be too difficult to get it to work though.</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.blurst.com/off-screen-particle-optimization/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Removing White Halos in Transparent Textures</title>
		<link>http://technology.blurst.com/remove-white-borders-in-transparent-textures/</link>
		<comments>http://technology.blurst.com/remove-white-borders-in-transparent-textures/#comments</comments>
		<pubDate>Tue, 29 Dec 2009 21:56:25 +0000</pubDate>
		<dc:creator>Matthew Wegner</dc:creator>
		
		<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://technology.blurst.com/?p=262</guid>
		<description><![CDATA[Unity allows native importing of PSD textures, which is awesome for workflow and iteration speeds.  However, transparent textures frequently exhibit white &#8220;halos&#8221; around objects.  This issue stems from Photoshop itself&#8211;fully transparent pixels are usually white in color, which means texture sampling will pick up these white pixels when your texture is scaled down.
Here [...]]]></description>
			<content:encoded><![CDATA[<p>Unity allows native importing of PSD textures, which is awesome for workflow and iteration speeds.  However, transparent textures frequently exhibit white &#8220;halos&#8221; around objects.  This issue stems from Photoshop itself&#8211;fully transparent pixels are usually white in color, which means texture sampling will pick up these white pixels when your texture is scaled down.</p>
<p>Here is an automated solution to this problem (you&#8217;ll probably want to <a href="http://vimeo.com/8444889">watch full-size on Vimeo</a>):</p>
<p><object width="450" height="253"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=8444889&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=1&amp;color=ff9933&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=8444889&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=1&amp;color=ff9933&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="450" height="253"></embed></object></p>
<p>You&#8217;ll need <a href="http://www.flamingpear.com/download.html">Flaming Pear&#8217;s free Solidify plugin</a> and <a href="/examples/Alpha.atn">this set of Photoshop Actions</a>.  Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.blurst.com/remove-white-borders-in-transparent-textures/feed/</wfw:commentRss>
		</item>
		<item>
		<title>JPEG Encoding in Native Unity JavaScript</title>
		<link>http://technology.blurst.com/unity-jpg-encoding-javascript/</link>
		<comments>http://technology.blurst.com/unity-jpg-encoding-javascript/#comments</comments>
		<pubDate>Sat, 28 Nov 2009 23:55:25 +0000</pubDate>
		<dc:creator>Matthew Wegner</dc:creator>
		
		<category><![CDATA[Scripts]]></category>

		<guid isPermaLink="false">http://technology.blurst.com/?p=234</guid>
		<description><![CDATA[A few months ago someone posted to the Unity forums about how to encode a JPEG file without writing to disk.  It piqued my curiosity, so I poked at it.  It turned out that the required .NET libraries aren&#8217;t available in Unity (likely for size reasons, but maybe it&#8217;s a Mono thing).  Bummer.
Native Encoding
The [...]]]></description>
			<content:encoded><![CDATA[<p>A few months ago someone <a href="http://forum.unity3d.com/viewtopic.php?t=33658">posted to the Unity forums</a> about how to encode a JPEG file without writing to disk.  It piqued my curiosity, so I poked at it.  It turned out that the required .NET libraries aren&#8217;t available in Unity (likely for size reasons, but maybe it&#8217;s a Mono thing).  Bummer.</p>
<h3>Native Encoding</h3>
<p>The solution to this problem is to implement a JPEG encoder in native C# or JavaScript in Unity.  The other day I saw someone link to a <a href="http://www.bytestrom.eu/blog/2009/1120a_jpeg_encoder_for_javascript">browser JavaScript implementation</a> of JPEG encoding, which was based off the <a href="http://code.google.com/p/as3corelib/source/browse/trunk/src/com/adobe/images/JPGEncoder.as">as3corelib implementation from Flash</a>.  Eureka!  It looked like an easy port, and an interesting exercise, so I went ahead and brought it over Unity JavaScript.</p>
<h3>Using the JPEG Encoder</h3>
<p>Usage is quite simple:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="co1">// spin up the JPEG encoder</span><br />
<span class="kw2">var</span> encoder:JPGEncoder = <span class="kw2">new</span> JPGEncoder<span class="br0">&#40;</span>texture, <span class="nu0">75</span>.<span class="nu0">0</span><span class="br0">&#41;</span>;</p>
<p><span class="co1">// encoder is threaded; wait for it to finish</span><br />
<span class="kw1">while</span><span class="br0">&#40;</span>!encoder.<span class="me1">isDone</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;yield;</p>
<p><span class="co1">// do something with bytes (like WWW upload or save to disk)</span><br />
<span class="kw2">var</span> bytes:byte<span class="br0">&#91;</span><span class="br0">&#93;</span> = encoder.<span class="me1">GetBytes</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</div>
<p>The encoder is threaded, so the calling script needs to yield until it&#8217;s complete.  <em>Warning</em>:  We have never actually used threads in Unity; this might totally blow up in your face!  If that&#8217;s the case it&#8217;d be easy to pseudo-thread it with a few yield statements (or just run it straight in circumstances where a frame hitch isn&#8217;t a big deal&#8211;capture the screen and hold on to the image bits until the player is at a good static GUI screen or something).</p>
<h3>Possible Uses</h3>
<p>Why would you want such a thing?  Perhaps you want to allow the player to take screenshots from a standalone build, saved to disk.  Or perhaps you want to upload images to your server (Unity has an <a href="http://unity3d.com/support/documentation/ScriptReference/Texture2D.EncodeToPNG.html">EncodeToPNG</a> function, but they can be quite large for network transmission).  <a href="http://blurst.com/splume/">Splume</a>, one of our first Unity games, had a level editor that simply uploaded game screenshots as thumbnails:</p>
<p align="center"><img src="http://splume.flashbangstudios.com/levelpics/1906-160.png" alt="Splume 1" /> <img src="http://splume.flashbangstudios.com/levelpics/862-160.png" alt="Splume 2" /></p>
<p>We also uploaded screenshots when something big would happen, like a huge scoring combo.</p>
<h3>Download the Encoder and Sample Project</h3>
<p><a href="/examples/JPEG_Encoding.zip">Download a simple project</a> that takes screenshots and outputs .JPG files.  Just drop JPGEncoder.js into your own projects to use native JPEG encoding.  Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.blurst.com/unity-jpg-encoding-javascript/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Unity Asset Server Browser</title>
		<link>http://technology.blurst.com/unity-asset-server-web-browser/</link>
		<comments>http://technology.blurst.com/unity-asset-server-web-browser/#comments</comments>
		<pubDate>Fri, 29 May 2009 19:23:26 +0000</pubDate>
		<dc:creator>Matthew Wegner</dc:creator>
		
		<category><![CDATA[Backend/Database]]></category>

		<category><![CDATA[Asset Server]]></category>

		<guid isPermaLink="false">http://technology.blurst.com/?p=223</guid>
		<description><![CDATA[Unity&#8217;s Asset Server is a key piece of technology in our workflow.  It provides per-asset source control inside of Unity, which is absolutely required for larger projects with multiple team members.  Unity 2.5 introduced in-Unity browsing of the asset server&#8211;update history, asset history, etc&#8211;but we still use our own web-based browser today.  It&#8217;s a convenient [...]]]></description>
			<content:encoded><![CDATA[<p>Unity&#8217;s Asset Server is a key piece of technology in our workflow.  It provides per-asset source control inside of Unity, which is absolutely required for larger projects with multiple team members.  Unity 2.5 introduced in-Unity browsing of the asset server&#8211;update history, asset history, etc&#8211;but we still use our own web-based browser today.  It&#8217;s a convenient way to quick check an asset or update without launching Unity and opening your project. Searching is also much easier, as our browser has a page with all updates and commit descriptions.</p>
<p>Here&#8217;s our browser in action (<a href="http://vimeo.com/4905144">or watch in HD)</a>:</p>
<p><object width="450" height="253"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=4905144&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=1&amp;color=fcb100&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=4905144&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=1&amp;color=fcb100&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="450" height="253"></embed></object></p>
<p>We&#8217;re releasing it!  <a href="/assetserverbrowser/unity_asset_server_browser_1.0.zip">Download the source code</a> or check out the <a href="/assetserverbrowser/README.txt">README.txt file</a>.  If you find this useful feel free to donate beer money:  paypal@blurst.com!</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.blurst.com/unity-asset-server-web-browser/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Getting Tricky with Triggers</title>
		<link>http://technology.blurst.com/unity-physics-trigger-collider-examples/</link>
		<comments>http://technology.blurst.com/unity-physics-trigger-collider-examples/#comments</comments>
		<pubDate>Fri, 29 May 2009 04:54:59 +0000</pubDate>
		<dc:creator>Matthew Wegner</dc:creator>
		
		<category><![CDATA[Code Snippets]]></category>

		<category><![CDATA[Physics]]></category>

		<guid isPermaLink="false">http://technology.blurst.com/?p=179</guid>
		<description><![CDATA[Unity triggers are insanely useful.  If you aren&#8217;t using physics triggers&#8211;even if your game is seemingly non-physical&#8211;you&#8217;re missing out on some of the most powerful functionality in Unity.  Let&#8217;s take a look:
What&#8217;s a Trigger?
A trigger is a Collider that fires events as other Colliders enter and leave its collision volume, but without physically interacting with [...]]]></description>
			<content:encoded><![CDATA[<p>Unity triggers are insanely useful.  If you <em>aren&#8217;t</em> using physics triggers&#8211;even if your game is seemingly non-physical&#8211;you&#8217;re missing out on some of the most powerful functionality in Unity.  Let&#8217;s take a look:</p>
<h3>What&#8217;s a Trigger?</h3>
<p>A trigger is a Collider that fires events as other Colliders enter and leave its collision volume, but without physically interacting with your scene.  They are physically &#8220;invisible&#8221;.  If a Rigidbody &#8220;hits&#8221; a trigger, it passes right through, but the trigger produces OnTriggerEnter calls, when the object enters, OnTriggerStay calls, for as long as the object is inside the trigger, and OnTriggerExit calls, for when the object leaves the trigger.</p>
<p>Take a look at the <a href="http://unity3d.com/support/documentation/Components/class-BoxCollider.html">Unity collider documentation </a>for a more verbose explanation, as well as the collision chart for when collision events are called.</p>
<h3>Where to Use Triggers?</h3>
<p>We use triggers as:</p>
<h4>Static Proximity Triggers</h4>
<p>The most obvious trigger example is to use them as, well, actual proximity triggers.  Some piece of game logic is run when the player, or another object, reaches a point in space.  You could place a trigger in front of a door which causes the door to open as the player approaches.  You can easily test the entered Collider for some layer, tag, or Component to see if the trigger should execute.  This is as sample as:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">function</span> OnTriggerEnter<span class="br0">&#40;</span>other:Collider<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// only process if we&#8217;re the player</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>!other.<span class="me1">CompareTag</span><span class="br0">&#40;</span><span class="st0">&#8220;Player&#8221;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// does the player have the blue key?&nbsp; if not, boo</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>!Player.<span class="me1">HasKey</span><span class="br0">&#40;</span><span class="st0">&#8220;blue&#8221;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// actually open the door!</span><br />
<span class="br0">&#125;</span></div>
</div>
<h4>Radius Triggers</h4>
<p>The first trick with triggers is to realize they can move.  You can set a trigger as a child of an object&#8211;even another physical object like a Rigidbody&#8211;and then use the trigger to take action as other objects approach or exit a radius around your object of interest.</p>
<p>Take the use case of spawn points, for instance; your goal is to trigger an enemy spawn as a spawn point nears your player.  You <em>could</em> place a script on your player that iterates all possible spawn points and spawns something if it&#8217;s near enough:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">function</span> FixedUpdate<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
<span class="kw1">for</span><span class="br0">&#40;</span><span class="kw2">var</span> spawn:SpawnPoint <span class="kw1">in</span> allSpawns<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>Vector3.<span class="me1">Distance</span><span class="br0">&#40;</span>transform.<span class="me1">position</span>, spawn.<span class="me1">transform</span>.<span class="me1">position</span> &lt; spawnRadius<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;spawn.<span class="me1">DoSpawn</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>The #1 reason for using triggers, over this &#8220;manual&#8221; method, is that triggers will be faster.  <em>Much</em> faster!  There are ways to make this example better&#8211;check the sqrMagnitude of the distance to avoid a square root, cache your Transform, etc&#8211;but the crux of the problem remains:  You have to run this code every Update, FixedUpdate, or at least with enough frequency to respond interactively.</p>
<p>However, the physics engine <em>is already checking for trigger collisions</em>.  It&#8217;s doing the work for you!  Let it do its super-fast optimized thing; believe me, you can&#8217;t compete with PhysX on an optimization level.  Instead of polling for spawn points in our radius ourselves, let the physics engine send events only when something enters our player radius trigger.  This becomes:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">function</span> OnTriggerEnter<span class="br0">&#40;</span>other:Collider<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> spawn:SpawnPoint = other.<span class="me1">GetComponent</span><span class="br0">&#40;</span>SpawnPoint<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>spawn<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;spawn.<span class="me1">DoSpawn</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>Create a gigantic trigger as a child of your player object, place this script on it, and voila!  To prevent collision with your physical gameplay objects, your spawn colliders should also be triggers (yes, triggers send OnTrigger* messages when other triggers enter and exit).</p>
<p>Warning:  Trigger colliders <em>do</em> respond to raycasts.  You should make sure your triggers are set to the Ignore Raycasts layer if your game logic uses raycasts (or are otherwise ignored by your raycast LayerMasks).</p>
<h4>What&#8217;s In This Space?</h4>
<p>Another great use of triggers is to the answer a question for your game logic:  What&#8217;s in this space?  Perhaps you want your spawn points to fire only if they&#8217;re empty, or you want to see if two objects are near enough to count for something.</p>
<p>Here&#8217;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:</p>
<p><a href="http://technology.blurst.com/wp-content/uploads/2009/05/crane_wars_stack.jpg"><img src="http://technology.blurst.com/wp-content/uploads/2009/05/crane_wars_stack.jpg" alt="" title="Crane Wars Triggers" width="486" height="421" class="alignnone size-full wp-image-195" /></a></p>
<p>The slim box outlines on the top of the building pieces are the triggers.  White indicates that nothing is in the trigger, and green&#8211;the bottom two floors of the stack&#8211;indicate that another building piece is in the trigger and is considered the &#8220;upstairs&#8221; piece in the sequence.  The light blue box is a spawn point; it will spawn another piece as soon as it is empty.</p>
<p>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&#8217;s fairly easy logic.  The following script will track <em>all</em> objects that enter, and store them in a list based on their layer:</p>
<div class="codesnip-container" >
<div class="codesnip">#pragma strict<br />
@script AddComponentMenu<span class="br0">&#40;</span><span class="st0">&#8220;Library/Physics/Trigger Track By Layer&#8221;</span><span class="br0">&#41;</span></p>
<p><span class="coMULTI">/**<br />
* Keep a list of all objects inside this trigger, available by layer<br />
* <br />
* Layer -1 is a list of all objects<br />
*/</span></p>
<p><span class="co1">// should we track triggers too?</span><br />
<span class="kw2">var</span> trackOtherTriggers:boolean = <span class="kw2">false</span>;</p>
<p><span class="co1">// objects we aren&#8217;t tracking</span><br />
<span class="kw2">var</span> ignoreColliders:Collider<span class="br0">&#91;</span><span class="br0">&#93;</span>;</p>
<p><span class="co1">// hashtable of arraylists for our objects</span><br />
<span class="kw2">private</span> <span class="kw2">var</span> objects:Hashtable = <span class="kw2">new</span> Hashtable<span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p><span class="coMULTI">/**<br />
* Initialize internals<br />
*/</span><br />
<span class="kw2">function</span> Awake<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// -1 is all layers</span><br />
&nbsp; &nbsp;objects<span class="br0">&#91;</span>-<span class="nu0">1</span><span class="br0">&#93;</span> = <span class="kw2">new</span> ArrayList<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="coMULTI">/**<br />
* Return an arraylist for a layer&#8211;if no layer, just make an empty one<br />
*/</span><br />
<span class="kw2">function</span> GetObjects<span class="br0">&#40;</span>layer:int<span class="br0">&#41;</span>:ArrayList<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> list:ArrayList = objects<span class="br0">&#91;</span>layer<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// scrub any nulls when scripts request a list</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>list<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;Helpers.<span class="me1">ClearArrayListNulls</span><span class="br0">&#40;</span>list<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> list;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw1">else</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> <span class="kw2">new</span> ArrayList<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="coMULTI">/**<br />
* Record when objects enter<br />
*/</span><br />
<span class="kw2">function</span> OnTriggerEnter<span class="br0">&#40;</span>other:Collider<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>!trackOtherTriggers &amp;&amp; other.<span class="me1">isTrigger</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span>;&nbsp; <br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// is this collider in our ignore list?</span><br />
&nbsp; &nbsp;<span class="kw1">for</span><span class="br0">&#40;</span><span class="kw2">var</span> testIgnore:Collider <span class="kw1">in</span> ignoreColliders<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>testIgnore == other<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw2">var</span> go:GameObject = other.<span class="me1">gameObject</span>;<br />
&nbsp; &nbsp;<span class="kw2">var</span> layer:int = go.<span class="me1">layer</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// create our list if none exists</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>!objects<span class="br0">&#91;</span>layer<span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;objects<span class="br0">&#91;</span>layer<span class="br0">&#93;</span> = <span class="kw2">new</span> ArrayList<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw2">var</span> list:ArrayList = objects<span class="br0">&#91;</span>layer<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// add if not present</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>!list.<span class="me1">Contains</span><span class="br0">&#40;</span>go<span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;list.<span class="me1">Add</span><span class="br0">&#40;</span>go<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// add to all</span><br />
&nbsp; &nbsp;list = objects<span class="br0">&#91;</span>-<span class="nu0">1</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>!list.<span class="me1">Contains</span><span class="br0">&#40;</span>go<span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;list.<span class="me1">Add</span><span class="br0">&#40;</span>go<span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="coMULTI">/**<br />
* Update when objects leave<br />
*/</span><br />
<span class="kw2">function</span> OnTriggerExit<span class="br0">&#40;</span>other:Collider<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>!trackOtherTriggers &amp;&amp; other.<span class="me1">isTrigger</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span>;&nbsp; <br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// is this collider in our ignore list?</span><br />
&nbsp; &nbsp;<span class="kw1">for</span><span class="br0">&#40;</span><span class="kw2">var</span> testIgnore:Collider <span class="kw1">in</span> ignoreColliders<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>testIgnore == other<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span>;&nbsp; <br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw2">var</span> go:GameObject = other.<span class="me1">gameObject</span>;<br />
&nbsp; &nbsp;<span class="kw2">var</span> layer:int = go.<span class="me1">layer</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// remove from all</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> list:ArrayList = objects<span class="br0">&#91;</span>-<span class="nu0">1</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;list.<span class="me1">Remove</span><span class="br0">&#40;</span>go<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// Remove from layer&#8217;s list if it&#8217;s present</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>objects<span class="br0">&#91;</span>layer<span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;list = objects<span class="br0">&#91;</span>layer<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;list.<span class="me1">Remove</span><span class="br0">&#40;</span>go<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="coMULTI">/**<br />
* Spew our list as an overlay in debug mode<br />
*/</span><br />
<span class="kw2">function</span> OnGUI<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>!Global.<span class="kw2">use</span>.<span class="me1">debug</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw2">var</span> debug:String = <span class="st0">&#8220;&#8221;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw1">for</span><span class="br0">&#40;</span><span class="kw2">var</span> de:DictionaryEntry <span class="kw1">in</span> objects<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> list:ArrayList = de.<span class="me1">Value</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> layer:int = de.<span class="me1">Key</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>layer == -<span class="nu0">1</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">continue</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;debug += String.<span class="me1">Format</span><span class="br0">&#40;</span><span class="st0">&#8220;{0} : {1}<span class="es0">\n</span>&#8220;</span>, LayerMask.<span class="me1">LayerToName</span><span class="br0">&#40;</span>de.<span class="me1">Key</span><span class="br0">&#41;</span>, list.<span class="me1">Count</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw2">var</span> screen:Vector3 = Camera.<span class="me1">main</span>.<span class="me1">WorldToScreenPoint</span><span class="br0">&#40;</span>transform.<span class="me1">position</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;GUI.<span class="me1">contentColor</span> = Color.<span class="me1">red</span>;<br />
&nbsp; &nbsp;GUI.<span class="me1">Label</span><span class="br0">&#40;</span><span class="kw2">new</span> Rect<span class="br0">&#40;</span>screen.<span class="me1">x</span>, Screen.<span class="me1">height</span> - screen.<span class="me1">y</span>, <span class="nu0">256</span>, <span class="nu0">128</span><span class="br0">&#41;</span>, debug<span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>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.</p>
<p>Rather than poll this list continuously, our game logic script only checks for an update when things may have changed&#8211;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:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="co1">// should we do a calculation next update?</span><br />
<span class="kw2">var</span> isDirty:boolean = <span class="kw2">false</span>;</p>
<p><span class="co1">// cache our tracker reference</span><br />
<span class="kw2">private</span> <span class="kw2">var</span> tracker:TriggerTrackByLayer;<br />
tracker = GetComponent<span class="br0">&#40;</span>TriggerTrackByLayer<span class="br0">&#41;</span>;</p>
<p><span class="coMULTI">/**<br />
* Recalculate status every object<br />
*/</span><br />
<span class="kw2">function</span> OnTriggerEnter<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span>&nbsp; <br />
&nbsp; &nbsp;isDirty = <span class="kw2">true</span>;<br />
<span class="br0">&#125;</span><br />
<span class="kw2">function</span> OnTriggerExit<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;isDirty = <span class="kw2">true</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="coMULTI">/**<br />
* Check for dirty every FixedUpdate (after OnTrigger* calls)<br />
*/</span><br />
<span class="kw2">function</span> FixedUpdate<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>isDirty<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// do our game logic, ie:</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> objectsInside = tracker.<span class="me1">GetObjects</span><span class="br0">&#40;</span>someLayerNumber<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// unset to prevent logic every frame</span><br />
&nbsp; &nbsp;isDirty = <span class="kw2">false</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>We use another variant that only tracks objects that match a certain LayerMask, which lets you avoid the overhead of tracking <em>all</em> objects in and out.  The <a href="/examples/triggers.zip">example project</a> includes both scripts.</p>
<p>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:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="coMULTI">/**<br />
* Debug display of our trigger state<br />
*/</span><br />
<span class="kw2">function</span> OnDrawGizmos<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// set to whatever color you want to represent</span><br />
&nbsp; &nbsp;Gizmos.<span class="me1">color</span> = Color.<span class="me1">green</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// we&#8217;re going to draw the gizmo in local space</span><br />
&nbsp; &nbsp;Gizmos.<span class="me1">matrix</span> = transform.<span class="me1">localToWorldMatrix</span>;&nbsp; &nbsp;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// draw a box collider based on its size</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> box:BoxCollider = GetComponent<span class="br0">&#40;</span>BoxCollider<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;Gizmos.<span class="me1">DrawWireCube</span><span class="br0">&#40;</span>box.<span class="me1">center</span>, box.<span class="me1">size</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<h3>Trigger Tips and Caveats</h3>
<p>This article mentions a few already, but to recap:</p>
<ul>
<li>Other triggers <em>will</em> &#8220;collide&#8221; with triggers!  Use this for invisible triggers that don&#8217;t collide with your actual physics (spawn point triggers, etc).</li>
<li>Triggers <em>do</em> respond to raycasts!  Make sure your triggers are set to ignore raycasts, unless you really want to raycast against them.</li>
<li>An object destroyed inside of a trigger will not fire OnTriggerExit.  If you track objects be wary of this.  The only sure way to count objects currently inside of a trigger is to use OnTriggerStay</li>
<li>Triggers are fast!  Use them!  Even in non-physical games you will see speed increases.  For example, you could have a tower defense game where your enemies are kinematic rigidbodies and turrets track targets in range using triggers.</li>
<li>There is a penalty for moving static colliders (a Collider with no Rigidbody component).  If you want to move your trigger around, add a Rigidbody and set it to be kinematic.
<li>Triggers are great on the iPhone, since everything happens in highly optimized PhysX.  You&#8217;d be surprised.</li>
</ul>
<h3>Example Project</h3>
<p>The above-mentioned scripts are included in a quick example project (so don&#8217;t worry about copying and pasting off the post).  <a href="/examples/triggers.zip">Download the example project</a> and check them out!</p>
<h3>Other Uses?</h3>
<p>How have you guys been using triggers?  Share your own tips and tricks in the comments!</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.blurst.com/unity-physics-trigger-collider-examples/feed/</wfw:commentRss>
		</item>
		<item>
		<title>All Hail Camera.RenderWithShader</title>
		<link>http://technology.blurst.com/camera-render-with-shader/</link>
		<comments>http://technology.blurst.com/camera-render-with-shader/#comments</comments>
		<pubDate>Wed, 11 Mar 2009 22:46:15 +0000</pubDate>
		<dc:creator>Shawn White</dc:creator>
		
		<category><![CDATA[Graphics]]></category>

		<category><![CDATA[Blush]]></category>

		<category><![CDATA[Jetpack Brontosaurus]]></category>

		<category><![CDATA[Post Processing]]></category>

		<category><![CDATA[Shaders]]></category>

		<guid isPermaLink="false">http://technology.blurst.com/?p=136</guid>
		<description><![CDATA[&#8220;one day there was no internet in the office, so I did not know what bugs to fix&#8230; so I played around with this instead :)&#8221; - Aras Pranckevičius
That day of internet outage is probably one of the happiest days for me using the Unity3d engine. On that fateful day Camera.RenderWithShader was born which lived [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p><em>&#8220;one day there was no internet in the office, so I did not know what bugs to fix&#8230; so I played around with this instead :)&#8221;</em> - Aras Pranckevičius</p></blockquote>
<p>That day of internet outage is probably one of the happiest days for me using the Unity3d engine. On that fateful day Camera.RenderWithShader was born which lived on to become the backbone of almost all of our post processing effects. The best way to explain how this makes a world of difference in our projects is to just give examples of how we handled post processing effects before and after replacement shaders.</p>
<h2>Jetpack Brontosaurus</h2>
<p><a href="http://technology.blurst.com/wp-content/uploads/2009/03/jbgameplay.png"><img src="http://technology.blurst.com/wp-content/uploads/2009/03/jbgameplay-300x157.png" alt="" title="Jetback Brontosaurus Graphics" width="300" height="157" class="aligncenter size-medium wp-image-171" /></a></p>
<h3>What We Did</h3>
<p>We haven&#8217;t posted a graphics postmortem for Jetpack Brontosaurus yet.  This post will simplify the techniques we used in order to demonstrate how we accomplished the &#8220;multiple dimension&#8221; effect. Each object in Jetpack Brontosaurus has at least three renderers associated with it. One for the nightmare/death dimension, one for the dream/living dimension, and one for the mask that determines which dimension gets rendered to the screen. The renderers are divided into each dimension by using different layers. We have a different camera for each dimension. One camera is set to render all the renderers in the nightmare dimension, one camera is set for the dream dimension, and one for the mask. These cameras output their renders to separate render textures. Then we combine the two dimensions based on the color in the mask.</p>
<p style="text-align: center;"><a href="http://technology.blurst.com/wp-content/uploads/2009/02/jbrgbmask.jpg"><img class="aligncenter size-medium wp-image-139" title="Jetpack Brontosaurus Multiple Dimension Composition" src="http://technology.blurst.com/wp-content/uploads/2009/02/jbrgbmask-250x300.jpg" alt="" width="250" height="300" /></a></p>
<p style="text-align: left;">The implementation required each of the three renderers to have its own game object, material, and layer.  As a result, the complexity of the scenes increased, producing redundant information and human errors.</p>
<h3 style="text-align: left;"><a href="http://technology.blurst.com/wp-content/uploads/2009/03/jbcameras.png"><img class="aligncenter size-full wp-image-143" title="Jetpack Brontosaurus Camera Architecture" src="http://technology.blurst.com/wp-content/uploads/2009/03/jbcameras.png" alt="" width="200" height="194" /></a><a href="http://technology.blurst.com/wp-content/uploads/2009/03/jbobject.png"><img class="aligncenter size-full wp-image-144" title="Typical Jetpack Brontosaurus Object" src="http://technology.blurst.com/wp-content/uploads/2009/03/jbobject.png" alt="" width="200" height="65" /></a></h3>
<h3 style="text-align: left;">What We Could Have Done</h3>
<p>If we had the ability to use replacement shaders during Jetpack Brontosaurus production, everyone&#8217;s life would have been easier. Most of the renderers in Jetpack Brontosaurus used a vertex color shader. Because the renderers shared the same shader, using a replacement shader is an easy change.</p>
<p>An important thing to note here is that all of the tags have the same Key/Value pair.</p>
<p>The dream replacement shader:</p>
<div class="codesnip-container" >
<div class="codesnip">Shader <span class="st0">&#8220;Bronto/Dream Replace&#8221;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;SubShader <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;Tags <span class="br0">&#123;</span><span class="st0">&#8220;RenderEffect&#8221;</span>=<span class="st0">&#8220;Multidimensional&#8221;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;Pass <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;ColorMaterial AmbientAndDiffuse<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Lighting Off<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SetTexture <span class="br0">&#91;</span>_DreamTex<span class="br0">&#93;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Combine texture * primary, primary<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>The death replacement shader:</p>
<div class="codesnip-container" >
<div class="codesnip">Shader <span class="st0">&#8220;Bronto/Death Replace&#8221;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;SubShader <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;Tags <span class="br0">&#123;</span><span class="st0">&#8220;RenderEffect&#8221;</span>=<span class="st0">&#8220;Multidimensional&#8221;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;Pass <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;ColorMaterial AmbientAndDiffuse<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Lighting Off<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SetTexture <span class="br0">&#91;</span>_DeathTex<span class="br0">&#93;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Combine texture * primary, primary<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>The mask replacement shader:</p>
<div class="codesnip-container" >
<div class="codesnip">Shader <span class="st0">&#8220;Bronto/Mask Replace&#8221;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;SubShader <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;Tags <span class="br0">&#123;</span><span class="st0">&#8220;RenderEffect&#8221;</span>=<span class="st0">&#8220;Multidimensional&#8221;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;Pass <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Lighting Off<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Color <span class="br0">&#91;</span>_MaskColor<span class="br0">&#93;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>Now we have one shader that has texture and color information for all of dimensions in a single material. No need for more than one renderer per object anymore!</p>
<p>The shader used by the material for the renderers (this shader is also used for rendering the object to the scene view):</p>
<div class="codesnip-container" >
<div class="codesnip">Shader <span class="st0">&#8220;Bronto/Multidimensional Object&#8221;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;Properties <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;_DreamTex <span class="br0">&#40;</span><span class="st0">&#8220;Dream Dimension Texture&#8221;</span>, 2D<span class="br0">&#41;</span> = <span class="st0">&#8220;white&#8221;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;_DeathTex <span class="br0">&#40;</span><span class="st0">&#8220;Death Dimension Texture&#8221;</span>, 2D<span class="br0">&#41;</span> = <span class="st0">&#8220;white&#8221;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;_MaskColor <span class="br0">&#40;</span><span class="st0">&#8220;Mask Color&#8221;</span>, Color<span class="br0">&#41;</span> = <span class="br0">&#40;</span><span class="nu0">1</span>,<span class="nu0">0</span>,<span class="nu0">0</span>,<span class="nu0">1</span><span class="br0">&#41;</span> <span class="co1">// Alpha used for interpolating between the two textures in the scene view</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;SubShader <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;Tags <span class="br0">&#123;</span><span class="st0">&#8220;RenderEffect&#8221;</span>=<span class="st0">&#8220;Multidimensional&#8221;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;Pass <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;ColorMaterial AmbientAndDiffuse<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Lighting Off<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SetTexture <span class="br0">&#91;</span>_DreamTex<span class="br0">&#93;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Combine texture<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SetTexture <span class="br0">&#91;</span>_DeathTex<span class="br0">&#93;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;constantColor <span class="br0">&#91;</span>_MaskColor<span class="br0">&#93;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;combine previous lerp<span class="br0">&#40;</span>constant<span class="br0">&#41;</span> texture<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SetTexture <span class="br0">&#91;</span>_DeathTex<span class="br0">&#93;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;combine previous * primary<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>For ingame rendering the material shader is never used. The only shaders used are the replacement shaders.</p>
<p>Now we have a script on the scene&#8217;s camera that renders the scene with each replacement shader and then composites them. The scene&#8217;s camera should be set to render nothing in its culling mask.</p>
<div class="codesnip-container" >
<div class="codesnip">#pragma strict<br />
@script ExecuteInEditMode<br />
@script RequireComponent <span class="br0">&#40;</span>Camera<span class="br0">&#41;</span></p>
<p><span class="co1">// The culling mask that should be used for rendering</span><br />
<span class="kw2">var</span> cullingMask : LayerMask;</p>
<p><span class="co1">// The replacement shaders</span><br />
<span class="kw2">var</span> dreamReplacementShader : Shader;<br />
<span class="kw2">var</span> deathReplacementShader : Shader;<br />
<span class="kw2">var</span> maskReplacmentShader : Shader;</p>
<p><span class="co1">// The magic composite material</span><br />
<span class="kw2">var</span> dimensionCompositeMaterial : Material;</p>
<p><span class="co1">// The render textures for each dimension</span><br />
<span class="kw2">private</span> <span class="kw2">var</span> dreamRT : RenderTexture;<br />
<span class="kw2">private</span> <span class="kw2">var</span> deathRT : RenderTexture;<br />
<span class="kw2">private</span> <span class="kw2">var</span> maskRT : RenderTexture;</p>
<p><span class="co1">// The camera that renders the replacement shaders (Don&#8217;t access this directly, use GetPPCamera())</span><br />
<span class="kw2">private</span> <span class="kw2">var</span> ppCamera:Camera;</p>
<p><span class="coMULTI">/**<br />
* Handle any needed pre processing<br />
*/</span><br />
<span class="kw2">function</span> OnPreCull<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// Start from nothing</span><br />
&nbsp; &nbsp;CleanRenderTextures<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// Reference to ppCamera&#8217;s camera</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> cam:Camera = GetPPCamera<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// Set up camera</span><br />
&nbsp; &nbsp;cam.<span class="me1">CopyFrom</span><span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">camera</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;cam.<span class="me1">cullingMask</span> = <span class="kw1">this</span>.<span class="me1">cullingMask</span>;<br />
&nbsp; &nbsp;cam.<span class="me1">clearFlags</span> = CameraClearFlags.<span class="me1">Skybox</span>;<br />
&nbsp; &nbsp;cam.<span class="me1">backgroundColor</span> = Color<span class="br0">&#40;</span><span class="nu0">0</span>.<span class="nu0">0</span>,<span class="nu0">0</span>.<span class="nu0">0</span>,<span class="nu0">0</span>.<span class="nu0">0</span>,<span class="nu0">0</span>.<span class="nu0">0</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// Render Dream Dimension</span><br />
&nbsp; &nbsp;dreamRT = RenderTexture.<span class="me1">GetTemporary</span><span class="br0">&#40;</span>Screen.<span class="me1">width</span>, Screen.<span class="me1">height</span>, <span class="nu0">16</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;cam.<span class="me1">targetTexture</span> = dreamRT;<br />
&nbsp; &nbsp;cam.<span class="me1">RenderWithShader</span><span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">dreamReplacementShader</span>, <span class="st0">&#8220;RenderEffect&#8221;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// Render Death Dimension</span><br />
&nbsp; &nbsp;deathRT = RenderTexture.<span class="me1">GetTemporary</span><span class="br0">&#40;</span>Screen.<span class="me1">width</span>, Screen.<span class="me1">height</span>, <span class="nu0">16</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;cam.<span class="me1">targetTexture</span> = deathRT;<br />
&nbsp; &nbsp;cam.<span class="me1">RenderWithShader</span><span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">deathReplacementShader</span>, <span class="st0">&#8220;RenderEffect&#8221;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// Render Death Dimension</span><br />
&nbsp; &nbsp;maskRT = RenderTexture.<span class="me1">GetTemporary</span><span class="br0">&#40;</span>Screen.<span class="me1">width</span>, Screen.<span class="me1">height</span>, <span class="nu0">16</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;cam.<span class="me1">targetTexture</span> = maskRT;<br />
&nbsp; &nbsp;cam.<span class="me1">RenderWithShader</span><span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">maskReplacementShader</span>, <span class="st0">&#8220;RenderEffect&#8221;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="coMULTI">/**<br />
* Post Processing magic<br />
* @param&nbsp;source<br />
* @param&nbsp;destination<br />
*/</span><br />
<span class="kw2">function</span> OnRenderImage<span class="br0">&#40;</span>source:RenderTexture, destination:RenderTexture<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// We do nothing with the source render texture, the camera didn&#8217;t do anything to it anyway!</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// Magically composite the render textures together into the final render</span><br />
&nbsp; &nbsp;<span class="co1">// The shader used in the dimensionCompositeMaterial for compositing these textures is outside the scope of this post</span><br />
&nbsp; &nbsp;<span class="co1">// Will have a post about CG full screen post processing effects sometime in the future</span><br />
&nbsp; &nbsp;RenderTexture.<span class="me1">active</span> = destination;<br />
&nbsp; &nbsp;dimensionCompositeMaterial.<span class="me1">SetTexture</span><span class="br0">&#40;</span><span class="st0">&#8220;_DreamRender&#8221;</span>, dreamRT<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;dimensionCompositeMaterial.<span class="me1">SetTexture</span><span class="br0">&#40;</span><span class="st0">&#8220;_DeathRender&#8221;</span>, deathRT<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;dimensionCompositeMaterial.<span class="me1">SetTexture</span><span class="br0">&#40;</span><span class="st0">&#8220;_MaskRender&#8221;</span>, maskRT<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;GL.<span class="me1">PushMatrix</span> <span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;GL.<span class="me1">LoadOrtho</span> <span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw2">var</span> i:int = <span class="nu0">0</span>; i &lt; dimensionCompositeMaterial.<span class="me1">passCount</span>; i++<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;dimensionCompositeMaterial.<span class="me1">SetPass</span> <span class="br0">&#40;</span>i<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;DrawQuad<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;GL.<span class="me1">PopMatrix</span> <span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// Clean up</span><br />
&nbsp; &nbsp;CleanRenderTextures<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="coMULTI">/**<br />
* Cleanup if we get disabled<br />
*/</span><br />
<span class="kw2">function</span> OnDisable<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;CleanResources<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="coMULTI">/**<br />
* Camera that renders the replacement shaders<br />
* ppCamera getter<br />
* @return<br />
*/</span><br />
<span class="kw2">private</span> <span class="kw2">function</span> GetPPCamera<span class="br0">&#40;</span><span class="br0">&#41;</span>:Camera<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// Create the shader camera if it doesn&#8217;t exist yet</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>!ppCamera<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;ppCamera = <span class="kw2">new</span> GameObject<span class="br0">&#40;</span><span class="st0">&#8220;PPCamera&#8221;</span>, Camera<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;ppCamera.<span class="me1">camera</span>.<span class="me1">enabled</span> = <span class="kw2">false</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;ppCamera.<span class="me1">hideFlags</span> = HideFlags.<span class="me1">HideAndDontSave</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw1">return</span> ppCamera.<span class="me1">camera</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="coMULTI">/**<br />
* Cleanup all resources used for Post Processing<br />
*/</span><br />
<span class="kw2">private</span> <span class="kw2">function</span> CleanResources<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>ppCamera<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;DestroyImmediate<span class="br0">&#40;</span>ppCamera<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;CleanRenderTextures<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="coMULTI">/**<br />
* Cleanup Temporary RenderTexture resources<br />
*/</span><br />
<span class="kw2">private</span> <span class="kw2">function</span> CleanRenderTextures<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>deathRT != <span class="kw2">null</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;RenderTexture.<span class="me1">ReleaseTemporary</span><span class="br0">&#40;</span>deathRT<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;deathRT = <span class="kw2">null</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>dreamRT != <span class="kw2">null</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;RenderTexture.<span class="me1">ReleaseTemporary</span><span class="br0">&#40;</span>dreamRT<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;dreamRT = <span class="kw2">null</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>maskRT != <span class="kw2">null</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;RenderTexture.<span class="me1">ReleaseTemporary</span><span class="br0">&#40;</span>maskRT<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;maskRT = <span class="kw2">null</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<h2>Blush</h2>
<p><a href="http://technology.blurst.com/wp-content/uploads/2009/03/blushdistortion.png"><img src="http://technology.blurst.com/wp-content/uploads/2009/03/blushdistortion-300x174.png" alt="" title="Distortion and Glow in Blush" width="300" height="174" class="aligncenter size-medium wp-image-169" /></a></p>
<h3>Glow</h3>
<p>The Pro Standard Assets package that comes with Unity has a simple glow effect. Their implementation uses the alpha channel of the destination render texture to decide where to render glow. This limits us a couple ways. We can not have multicolored glow effects and we can not use the alpha channel for anything else. We decided to just bite the bullet and have a separate render texture for rendering glow. </p>
<p>Now we&#8217;ve freed up the destination render texture&#8217;s alpha channel for something else to use and we can have glow any color we like. Other than the additional memory needed for a 32bit render texture there&#8217;s a large disadvantage to doing it our way. Glow is no longer occluded by other geometry. A workaround for this is to have objects that you don&#8217;t want to glow render black to the glow render texture. Since glow is an additive pass, anything that is black will do nothing to the original image.</p>
<p>The Glow Replace Shader:</p>
<div class="codesnip-container" >
<div class="codesnip">Shader <span class="st0">&#8220;Blush/Glow Replace&#8221;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;SubShader <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;Tags <span class="br0">&#123;</span> <span class="st0">&#8220;RenderEffect&#8221;</span>=<span class="st0">&#8220;Glow&#8221;</span> <span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;Pass <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Fog <span class="br0">&#123;</span> Mode Off <span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Color <span class="br0">&#91;</span>_Glow_Color<span class="br0">&#93;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>For every object we wanted to glow we added two things to the object&#8217;s original shader.<br />
- Tag: &#8220;RenderEffect&#8221; = &#8220;Glow&#8221;<br />
- Property: _Glow_Color (&#8221;Glow Color&#8221;, COLOR) = (1,1,1,1)</p>
<h3>Distortion</h3>
<p>Distortion is handled in a few steps.<br />
1. Render the scene to a render texture.<br />
2. Render a 2 dimensional &#8220;normal&#8221; map to a render texture.<br />
3. Draw the scene&#8217;s render texture to the screen offsetting each texels&#8217; texture coordinate by the amount specified by the 2 dimensional &#8220;normal&#8221; map texture.</p>
<p>Blush used a constantly oscillating full screen normal map to distort the scene.  This distortion helped established an underwater feel.  We used replacement shaders to render directly to this normal map to further modify the distortion.  The artists used these shaders on particles to provide distortion effects on fast-moving tentacles, enemies, and other places.</p>
<p>The Particle Distortion Replace Shader:</p>
<div class="codesnip-container" >
<div class="codesnip">Shader <span class="st0">&#8220;Squiddy/Post Processing/Distortion Replace&#8221;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;Properties <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;_BumpMap <span class="br0">&#40;</span><span class="st0">&#8220;Bump (RGB)&#8221;</span>, 2D<span class="br0">&#41;</span> = <span class="st0">&#8220;bump&#8221;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;SubShader <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;Tags <span class="br0">&#123;</span> <span class="st0">&#8220;RenderEffect&#8221;</span>=<span class="st0">&#8220;Distort&#8221;</span> <span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;Pass <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Lighting Off<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;ZWrite Off<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Blend SrcAlpha OneMinusSrcAlpha<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;BindChannels <span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Bind <span class="st0">&#8220;Color&#8221;</span>, color<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Bind <span class="st0">&#8220;Vertex&#8221;</span>, vertex<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Bind <span class="st0">&#8220;Texcoord&#8221;</span>, texcoord<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SetTexture<span class="br0">&#91;</span>_BumpMap<span class="br0">&#93;</span> <span class="br0">&#123;</span>combine texture, texture * primary<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://technology.blurst.com/camera-render-with-shader/feed/</wfw:commentRss>
		</item>
		<item>
		<title>UnityDevelop, An Editor for Unity JavaScript</title>
		<link>http://technology.blurst.com/unitydevelop-javascript-editor/</link>
		<comments>http://technology.blurst.com/unitydevelop-javascript-editor/#comments</comments>
		<pubDate>Wed, 04 Feb 2009 07:21:04 +0000</pubDate>
		<dc:creator>Matthew Wegner</dc:creator>
		
		<category><![CDATA[Tools]]></category>

		<category><![CDATA[JavaScript]]></category>

		<category><![CDATA[UnityDevelop]]></category>

		<guid isPermaLink="false">http://technology.blurst.com/?p=125</guid>
		<description><![CDATA[Choosing a language for Unity development is a tricky thing.  There are a lot of great reasons to use C# (like its tool ecosystem), but other, just-as-great reasons to use JavaScript (like its less verbose and more accessible nature).  The Unity forums have endless debates about language choice.
The availability of Intellisense with Visual Studio is [...]]]></description>
			<content:encoded><![CDATA[<p>Choosing a language for Unity development is a tricky thing.  There are a lot of great reasons to use C# (like its tool ecosystem), but other, just-as-great reasons to use JavaScript (like its less verbose and more accessible nature).  The Unity forums have endless debates about language choice.</p>
<p>The availability of Intellisense with Visual Studio is a <em>huge</em> reason to use C#.  However, we liked the simplicity of Unity&#8217;s JavaScript, its similarity to Flash&#8217;s ActionScript, and some of its automagical features like compiler support for yield.  Ultimately we decided to use UnityScript here at Flashbang, and modified <a href="http://www.flashdevelop.org/community/">FlashDevelop</a> to provide an editor environment with code completion.  We use FlashDevelop for our Flash work already, so this made sense.</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="450" height="253" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://vimeo.com/moogaloop.swf?clip_id=3076296&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=1&amp;color=fcb100&amp;fullscreen=1" /><embed type="application/x-shockwave-flash" width="450" height="253" src="http://vimeo.com/moogaloop.swf?clip_id=3076296&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=1&amp;color=fcb100&amp;fullscreen=1" allowscriptaccess="always" allowfullscreen="true"></embed></object><br />
<a href="http://vimeo.com/3076296">Watch this in HD!</a></p>
<p>We&#8217;ve been using this tool for over a year now, internally.  It&#8217;s still a hack&#8211;so your mileage may vary&#8211;but we&#8217;ve been quite happy with it!  It&#8217;s taken us awhile to scrounge together a release, but here it is:</p>
<h3>Installing UnityDevelop</h3>
<p>1) Get Windows.  UnityDevelop is a modified FlashDevelop.  Unfortunately, FlashDevelop is Windows-only, which means you&#8217;ll need to find some way to run Windows alongside your Mac (unless you&#8217;re using Unity 2.5 by now, in which case you&#8217;re probably golden)!  We recommend using <a href="http://synergy2.sourceforge.net/">Synergy</a> to share a keyboard/mouse between both monitors, or virtualizing Windows entirely.</p>
<p>If you virtualize Windows, seriously look into a stripped-down version of XP.  You can use <a href="http://www.nliteos.com/">nLite</a> to do this yourself, or you can download a pre-made ISO if you don&#8217;t mind dipping into the shadier areas of the Internet.  This will reduce the memory footprint of XP tremendously (the popularity of Netbooks means there are endless tutorials and pre-made variants available).  If you run multiple monitors, you probably don&#8217;t want to run the Coherence/Unity feature, which can be slow with a ton of desktop real estate.  We run Parallels in windowed mode.</p>
<p>2) <a href="/examples/UnityDevelop.zip">Download UnityDevelop</a> (2.9 MB).</p>
<p>3) You probably want the <a href="http://technology.blurst.com/examples/UnityDevelop_Classes_2.6.zip">classes for Unity 2.6</a> (replace the files in your UnityDevelop\Classes directory).</p>
<p>4) Unzip, and copy the UnityDevelop directory to &#8220;C:\Program Files&#8221;.  There are some hard-coded paths in here; apologies if you organize your apps differently!</p>
<h3>Creating a Project</h3>
<p>UnityDevelop works best if you have your scripts in a single, scripts-only directory to begin with.  Open up UnityDevelop, and go to Project-&gt;Create Project.  We directly access our Unity project files via a network share; this is fine.</p>
<p>Select &#8220;Empty Project&#8221; as your template, give it a name, and browse to your scripts directory.  This will look like:<a href="http://technology.blurst.com/wp-content/uploads/2009/02/unitydevelop_create_project.png"><img class="aligncenter size-full wp-image-126" title="unitydevelop_create_project" src="http://technology.blurst.com/wp-content/uploads/2009/02/unitydevelop_create_project.png" alt="" width="486" height="373" /></a></p>
<p>A &#8220;project&#8221; is just a pointer to a directory.  If you add new files in Unity, they will show up here.  If not, click the refresh icon in the &#8220;Project Explorer&#8221; pane, or, in a worst-case scenario, just restart UnityDevelop.  In general it&#8217;s easiest to make new files in UnityDevelop directly.  The same restrictions apply here, though&#8211;make sure you do all of your script <em>renames</em> in Unity itself (if you rename outside of Unity it&#8217;ll look like one file was deleted and the other freshly created).</p>
<h3>Code Editing</h3>
<p>Now, edit away!  You&#8217;ll get autocompletion for built-in Unity scripts, as well as your own files.</p>
<p><a href="http://technology.blurst.com/wp-content/uploads/2009/02/unitydevelop_code.png"><img class="aligncenter size-full wp-image-128" title="unitydevelop_code" src="http://technology.blurst.com/wp-content/uploads/2009/02/unitydevelop_code.png" alt="" width="499" height="280" /></a></p>
<p>Hooray!</p>
<h3>Tips, Tricks, and Questions</h3>
<p><strong>Changing the Font</strong></p>
<p>Our default settings file uses Consolas, which is a great programming font.  If you want to change the font, close UnityDevelop, edit Settings\ScintillaNET.xml, and restart.</p>
<p><strong>Project-Wide Search</strong></p>
<p>CTRL-I is the shortcut to find in project.  It populates the search terms with your selection&#8211;you can easily select something, hit CTRL-I, enter, and see results immediately.  Nice!</p>
<p><strong>Goto Declaration</strong></p>
<p>F4 will go to the declaration of a function.  You&#8217;ll end up in the intrinsic class files for anything Unity-specific.</p>
<p><strong>Editing Into Two Directories</strong></p>
<p>If you get crafty with symlinks you can edit into your &#8220;Scripts&#8221; directory <em>and</em> the &#8220;Editor&#8221; directory.  On your Mac, create an empty folder, and then create symlinks into your project folder for both.  Create the UnityDevelop project file in this new directory.  If none of this makes sense, don&#8217;t worry (Pro Tip:  Use a network share to access your Mac; this won&#8217;t work with VMWare/Parallels built-in sharing).</p>
<p><strong>I Can&#8217;t It to Work.  Can You Help Me?</strong></p>
<p>Honestly, no, we can&#8217;t.  Sorry!  It took us forever just to release this, and all we had to do was zip up some files and write this post.  We don&#8217;t have time to support it, so you&#8217;re kind of on your own.</p>
<p><strong>I Added Some New Stuff.  Do You Guys Want It?<br />
</strong></p>
<p>Yes please!  It would be awesome to see this grow.  Just drop us an email! FlashDevelop 3 is almost done, too, if someone wants to take a stab and making the same hacks.</p>
<p><a href="/examples/UnityDevelop_dev.zip">Here is the source code</a>, by the way.</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.blurst.com/unitydevelop-javascript-editor/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A Cocoa-Based Frontend For Unity iPhone Applications</title>
		<link>http://technology.blurst.com/a-cocoa-based-frontend-for-unity-iphone-applications/</link>
		<comments>http://technology.blurst.com/a-cocoa-based-frontend-for-unity-iphone-applications/#comments</comments>
		<pubDate>Sat, 24 Jan 2009 00:44:38 +0000</pubDate>
		<dc:creator>Matt Mechtley</dc:creator>
		
		<category><![CDATA[Tutorials]]></category>

		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://technology.blurst.com/?p=103</guid>
		<description><![CDATA[I spent about 3 months at the end of 2008 knee-deep in Unity iPhone &#8212; first testing the beta and then working with the release version. I spent tons of time just playing with it, learning its capabilities and how to optimize for it. That&#8217;s a whole other post though, which I&#8217;ll get to sometime [...]]]></description>
			<content:encoded><![CDATA[<p>I spent about 3 months at the end of 2008 knee-deep in Unity iPhone &#8212; first testing the beta and then working with the release version. I spent tons of time just playing with it, learning its capabilities and how to optimize for it. That&#8217;s a whole other post though, which I&#8217;ll get to sometime in the future. For now I want to talk about the Cocoa frontend that I developed for all our Unity iPhone games.</p>
<h3>Why use a Cocoa frontend?</h3>
<p>We wanted a way to allow players to login using their Blurst user id in our iPhone games, but Unity iPhone doesn&#8217;t yet support the iPhone keyboard. We could have simply used the device id to let users pair their account via the webpage, but I wanted a more elegant solution. Furthermore, after working on iSplume (which we coded entirely using Objective-C), I found that I could make menus much faster in Apple&#8217;s Interface Builder than in UnityGUI. Adam and I planned a fair number of menus in Rebolt, so I wanted a way to make them in Cocoa/Interface Builder.</p>
<p>So I set a goal: <strong>Make an easily extensible Cocoa frontend for Unity iPhone that supports Blurst logins and supports any menus we might want.</strong> It should work for any project we add it to, so we don&#8217;t have to do tons of custom code for every game. Further, it should require changing as little of ReJ&#8217;s  existing Objective-C AppController code as possible, in the event that it changed in a later build. Finally, I wanted an easy way to add my additional files to the XCode project once I created a build. This is particularly important because, to maintain <strong>rapid iteration times</strong>, there must be a minimal amount we have to do in XCode between creating a build and installing that build on the phone.</p>
<h3>Basic Architecture</h3>
<p>The basic idea is that we write our own UIApplication delegate to replace AppController, and then <strong>forward events</strong> like applicationWillTerminate: to the existing AppController once we&#8217;ve started the Unity content. We&#8217;ll also keep a loop running in the background once the Unity content is created that checks the PlayerPrefs file. We&#8217;ll use this to get back to the menus from within the Unity content. Finally, we&#8217;ll organize the Cocoa content in such a way that we can easily add it to the XCode project that Unity iPhone spits out. We&#8217;ll use a PostprocessBuildPlayer Perl script to accomplish this.</p>
<h3>Writing our own UIApplication delegate</h3>
<p>Our UIApplication delegate needs to do a few different things. First, we want to handle the usual application event callbacks &#8212; applicationDidFinishLaunching:, applicationWillResignActive:, etc. Unless we&#8217;re particularly interested in some event, or we&#8217;re doing something more complex than just menus, we will just forward most of these messages to ReJ&#8217;s AppController. The notable exception is applicationDidFinishLaunching:, which we will use to launch our frontend and add a scheduled timer to the app&#8217;s run loop that will listen for menu return requests.</p>
<p>We&#8217;ll also want a few functions for switching between Unity and Cocoa content. We&#8217;ll create launchFrontend, cleanupFrontend, and launchUnity methods to handle switching content. We&#8217;ll also create a checkForReturnToMenu: method that our scheduled timer will call regularly. This will read the PlayerPrefs file and, if it finds a specific key, hide the Unity content and re-launch our frontend.</p>
<p>Here&#8217;s a zipped copy of the default Flashbang UIApplication delegate files &#8212; download it and follow along as I describe the various sections.<br />
<a href="http://technology.blurst.com/wp-content/uploads/2009/01/flashbangfrontend.zip">flashbangfrontend.zip</a></p>
<p>First, we&#8217;ll take a look at the header file. Note that we explicitly adopt the UIApplicationDelegate protocol. We also keep references to the application window and the Unity AppController.</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="co2">#import &quot;FBGameSettings.h&quot;</span><br />
<span class="co2">#import &quot;FBScene.h&quot;</span><br />
<span class="co2">#import &quot;FBSceneManager.h&quot;</span><br />
<span class="co2">#import &quot;FBSceneSetup.h&quot;</span><br />
<span class="co2">#import &quot;AppController.h&quot;</span></p>
<p><span class="co1">// Integer tag that we use to distinguish the Unity view</span><br />
<span class="co2">#define UNITY_VIEW_TAG 1</span></p>
<p><span class="kw4">@interface</span> FBFrontendController : <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/nsobject.html"><span class="kw5">NSObject</span></a><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// A local reference to the app&#8217;s window</span><br />
&nbsp; &nbsp;UIWindow *window;<br />
&nbsp; &nbsp;<span class="co1">// ReJ&#8217;s original AppController that runs Unity</span><br />
&nbsp; &nbsp;AppController *unityController;<br />
<span class="br0">&#125;</span></p>
<p>- <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>checkForReturnToMenu:<span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/nstimer.html"><span class="kw5">NSTimer</span></a> *<span class="br0">&#41;</span>timer;<br />
- <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>launchFrontend;<br />
- <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>launchUnity;<br />
- <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>cleanupFrontend;</p>
<p><span class="kw4">@end</span></div>
</div>
<p>The specific details of the headers I&#8217;m importing are mostly unimportant. FBGameSettings.h is just some game-specific #defines (version number, etc). FBScene is a subclass of UIViewController and represents a generic menu scene. Specific scenes needed by an individual game are subclasses of this. FBSceneManager keeps a hash table of all scenes and handles transition animations between them. We&#8217;ll take a closer look at FBSceneSetup.h later.</p>
<h3>Starting the Application</h3>
<p>Now let&#8217;s take a look at the implementation of FBFrontendController. We&#8217;ll look at the applicationDidFinishLaunching: method first.</p>
<div class="codesnip-container" >
<div class="codesnip">- <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>applicationDidFinishLaunching:<span class="br0">&#40;</span>UIApplication *<span class="br0">&#41;</span>application<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="br0">&#91;</span>application setStatusBarHidden:YES animated:NO<span class="br0">&#93;</span>;</p>
<p>&nbsp; &nbsp;<span class="co1">// Clear keys that signal transitions back and forth from </span><br />
&nbsp; &nbsp;<span class="co1">// Unity, just in case</span><br />
&nbsp; &nbsp;<span class="br0">&#91;</span>FBPlayerPrefs deleteKey:@<span class="st0">&#8220;_start_cocoa&#8221;</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#91;</span>FBPlayerPrefs deleteKey:@<span class="st0">&#8220;_start_unity&#8221;</span><span class="br0">&#93;</span>;</p>
<p>&nbsp; &nbsp;<span class="co1">// reset blurst logged in status</span><br />
&nbsp; &nbsp;<span class="br0">&#91;</span>FBPlayerPrefs deleteKey:@<span class="st0">&#8220;blurst_online&#8221;</span><span class="br0">&#93;</span>;</p>
<p>&nbsp; &nbsp;<span class="co1">// Start listening for signal to return to menus</span><br />
&nbsp; &nbsp;<span class="br0">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/nstimer.html"><span class="kw5">NSTimer</span></a> scheduledTimerWithTimeInterval:<span class="nu0">1</span>.<span class="nu0">0</span> target:self<br />
&nbsp; &nbsp;&nbsp; &nbsp;selector:<span class="kw4">@selector</span><span class="br0">&#40;</span>checkForReturnToMenu:<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;userInfo:<span class="kw2">nil</span> repeats:YES<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#91;</span>self launchFrontend<span class="br0">&#93;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>Here, we first delete the two PlayerPrefs keys we&#8217;ll use to communicate that we want to swap between Cocoa and Unity &#8212; <strong>_start_cocoa and _start_unity</strong>. This ensures that we know their initial states. Note: Unity iPhone stores PlayerPrefs using NSUserDefaults. FBPlayerPrefs is just a wrapper for NSUserDefaults that behaves like the PlayerPrefs class in Unity. We then begin a timer that runs our checkForReturnToMenu: method once per second. A shorter delay here means faster responsiveness for opening the frontend from within Unity, while a longer delay will give better performance. Finally, we run our launchFrontend method. Here&#8217;s the checkForReturnToMenu: method.</p>
<div class="codesnip-container" >
<div class="codesnip">- <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>checkForReturnToMenu:<span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_classic/Classes/nstimer.html"><span class="kw5">NSTimer</span></a> *<span class="br0">&#41;</span>timer<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span><span class="br0">&#91;</span>FBPlayerPrefs getInt:@<span class="st0">&#8220;_start_cocoa&#8221;</span> orDefault:<span class="nu0">0</span><span class="br0">&#93;</span> == <span class="nu0">1</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#91;</span>FBPlayerPrefs deleteKey:@<span class="st0">&#8220;_start_cocoa&#8221;</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#91;</span>self launchFrontend<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>This simply checks for the proper key in PlayerPrefs and then launches the frontend if it finds it.</p>
<h3>Launching Our Frontend</h3>
<p>Here&#8217;s the launchFrontend method, which we call whenever we want to display our Interface Builder-constructed menu system:</p>
<div class="codesnip-container" >
<div class="codesnip">- <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>launchFrontend<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// re-sync the PlayerPrefs file, in case we&#8217;ve been in Unity</span><br />
&nbsp; &nbsp;<span class="br0">&#91;</span>FBPlayerPrefs readPrefsFile<span class="br0">&#93;</span>;</p>
<p>&nbsp; &nbsp;<span class="co1">// Create the window if we don&#8217;t already have one</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span><span class="br0">&#91;</span>UIApplication sharedApplication<span class="br0">&#93;</span>.keyWindow == <span class="kw2">nil</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;window = <span class="br0">&#91;</span><span class="br0">&#91;</span>UIWindow alloc<span class="br0">&#93;</span> initWithFrame:<span class="br0">&#91;</span><span class="br0">&#91;</span>UIScreen <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;mainScreen<span class="br0">&#93;</span> bounds<span class="br0">&#93;</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#91;</span>window makeKeyAndVisible<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp;<span class="co1">// Check to see if any views are exclusive/multitouch (ie find</span><br />
&nbsp; &nbsp;<span class="co1">// the Unity EAGLView). Temporarily disable it, and tag it </span><br />
&nbsp; &nbsp;<span class="co1">// so we can find it later</span><br />
&nbsp; &nbsp;<span class="kw1">for</span><span class="br0">&#40;</span>UIView *v in window.subviews<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>v.exclusiveTouch &amp;&amp; v.multipleTouchEnabled<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;v.exclusiveTouch = NO;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;v.multipleTouchEnabled = NO;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;v.tag = UNITY_VIEW_TAG;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;v.hidden = YES;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp;<span class="co1">// load menu scenes</span><br />
&nbsp; &nbsp;LoadScenesInWindow<span class="br0">&#40;</span>window<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp;<span class="co1">// start the first scene</span><br />
&nbsp; &nbsp;<span class="br0">&#91;</span>FBSceneManager startScene:FIRST_SCENE<br />
&nbsp; &nbsp;&nbsp; &nbsp;withTransition:FBSceneTransitionNone<span class="br0">&#93;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>Here we create the application window if it doesn&#8217;t exist, we disable interaction with the Unity view if it&#8217;s present, then we load our custom views in the window. Finally, we start our first scene using the scene manager. LoadScenesInWindow is a function defined in FBSceneSetup.h &#8212; we&#8217;ll take a quick look at that.</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="co2">#define FIRST_SCENE @&quot;Title&quot;&nbsp; // The string key for our first scene</span></p>
<p><span class="co1">// load in game-specific scenes and define function to load them</span><br />
<span class="co2">#import &quot;SceneCredits.h&quot;</span><br />
<span class="co2">#import &quot;SceneOptions.h&quot;</span><br />
<span class="co2">#import &quot;SceneTitle.h&quot;</span><br />
<span class="co2">#import &quot;SceneGame.h&quot;</span></p>
<p><span class="kw4">void</span> LoadScenesInWindow<span class="br0">&#40;</span>UIWindow* window<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="br0">&#91;</span>window addSubview:<span class="br0">&#91;</span><span class="br0">&#91;</span><span class="br0">&#91;</span>SceneCredits alloc<span class="br0">&#93;</span> init<span class="br0">&#93;</span> view<span class="br0">&#93;</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#91;</span>window addSubview:<span class="br0">&#91;</span><span class="br0">&#91;</span><span class="br0">&#91;</span>SceneOptions alloc<span class="br0">&#93;</span> init<span class="br0">&#93;</span> view<span class="br0">&#93;</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#91;</span>window addSubview:<span class="br0">&#91;</span><span class="br0">&#91;</span><span class="br0">&#91;</span>SceneTitle alloc<span class="br0">&#93;</span> init<span class="br0">&#93;</span> view<span class="br0">&#93;</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#91;</span>window addSubview:<span class="br0">&#91;</span><span class="br0">&#91;</span><span class="br0">&#91;</span>SceneGame alloc<span class="br0">&#93;</span> init<span class="br0">&#93;</span> view<span class="br0">&#93;</span><span class="br0">&#93;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>Recall that each SceneXXXX is a subclass of FBScene, which is a subclass of UIViewController. The init method of each SceneXXXX first calls initWithNibName: with the name of each scene&#8217;s Interface Builder xib, then adds the scene to the scene manager with an appropriate string-based key. The LoadScenesInWindow function thus initializes each view controller and adds its view to the window. The idea behind this architecture is that <strong>for any given project, we only have to edit FBSceneSetup.h, and then create the appropriate SceneXXXX subclasses to manage each of our scene xibs</strong>. That is, FBSceneController will be the same for every project.</p>
<h3>Launching Unity</h3>
<p>Now we&#8217;ll take a look at how we launch the Unity content.</p>
<div class="codesnip-container" >
<div class="codesnip">- <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>launchUnity<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="br0">&#91;</span>self cleanupFrontend<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<span class="co1">// Tell Unity loading scene to stop holding</span><br />
&nbsp; &nbsp;<span class="br0">&#91;</span>FBPlayerPrefs setInt:<span class="nu0">1</span> withKey:@<span class="st0">&#8220;_start_unity&#8221;</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#91;</span>FBPlayerPrefs saveAndUnload<span class="br0">&#93;</span>;</p>
<p>&nbsp; &nbsp;<span class="co1">// If we&#8217;ve not yet started the Unity content, run its startup</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>unityController == <span class="kw2">nil</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;unityController = <span class="br0">&#91;</span><span class="br0">&#91;</span>AppController alloc<span class="br0">&#93;</span> init<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#91;</span>unityController applicationDidFinishLaunching:<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#91;</span>UIApplication sharedApplication<span class="br0">&#93;</span><span class="br0">&#93;</span>;</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// Set our window to the one created by ReJ&#8217;s AppController,</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// for any future use</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;window = unityController-&gt;_window;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp;<span class="co1">// If we&#8217;ve already got Unity content running, show it and</span><br />
&nbsp; &nbsp;<span class="co1">// return its Exclusive/multitouch status</span><br />
&nbsp; &nbsp;<span class="kw1">else</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">for</span><span class="br0">&#40;</span>UIView *v in window.subviews<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>v.tag == UNITY_VIEW_TAG<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;v.exclusiveTouch = YES;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;v.multipleTouchEnabled = YES;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;v.hidden = NO;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#91;</span>window bringSubviewToFront:v<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>We start out by cleaning up the frontend (which just tells the scene manager to remove its views from the window and releases them). We then set the _start_unity PlayerPrefs key, so that our loaded Unity content will know we want it to start executing. After that, there are two possible codepaths. The first time we call the method, it will call AppController&#8217;s applicationDidFinishLaunching: method, and then point our local window reference to the one created by AppController. Once the Unity content is initialized (if we&#8217;ve come back to the menu and then want to return to Unity), we find our Unity view by the tag we set in launchFrontend, return it to the front, and re-enable interaction with it.</p>
<p>We&#8217;ll typically want to run this method in response to a button press in some view. Here&#8217;s an example use:</p>
<div class="codesnip-container" >
<div class="codesnip">- <span class="br0">&#40;</span>IBAction<span class="br0">&#41;</span>playButtonPressed:<span class="br0">&#40;</span><span class="kw4">id</span><span class="br0">&#41;</span>sender<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="br0">&#91;</span><span class="br0">&#40;</span>FBFrontendController *<span class="br0">&#41;</span><span class="br0">&#91;</span>UIApplication<br />
&nbsp; &nbsp;&nbsp; &nbsp;sharedApplication<span class="br0">&#93;</span>.delegate launchUnity<span class="br0">&#93;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<h3>Using the Frontend From Unity</h3>
<p>To get back to the frontend from Unity, we just need to set the _start_cocoa PlayerPrefs key. Since the Unity content will continue running in the background, <strong>you&#8217;ll also want to pause your game and have a loop continue to check for the _start_unity PlayerPrefs key</strong>.</p>
<h3>Putting It All Together &#8212; Project Organization and PostprocessBuildPlayer</h3>
<p>So this frontend stuff is all well and good, but it would be a royal pain in the ass if we had to copy the files into the project manually and edit ReJ&#8217;s files every time we made a build. But, as usual, it&#8217;s Perl to the rescue!</p>
<p>We&#8217;ll first create a directory inside our project that will contain all of our frontend files. We&#8217;ll set it up so that we can also replace the application icon and splash screen in the same pass. First, create an &#8220;XCode&#8221; directory within the Unity project. Any files that you want overwritten in the default XCode project should be in the same locations with the same names. So for instance, we&#8217;ll add Icon.png and Default.png to the root of the XCode directory. <strong>Put anything that you&#8217;re <em>adding</em> to the project (all the frontend files) into a separate &#8220;Frontend&#8221; sub-directory.</strong> So your tree should end up something like this:</p>
<p><a href="http://technology.blurst.com/wp-content/uploads/2009/01/tree.png"><img class="aligncenter size-medium wp-image-105" title="XCode Directory Tree" src="http://technology.blurst.com/wp-content/uploads/2009/01/tree-277x300.png" alt="XCode Directory Tree" width="277" height="300" /></a></p>
<p>Now we&#8217;ll take a look at the PostprocessBuildPlayer script. If you aren&#8217;t familiar with it, check the <a href="http://unity3d.com/support/documentation/Manual/Build%20Player%20Pipeline.html">Build Player Pipeline</a> section of the Unity Manual. Here&#8217;s my script, written in Perl:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="co1">#!/usr/bin/perl</span></p>
<p><span class="co1">#################################################################</span><br />
<span class="co1"># Build Player postprocessor for Unity iPhone projects. Injects #</span><br />
<span class="co1"># FBS Frontend into generated XCode project&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;#</span><br />
<span class="co1">#################################################################</span></p>
<p><span class="co1"># Path for assets that will get added to the XCode project.</span><br />
<span class="co1"># Relative to the project root directory.</span><br />
<span class="re0">$iPhoneAssetPath</span> = <span class="st0">&#8220;./Assets/XCode/&#8221;</span>;<br />
<span class="re0">$toPath</span> = <span class="re0">$ARGV</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>;</p>
<p><span class="co1">##########################################################</span><br />
<span class="co1"># Copy iPhone assets from Unity project to XCode project #</span><br />
<span class="co1">##########################################################</span></p>
<p><a href="http://www.perldoc.com/perl5.6/pod/func/opendir.html"><span class="kw3">opendir</span></a><span class="br0">&#40;</span>XCODEDIR, <span class="re0">$iPhoneAssetPath</span><span class="br0">&#41;</span> || <a href="http://www.perldoc.com/perl5.6/pod/func/die.html"><span class="kw3">die</span></a><span class="br0">&#40;</span><span class="st0">&#8220;Cannot open directory $iPhoneAssetPath&#8221;</span><span class="br0">&#41;</span>;<br />
<span class="re0">@files</span> = <a href="http://www.perldoc.com/perl5.6/pod/func/readdir.html"><span class="kw3">readdir</span></a><span class="br0">&#40;</span>XCODEDIR<span class="br0">&#41;</span>;<br />
<a href="http://www.perldoc.com/perl5.6/pod/func/closedir.html"><span class="kw3">closedir</span></a><span class="br0">&#40;</span>XCODEDIR<span class="br0">&#41;</span>;</p>
<p><span class="co1"># copy files from Unity iPhoneAssetPath to the generated XCode project</span><br />
<span class="kw1">foreach</span> <span class="re0">$file</span> <span class="br0">&#40;</span><span class="re0">@files</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1"># kind of a lazy hack</span><br />
&nbsp; &nbsp;<span class="kw1">unless</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="re0">$file</span> eq <span class="st0">&#8220;.&#8221;</span><span class="br0">&#41;</span> || <span class="br0">&#40;</span><span class="re0">$file</span> eq <span class="st0">&#8220;..&#8221;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">#`echo $file &gt; log.txt`;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="re0">$fromPath</span> = <span class="re0">$iPhoneAssetPath</span>.<span class="re0">$file</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;`cp -R \<span class="st0">&#8216;$fromPath<span class="es0">\&#8217;</span> <span class="es0">\&#8217;</span>$toPath<span class="es0">\&#8217;</span>`;<br />
&nbsp; &nbsp;}<br />
}</p>
<p>################################################################<br />
# Change default UIApplicationDelegate to FBFrontendController #<br />
################################################################</p>
<p>$omPath = $toPath.&quot;/Classes/main.mm&quot;;<br />
$nmPath = $toPath.&quot;/Classes/main.mm.tmp&quot;;</p>
<p>open OLDMAIN, &quot;&lt;&quot;, $omPath or die(&quot;Cannot open main.mm&quot;);<br />
open NEWMAIN, &quot;&gt;&quot;, $nmPath or die(&quot;Cannot create new main.mm&quot;);</p>
<p>while(&lt;OLDMAIN&gt;)<br />
{<br />
&nbsp; &nbsp;$_ =~ s/<span class="es0">\&#8221;</span>AppController<span class="es0">\&#8221;</span>/<span class="es0">\&#8221;</span>FBFrontendController<span class="es0">\&#8221;</span>/;<br />
&nbsp; &nbsp;print NEWMAIN $_;<br />
}</p>
<p>close OLDMAIN;<br />
close NEWMAIN;</p>
<p>`mv &quot;$nmPath&quot; &quot;$omPath<span class="es0">\&#8217;</span>`;</p>
<p>#################################################<br />
# Make _window variable in AppController public #<br />
#################################################</p>
<p>$oacPath = $toPath.&quot;/Classes/AppController.h&quot;;<br />
$nacPath = $toPath.&quot;/Classes/AppController.h.tmp&quot;;</p>
<p>open OLDAC, &quot;&lt;&quot;, $oacPath or die(&quot;Cannot open AppController.h&quot;);<br />
open NEWAC, &quot;&gt;&quot;, $nacPath or die(&quot;Cannot create new AppController.h&quot;);</p>
<p>while(&lt;OLDAC&gt;)<br />
{<br />
&nbsp; &nbsp;if($_ =~ m/UIWindow.*window/)<br />
&nbsp; &nbsp;{<br />
&nbsp; &nbsp;&nbsp; &nbsp;print NEWAC &quot;<span class="es0">\t</span><span class="es0">\@</span>public<span class="es0">\n</span>&quot;;<br />
&nbsp; &nbsp;}<br />
&nbsp; &nbsp;print NEWAC $_;<br />
}</p>
<p>close OLDAC;<br />
close NEWAC;</p>
<p>`mv &quot;$nacPath&quot; &quot;$oacPath&quot;`; </span></div>
</div>
<p>As you can see, this script does three things &#8212; copy all the files from our XCode directory to the built XCode project, change the UIApplicationDelegate in main.mm to FBFrontendController, and make the _window variable of AppController public. <strong>So we&#8217;ve managed to implement our own frontend by changing only two lines of existing code!</strong></p>
<h3>Building the Project</h3>
<p>I know of no way to add files to an XCode project via the command line, so you will still have to manually add the files to the project after building.  However, because of the way that we&#8217;ve organized the project, this will be relatively simple. It does mean, however, that <strong>&#8220;Build and Run&#8221; will no longer work as a one-click solution</strong>.</p>
<p>Build the project in Unity and open the generated project in XCode. Select Project -&gt; Add To Project&#8230; (Cmd + Option + A), and select &#8220;Frontend&#8221; directory. In the next dialog, choose to &#8220;Recursively create groups for added folders:</p>
<p><a href="http://technology.blurst.com/wp-content/uploads/2009/01/dialog.png"><img class="aligncenter size-medium wp-image-106" title="Add files to project dialog" src="http://technology.blurst.com/wp-content/uploads/2009/01/dialog-300x280.png" alt="Add files to project dialog" width="300" height="280" /></a></p>
<p>That&#8217;s it! You&#8217;ll now have the references needed to run your custom frontend before the Unity content &#8212; simply build and run in XCode!</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.blurst.com/a-cocoa-based-frontend-for-unity-iphone-applications/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Unity Basics:  An Introduction</title>
		<link>http://technology.blurst.com/unity-basics-overview/</link>
		<comments>http://technology.blurst.com/unity-basics-overview/#comments</comments>
		<pubDate>Fri, 26 Dec 2008 21:42:40 +0000</pubDate>
		<dc:creator>Matthew Wegner</dc:creator>
		
		<category><![CDATA[Tutorials]]></category>

		<category><![CDATA[Unity Basics]]></category>

		<guid isPermaLink="false">http://technology.blurst.com/?p=75</guid>
		<description><![CDATA[Unity 2.5&#8217;s release is finally on the horizon, which means Windows editor!  In addition to some great new workflow and editor features, 2.5 will also usher in a wave of Windows users.  There is a lot to learn about Unity, when you first encounter it, so we&#8217;re going to do a series of Unity Basics [...]]]></description>
			<content:encoded><![CDATA[<p>Unity 2.5&#8217;s release is finally on the horizon, which means Windows editor!  In addition to some great new workflow and editor features, 2.5 will also usher in a wave of Windows users.  There is a lot to learn about Unity, when you first encounter it, so we&#8217;re going to do a series of Unity Basics posts, with an introduction to some of the core concepts.  This first post answer the question:</p>
<h2>What is Unity?</h2>
<p>Unity&#8217;s scope makes concise definition difficult.  Unity is a lot of things, and it&#8217;s used differently by different disciplines, but here&#8217;s one breakdown.  Unity is:</p>
<h3>An Integrated Editor</h3>
<p>Unity provides an editing environment where you organize your project assets, create game objects, add scripts to these objects, and organize objects and assets into levels.  Most importantly, Unity provides a &#8220;game&#8221; view for your content.  You can hit play and interact with your content while you watch values, change settings, and even recompile scripts.</p>
<p><a href="http://technology.blurst.com/wp-content/uploads/2008/12/mcs-development-tweet.jpg"><img class="aligncenter size-medium wp-image-77" title="Unity Editing Environment" src="http://technology.blurst.com/wp-content/uploads/2008/12/mcs-development-tweet-300x187.jpg" alt="" width="300" height="187" /></a></p>
<p>The IDE is largely stateless, in that there is little distinction between creating your levels and playing them.  For example, the editor remains functionality identical whether your content is stopped or currently playing.  This is hugely useful, because while your content is playing you can hit pause and then move things, create new objects, add scripts, and whatever else you need to do to test gameplay or chase down bugs.</p>
<p>Different team members and disciplines use the editor differently.  Here at Flashbang artists use the editor to smoke test new asset imports, arrange assets into levels, and tweak textures and other visuals.  A programmer may focus more on watching values and tweaking numbers.  A unified interface helps us tremendously; we don&#8217;t have people using different tools with different interfaces and workflow conventions.</p>
<h3>A Component Architecture Paradigm</h3>
<p>Unity utilizes a component-based architecture.  You <em>could</em> ignore this in creating your game logic, but you will suffer without a clear understanding of Unity&#8217;s design.  In Unity, every object in your scene is a GameObject.  An arbitrary number of Components are attached to GameObjects to define their behavior.</p>
<p><a href="http://technology.blurst.com/wp-content/uploads/2008/12/crate_setup1.png"><img class="alignright size-medium wp-image-79" title="Crate Setup" src="http://technology.blurst.com/wp-content/uploads/2008/12/crate_setup1-160x300.png" alt="" width="160" height="300" /></a></p>
<p>For example, a physical crate might be:</p>
<ul>
<li><strong>GameObject</strong><br />
(name, layer, tags)</p>
<ul>
<li><strong>Transform</strong><br />
(position, rotation, scale, parent)</li>
<li><strong>Mesh Renderer</strong><br />
(actually draws the object)</li>
<li><strong>Box Collider</strong><br />
(define collision volume)</li>
<li><strong>Rigidbody</strong><br />
(movable physics object)</li>
</ul>
</li>
</ul>
<p>Here&#8217;s the key:  <strong>When you create a script, you create a component</strong>. For example, you could create a Jump.js script to make your cube jump when you press a key, like:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">var</span> strength:float = <span class="nu0">30</span>.<span class="nu0">0</span>;</p>
<p><span class="kw2">function</span> Update<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>Input.<span class="me1">GetKeyDown</span><span class="br0">&#40;</span><span class="st0">&#8220;space&#8221;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;rigidbody.<span class="me1">AddForce</span><span class="br0">&#40;</span>Vector3.<span class="me1">up</span> * strength<span class="br0">&#41;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>JavaScript hides some of the details, but what&#8217;s happening here is you&#8217;ve created a new <em>Jump</em> Component.  Your script implicitly inherits from <a href="http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.html">MonoBehaviour</a>, which inherits from Behaviour, which inherits from Component.  <strong>You now have a new component</strong>, which you can easily add to your crate!</p>
<p>Note:  We use JavaScript at Flashbang, for a variety of reasons, but the steps are quite similar in C#.  The only real different, aside from syntax, is that you need to explicitly define the inheritance:</p>
<div class="codesnip-container" >
<div class="codesnip">using UnityEngine;<br />
using System.<span class="me1">Collections</span>;</p>
<p>public class Jump : MonoBehaviour<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;public <span class="kw4">float</span> strength = <span class="nu0">30</span>.0f;</p>
<p>&nbsp; &nbsp;<span class="kw4">void</span> Update <span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>Input.<span class="me1">GetKeyDown</span><span class="br0">&#40;</span><span class="st0">&#8220;space&#8221;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;rigidbody.<span class="me1">AddForce</span><span class="br0">&#40;</span>Vector3.<span class="me1">up</span> * strength<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<h3>A Game Engine</h3>
<p>Unity is a fully-featured game engine.  It includes and exposes many systems needed for game creation, such as:</p>
<ul>
<li><strong>Graphics </strong><strong>Engine</strong><br />
Unity&#8217;s graphic engine includes a shader language, ShaderLab, which wraps Cg and GLSL shaders with additional engine semantics.</li>
<li><strong>Physics Engine</strong><br />
Unity uses NVIDIA PhysX for their physics engine, with editor and API integration (you set up collision volumes, joints, and things by adding components to your GameObjectsin the editor, and script physics with things like <a href="http://unity3d.com/support/documentation/ScriptReference/Rigidbody.AddForce.html">Rigidbody.AddForce()</a> and <a href="http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.OnCollisionEnter.html">MonoBehaviour.OnCollisionEnter()</a> callbacks).</li>
<li><strong>Audio Engine</strong><br />
Unity has a positional audio system.  You can play sounds in 3D space, or &#8220;2D&#8221; stereo sounds.</li>
<li><strong>Animation System</strong><br />
Unity includes an animation system, including support for animation layers, blending, additive animations and mixing, and real-time vertex/bone reassignment.</li>
</ul>
<p>There are quite a few other out-of-the-box systems there to help you, too, like particle systems, networking, UnityGUI, and so on.</p>
<h3>A Scripting Platform</h3>
<p><a href="http://mono-project.com/Main_Page"><img class="alignleft size-full wp-image-88" title="Mono Logo" src="http://technology.blurst.com/wp-content/uploads/2008/12/mono_logo.png" alt="" width="100" height="120" /></a>Unity embeds Mono to power its scripting environment.  You can script in C#, JavaScript, or Boo (a Python variant).  Mono itself is an open-source version of the .NET development environment.  Note that this <em>doesn&#8217;t</em> mean that Unity requires .NET.  Mono is totally distinct from Microsoft&#8217;s .NET, and Unity totally embeds Mono.</p>
<p>It&#8217;s also worth noting that Unity&#8217;s use of Mono goes above and beyond the compiler and common language runtime.  You also get the full .NET namespace, which means a huge amount of classes are available to you out of the box:  XML parsing, cryptography, sockets, and more.</p>
<p>As I mentioned earlier, Flashbang uses JavaScript.  Unity&#8217;s JavaScript isn&#8217;t very similar to the JavaScript language found in web browers.  It&#8217;s about as similar to web JavaScript as Flash&#8217;s ActionScript, which is to say not very similar at all.  There are a number of advantages to using UnityScript, although there are far fewer tools available (we use a custom-created hack of FlashDevelop).  With the advant of the Windows release, I imagine many newcomers will choose C# and Visual Studio.  Lucas Meijer <a href="http://lucasmeijer.com/posts/on-how-cool-mono-net-and-c-are/">makes a very compelling case</a> for C# scripting over at his Unity blog.</p>
<h3>A Scripting API</h3>
<p>Your Mono-powered scripts have full access to Unity&#8217;s engine through Unity&#8217;s scripting API.  They&#8217;ve exposed the entirety of the engine, which means that you can do pretty much anything.  High level stuff is quite easy and simple, but you can dig all the way down to doing mesh generation or direct OpenGL calls if you&#8217;d like (which work on DirectX, thanks to <a href="http://aras-p.info/blog/">Aras&#8217;</a> genius).</p>
<p><a href="http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.html">MonoBehaviour</a>, the parent class for your scripts, provides a number of convenience members.  Things are usually quite straightfoward.  For example:</p>
<ul>
<li>transform.position = Vector3.zero;</li>
<li>rigidbody.AddForce(Vector3.up * 10);</li>
<li>renderer.enabled = false;</li>
<li>particleEmitter.Emit(10);</li>
</ul>
<p>There are a number of callbacks provided for game logic purposes:</p>
<ul>
<li>Start()</li>
<li>Update()</li>
<li>OnCollisionEnter()</li>
<li>OnMouseDown()</li>
</ul>
<p>The scripting environment supports <a href="http://en.wikipedia.org/wiki/Coroutine">coroutines</a>, which are magically useful for all kinds of things.  Want to destroy an object 3 seconds after it was hit with something?</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">function</span> OnCollisionEnter<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// do something</span><br />
&nbsp; &nbsp;yield WaitForSeconds<span class="br0">&#40;</span><span class="nu0">3</span>.<span class="nu0">0</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;Destroy<span class="br0">&#40;</span>gameObject<span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>In addition to scripting your game at runtime, Unity provides a powerful editor API to create custom tools, windows, and shortcuts to expedite your workflow in the editor itself.  With Unity 2.5 the entire editor itself has been rewritten with the Unity API (which means you should be able to do practically anything they have).</p>
<h3>More to Learn!</h3>
<p>As you can see, Unity is quite broad.  This article should provide a good starting point for its top-level features, but even this overview hasn&#8217;t covered the whole of the software.</p>
<p>We&#8217;ll dive into more Unity features in depth in future Unity Basics articles.  We didn&#8217;t talk much about the Inspector (and how variables are serialized in Unity), or asset importing, or any number of other features.  What would you guys like to focus on?  Use the comments below to let us know!</p>
]]></content:encoded>
			<wfw:commentRss>http://technology.blurst.com/unity-basics-overview/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A Useful Messaging System</title>
		<link>http://technology.blurst.com/unityscript-messaging-system/</link>
		<comments>http://technology.blurst.com/unityscript-messaging-system/#comments</comments>
		<pubDate>Sun, 09 Nov 2008 20:11:51 +0000</pubDate>
		<dc:creator>Matthew Wegner</dc:creator>
		
		<category><![CDATA[Scripts]]></category>

		<category><![CDATA[Framework]]></category>

		<category><![CDATA[Library]]></category>

		<guid isPermaLink="false">http://technology.blurst.com/?p=44</guid>
		<description><![CDATA[The ability to send game events as messages is a very useful thing indeed.  In our projects, we produce different game systems at different times.  Sound might be last, or we might add in a scoring system long after the initial game logic is completed.  Messages are ideal for this type of [...]]]></description>
			<content:encoded><![CDATA[<p>The ability to send game events as messages is a very useful thing indeed.  In our projects, we produce different game systems at different times.  Sound might be last, or we might add in a scoring system long after the initial game logic is completed.  Messages are ideal for this type of scenario.</p>
<p>For instance, take the event of a raptor dying in <a href="http://blurst.com/raptor-safari/">Raptor Safari</a>.  One option&#8211;a bad one&#8211;is to explicitly reference all neccesary managers in the raptor scripts themselves.  So, to add sound we would have to add a call to our sound manager, to add scoring we call a function on our scoring manager, and so on.  The problem is we <strong>shouldn&#8217;t have to edit older scripts to enable functionality in new managers</strong>.  This is a recipe for errors and programmer collisions (it will be harder to add in real raptor-specific functionality if there is a constant stream of edits to support other parts of the game).</p>
<p>A better paradigm is to have the raptor broadcast a message about its death.  This message includes all relevant information:  What killed the raptor, where it died, a reference to the raptor object itself, and so on.  The message is broadcast with a specific category, like <em>&#8220;raptor&#8221;</em>,<em></em> and interested parties <strong>sign up to consume messages</strong> about this category.</p>
<p>This means we can add functionality about an event <em>without editing the original script</em>.  We could add a sound for our raptor&#8217;s death, include it in our scoring systems, spawn a particle effect, and more&#8211;all without touching the original raptor logic.  Perfect!  But how do we accomplish this is UnityScript?</p>
<p>C# includes a mechanism to do this called delegates, which is a type that references a method or methods.  Unity&#8217;s JavaScript doesn&#8217;t support delegates, however, and in fact we&#8217;re better served with our own system anyway, since we can do additional logic where necessary.  Here&#8217;s our solution:</p>
<h3>Messenger Singleton</h3>
<p>We need a single object to keep track of our lists of listeners.  When a script wants to listen to some classification of events, like &#8220;item&#8221; events, it has to call a function on our messenger.  The messenger then keeps track of which scripts should recieve messages for which types of events.  This looks like:</p>
<div class="codesnip-container" >
<div class="codesnip">Messenger.<span class="me1">instance</span>.<span class="me1">Listen</span><span class="br0">&#40;</span><span class="st0">&#8220;item&#8221;</span>, <span class="kw1">this</span><span class="br0">&#41;</span>;</div>
</div>
<p>The actual collection of listeners is very basic.  We use a Hashtable of ArrayLists.  The Listen() function looks like:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="coMULTI">/**<br />
* Adds a listener for a particular type of message<br />
*/</span><br />
<span class="kw2">function</span> Listen<span class="br0">&#40;</span>listenerType:String, go:GameObject<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span>&nbsp; <br />
&nbsp; &nbsp;<span class="co1">// if there&#8217;s no array for this tracking category, make a new one</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>listeners<span class="br0">&#91;</span>listenerType<span class="br0">&#93;</span> == <span class="kw2">null</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;listeners<span class="br0">&#91;</span>listenerType<span class="br0">&#93;</span> = <span class="kw2">new</span> ArrayList<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw2">var</span> listener:ArrayList = listeners<span class="br0">&#91;</span>listenerType<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// only add to the array if it isn&#8217;t already being tracked</span><br />
&nbsp; &nbsp;<span class="kw1">if</span><span class="br0">&#40;</span>!listener.<span class="me1">Contains</span><span class="br0">&#40;</span>go<span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;listener.<span class="me1">Add</span><span class="br0">&#40;</span>go<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="coMULTI">/**<br />
* Register implicitly with a Component instead of GameObject<br />
*/</span><br />
<span class="kw2">function</span> Listen<span class="br0">&#40;</span>listenerType:String, component:Component<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;Listen<span class="br0">&#40;</span>listenerType, component.<span class="me1">gameObject</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>We use a second function signature that accepts a Component to allow scripts to use <em>this</em> to register as a listener.</p>
<h3>Message Class Structure</h3>
<p>All messages are their own classes.  To send a message you simply instantiate the class.  In Minotaur China Shop, a broadcast of the item delivered message looks like:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">new</span> MessageItemDelivered<span class="br0">&#40;</span><span class="kw1">item</span>, <span class="kw1">this</span><span class="br0">&#41;</span>;</div>
</div>
<p>In this particular case, the message contains the item we delivered to a custom (the first argument), and the customer to which it was delivered (the second argument).  Let&#8217;s take a look at the actual <em>MessageItemDelievered.js</em> file:</p>
<div class="codesnip-container" >
<div class="codesnip">#pragma strict</p>
<p><span class="kw2">class</span> MessageItemDelivered <span class="kw2">extends</span> Message<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// the item that was collected</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> <span class="kw1">item</span>:Item;</p>
<p>&nbsp; &nbsp;<span class="co1">// which customer we delievered it to</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> customer:BaseCustomer;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw2">function</span> MessageItemDelivered<span class="br0">&#40;</span><span class="kw1">item</span>:Item, customer:BaseCustomer<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">this</span>.<span class="kw1">item</span> = <span class="kw1">item</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">this</span>.<span class="me1">customer</span> = customer;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">super</span><span class="br0">&#40;</span><span class="st0">&#8220;item&#8221;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>We use our message objects to store multiple references and values.  Many times we will compute additional values.  For instance, for a raptor death event we may calculate the impact of the event as a scalar from 0..1 and store that in the message.  If other scripts want to know the severity of the impact they can use this value, while leaving us the flexibility to tune it in a single location.  This is one reason delegates wouldn&#8217;t serve us very well.</p>
<p>The <strong>super(&#8221;item&#8221;)</strong> line calls the constructor on the parent class, Message.  This is where we stick our category identifier.  You can think of the line as saying &#8220;our message is now ready, send out to anyone interested in the <em>item</em> category&#8221;.</p>
<h3>Receiving Messages</h3>
<p>You&#8217;ll notice we don&#8217;t actually define the function name the message is calling anywhere.  We do this implicitly based on the class name.  The naming standards we use are messages look like <em>MessageItemDelivered</em> and their corresponding function names look like <em>_ItemDelivered()</em>.  The leading underscore lets us know at a glance that the function will be called by the messenger.</p>
<p>The messenger calls the function and <strong>sends it the instance of the message</strong>.  This allows messages to contain as much data as we want, and also to precompute anything expensive once (at message composition instead of per-listener).  A listening object might look like:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="coMULTI">/**<br />
* Score an item being delievered<br />
*/</span><br />
<span class="kw2">function</span> _ItemDelivered<span class="br0">&#40;</span>msg:MessageItemDelivered<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// do something here</span><br />
&nbsp; &nbsp;Debug.<span class="me1">Log</span><span class="br0">&#40;</span><span class="st0">&#8220;customer purchase # &#8220;</span> + msg.<span class="me1">customer</span>.<span class="me1">itemsPurchased</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>Because our code editing environment includes JavaScript autocomplete, it&#8217;s very easy to write these functions and see which variables a message provides without having to look it up.</p>
<h3>Project Organization</h3>
<p>One of the nice side effects of using one class per message is visible organization.  We keep all of our messages in one folder, so it&#8217;s very easy to see which messages are available in a project.  This allows collaborators to get an idea of how much functionality is exposed by other systems.  If we need to create a new message&#8211;the sound designer would like to hook into something else&#8211;it&#8217;s easy to go in and add new messages, which may prove useful for other functionality later.</p>
<p><img src="http://technology.blurst.com/wp-content/uploads/2008/11/picture-1.png" alt="" title="MCS messages" width="252" height="178" class="alignnone size-full wp-image-59" /></p>
<h3>Adding New Messages</h3>
<p>Adding a new message is relatively painless.  We must:</p>
<ul>
<li>Create a new <strong>MessageSomething</strong> class (we copy/paste an existing message)</li>
<li>Specify the category in the super() call</li>
<li>Listeners register with the Messenger singleton</li>
<li>Listeners implement <strong>_Something</strong>(msg:MessageSomething) function</li>
</ul>
<h3>Performance</h3>
<p>Our actual broadcast functionality uses Unity&#8217;s SendMessage() function.  This isn&#8217;t nearly as fast as calling functions directly with your code, but in practice it&#8217;s fast enough.  You wouldn&#8217;t want to be calling multiple messages every frame, but for game events&#8211;enemy spawned, enemy killed, powerup acquired&#8211;it&#8217;s performant enough to be practical.</p>
<p>In our current implementation we also let null values accumulate in the ArrayLists of listeners.  This hasn&#8217;t caused any problems, because we flush the Messenger along with scene changes.  If you are incredibly performance-conscious, or developing for the iPhone, you may want to skip a messaging system altogether.  The point of a messaging system isn&#8217;t programming performance, but production performance; it&#8217;s a fast and efficient way to get things done.</p>
<h3>Sample Project</h3>
<p>It&#8217;s not as complicated as it sounds, actually.  In practice we create new messages in just a few minutes, and we haven&#8217;t updated the actual Messenger logic in two projects.  Here&#8217;s a sample project to get you started.  If you make any improvements or changes to the project, please let us know by leaving a comment!</p>
<p><a href="/examples/messenger.zip" class="big">Download Sample Project</a></p>
]]></content:encoded>
			<wfw:commentRss>http://technology.blurst.com/unityscript-messaging-system/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
