<?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"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>TriangularPixels.com &#187; Games</title>
	<atom:link href="http://triangularpixels.net/games/category/games/feed/" rel="self" type="application/rss+xml" />
	<link>http://triangularpixels.net/games</link>
	<description>Blue Sky Games</description>
	<lastBuildDate>Tue, 28 Jul 2009 11:51:37 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Analog &#8211; website and 0.5 release</title>
		<link>http://triangularpixels.net/games/games/2009/02/09/analog-website-and-05-release/</link>
		<comments>http://triangularpixels.net/games/games/2009/02/09/analog-website-and-05-release/#comments</comments>
		<pubDate>Mon, 09 Feb 2009 17:59:29 +0000</pubDate>
		<dc:creator>JC</dc:creator>
				<category><![CDATA[Analog]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Games]]></category>
		<category><![CDATA[Rescue Squad 2]]></category>

		<guid isPermaLink="false">http://triangularpixels.net/games/games/2009/02/09/analog-website-and-05-release/</guid>
		<description><![CDATA[Just released into the wild is Analog version 0.5, now with a proper home on the internet with downloads, a feature list and screenshots. It's a freeform map editor for 2d games that's based on vectors rather than being tile-based.

I started work on Analog over a year ago when I wanted a flexible map editor [...]]]></description>
			<content:encoded><![CDATA[<p>Just released into the wild is <a href="http://triangularpixels.net/games/tools/analog/">Analog version 0.5</a>, now with a proper home on the internet with downloads, a feature list and screenshots. It's a freeform map editor for 2d games that's based on vectors rather than being tile-based.</p>
<p><img src="http://www.triangularpixels.net/Analog/Images/version0.5thumb.png" /></p>
<p>I started work on Analog over a year ago when I wanted a flexible map editor for <a href="http://triangularpixels.net/games/rescuesquad2/">Rescue Squad 2</a>, I looked around at various free tile-based editors but they really didn't match what I was looking for. For Rescue Squad I wanted free placement of buildings, items and so on rather than being locked to a grid. Since then I've added support for rectangles, polys and poly lines, and also used it for <a href="http://triangularpixels.net/games/nights-4k/">NiGHTS4k</a>.</p>
<p>It saves into xml format, and you can plug in your own export scripts (written in Java/Beanshell) so you can easily export to another format that's crafted specifically for your game. This came in very handy for NiGHTS4k as I could write the levels into a highly compressed binary format to keep the size as small as possible.</p>
<p>Anyway, have a look and maybe a play with it and let me know what you think. If you're wanting to use it for a game but it's missing an important feature you'd like then don't hesitate to drop me an <a href="http://triangularpixels.net/games/about/">email</a> or a comment here and I'll see what I can do.</p>
]]></content:encoded>
			<wfw:commentRss>http://triangularpixels.net/games/games/2009/02/09/analog-website-and-05-release/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New year, new theme, new game!</title>
		<link>http://triangularpixels.net/games/games/2009/01/31/new-year-new-theme-new-game/</link>
		<comments>http://triangularpixels.net/games/games/2009/01/31/new-year-new-theme-new-game/#comments</comments>
		<pubDate>Sat, 31 Jan 2009 18:26:36 +0000</pubDate>
		<dc:creator>JC</dc:creator>
				<category><![CDATA[Competitions]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Games]]></category>
		<category><![CDATA[Java4k]]></category>

		<guid isPermaLink="false">http://triangularpixels.net/games/games/2009/01/31/new-year-new-theme-new-game/</guid>
		<description><![CDATA[Since it's the new year (yes, I'm a little slow catching up with things) I've been giving the site a bit of an overhaul. I was never really happy with the old theme, due to it being very dark narrow, making it a bit awkward to read on certain monitors and. It was also pretty [...]]]></description>
			<content:encoded><![CDATA[<p>Since it's the new year (yes, I'm a little slow catching up with things) I've been giving the site a bit of an overhaul. I was never really happy with the old theme, due to it being very dark narrow, making it a bit awkward to read on certain monitors and. It was also pretty restrictive in terms of what I could put on the individual pages due to the side navigation bar always being required.</p>
<p>So I've spent the last week working on this new theme and it's pretty much done now. It's much lighter and less bunched up which makes it much easier to read (particularly for large chunks of text) and because the primary navigation is the strip of tabs across the top I can have pages which ditch the side navigation if I want to have a really wide page.</p>
<p>There's new content up too, a game called <a href="nights-4k">NiGHTS 4k</a>, so check that out when you've got a moment. Applets are much more solid these days so I may try a few more applet games as tests, particularly as the new theme means I can embed decent sized applets without breaking the layout.</p>
<p>One minor note about the new theme - it's been tested on the latest versions of Opera, Firefox and Chrome, as well as IE7. Safari hasn't been tested (because I don't have that handy) but since Chrome is based on the same renderer it should be identical. IE6 manages to make a complete pig's ear of it, despite claiming to render it in "standards" mode. Frankly I don't fancy spending a week fighting with IE6's bugs because I shouldn't have to.</p>
<p>Those twelve people reading this site who are still on IE6 will just have to bite the bullet and get a proper browser - or upgrade to IE7 <img src='http://triangularpixels.net/games/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://triangularpixels.net/games/games/2009/01/31/new-year-new-theme-new-game/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Excuse the mess&#8230;</title>
		<link>http://triangularpixels.net/games/games/2009/01/20/excuse-the-mess/</link>
		<comments>http://triangularpixels.net/games/games/2009/01/20/excuse-the-mess/#comments</comments>
		<pubDate>Tue, 20 Jan 2009 17:25:20 +0000</pubDate>
		<dc:creator>JC</dc:creator>
				<category><![CDATA[Games]]></category>

		<guid isPermaLink="false">http://triangularpixels.net/games/games/2009/01/20/excuse-the-mess/</guid>
		<description><![CDATA[I'm having a bit of an early spring clean, mostly to see if I can sort out the site theme and add some new content. If you notice some odd behaviour it's not your eyes going funny.  
]]></description>
			<content:encoded><![CDATA[<p>I'm having a bit of an early spring clean, mostly to see if I can sort out the site theme and add some new content. If you notice some odd behaviour it's not your eyes going funny. <img src='http://triangularpixels.net/games/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://triangularpixels.net/games/games/2009/01/20/excuse-the-mess/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ludum Dare 48h &amp; Locomotion</title>
		<link>http://triangularpixels.net/games/games/2008/07/30/ludum-dare-48h-locomotion/</link>
		<comments>http://triangularpixels.net/games/games/2008/07/30/ludum-dare-48h-locomotion/#comments</comments>
		<pubDate>Wed, 30 Jul 2008 23:06:38 +0000</pubDate>
		<dc:creator>JC</dc:creator>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Competitions]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Games]]></category>

		<guid isPermaLink="false">http://triangularpixels.net/games/games/2008/07/30/ludum-dare-48h-locomotion/</guid>
		<description><![CDATA[It looks like there's another Ludum Dare 48 hour game programming competition starting soon, so I'll hopefully be taking part in that. Spread the word and join in - the more the merrier!
Meanwhile, back on my main project, I'm having much trouble with just trying to get a simple "chase player" behaviour. Pathfinding (with A*) [...]]]></description>
			<content:encoded><![CDATA[<p>It looks like there's another <a href="http://www.ludumdare.com/compo/2008/07/19/ludum-dare-12-august-8-10/">Ludum Dare 48 hour game programming competition</a> starting soon, so I'll hopefully be taking part in that. Spread the word and join in - the more the merrier!</p>
<p>Meanwhile, back on my main project, I'm having much trouble with just trying to get a simple "chase player" behaviour. Pathfinding (with A*) wasn't too hard but there's lots of icky low-level details for moving a character around the environment which are creaping into my behaviour and generally cluttering it up. And due to the highly temporary nature of behaviours stopping and restarting a behaviour (such as repathing when the player moves far enough to invalidate the current behaviour) tends to lead to unpleasant animation jittering as it rapidly switches between idle and running animations.</p>
<p>So I'm trying to pull out some of the low-level movement and animation into a "locomotion" layer. The idea being that it will take high level orders like "run left to this point" or "jump to this waypoint" and it'll automatically handle transitioning from the current animation to the next as well as the low-level ground following and animation ticking.</p>
<p>The idea is that if a behaviour aborts or switches the locomotion layer will still retain the current action and state, so it'll continue with it's current animation until issued a new order by the behaviour. So hopefully switching to or restarting the "chase" behaviour means that instead of snapping to a halt and then starting to run again (often in the same direction) the enemy should continue to run as it was until the "chase" behaviour decides where it actually wants to go. The locomotion layer should probably have a default anim to revert too should the current action finish, so if a behaviour is taking a particularly large time to respond it'll start playing an idle animation rather than doing nothing.</p>
<p>That's the theory at least. In practice drawing the line between locomotion and AI logic is proving tricky, so we'll see how it evolves as things progress...</p>
]]></content:encoded>
			<wfw:commentRss>http://triangularpixels.net/games/games/2008/07/30/ludum-dare-48h-locomotion/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>2D Ambient Shadows</title>
		<link>http://triangularpixels.net/games/games/2008/07/25/2d-ambient-shadows/</link>
		<comments>http://triangularpixels.net/games/games/2008/07/25/2d-ambient-shadows/#comments</comments>
		<pubDate>Fri, 25 Jul 2008 00:01:53 +0000</pubDate>
		<dc:creator>JC</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Games]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[Shaders]]></category>

		<guid isPermaLink="false">http://triangularpixels.net/games/games/2008/07/25/2d-ambient-shadows/</guid>
		<description><![CDATA[For the last few days I've taken some time off from the AI work to mess around with some graphical effects, and in particular I've been experimenting with a 2d ambient shadows effect. This is inspired by the Screen Space Ambient Occulsion (SSAO) effect which has gotten popular lately, and is largely a translation and [...]]]></description>
			<content:encoded><![CDATA[<p>For the last few days I've taken some time off from the AI work to mess around with some graphical effects, and in particular I've been experimenting with a 2d ambient shadows effect. This is inspired by the Screen Space Ambient Occulsion (SSAO) effect which has gotten popular lately, and is largely a translation and adaptation of it into a 2d world.</p>
<p>To start with, here's my test scene (unrelated to the current platformer/ai work):</p>
<p><a href="http://www.triangularpixels.com/DreamCascade/Screenshots/AmbientShader_BaseColour.png"><img src="http://www.triangularpixels.com/DreamCascade/Screenshots/AmbientShader_BaseColour.png" width="200" height="150"></img></a><br />
(all screenshots a quater full size, click to view the full sized version)</p>
<p>That's a whole bunch of tightly packed parallax layers with some trees and letters interleaved between them. The parallax is quite subtle, so it's mostly lost in a static shot but it creates a nice 3d effect when scrolling.</p>
<p>The first step is to also generate a depth map from this. Since we're in 2d and we don't have a z-buffer, we can fake one with a simple shader to tint the sprites based on their depth.</p>
<p><a href="http://www.triangularpixels.com/DreamCascade/Screenshots/AmbientShader_Depth.png"><img src="http://www.triangularpixels.com/DreamCascade/Screenshots/AmbientShader_Depth.png" width="200" height="150"></img></a></p>
<p>(I've artificially tweeked the colour levels in the above to exagerate the layers, as otherwise you only really see white objects on a black background). It looks a bit jaggier than the base colour because we clamp the alpha values of the sprite textures to either be zero or one in the depth shader as otherwise the semi-transparent pixels introduce errors in the next step.</p>
<p>Next is the real magic, we apply the ambient shader. This accepts the previously generated depth texture as an input. For each fragment it looks up it's base depth, then samples a number of surrounding texels and finds their depth as well. Surrounding depths which are higher than our base depth (i.e. it's from a surface in front of us) darken our ambient shadow factor. We also apply a cutoff for this test so that depths which are really far in front get ignored as we decide that their shadow won't be cast onto our current pixel. Surrounding depths lower (i.e. behind) our base depth are ignored.</p>
<p>Surrounding texels are found using precalculated poisson disc offsets in a similar way to traditional growable blur. We also apply a constant offset to these samples so that the shadows appear dropped slightly down-left of the shadow casters.</p>
<p>This produces the raw ambient map:</p>
<p><a href="http://www.triangularpixels.com/DreamCascade/Screenshots/AmbientShader_RawAmbient.png"><img src="http://www.triangularpixels.com/DreamCascade/Screenshots/AmbientShader_RawAmbient.png" width="200" height="150"></img></a></p>
<p>You can see how the grass layers are much more clearly defined and that letters both cast shadows onto trees behind them and receive shadows from trees in front as well.</p>
<p>Since this is a little noisy, we apply a simple blur to the raw ambient map:</p>
<p><a href="http://www.triangularpixels.com/DreamCascade/Screenshots/AmbientShader_BlurredAmbient.png"><img src="http://www.triangularpixels.com/DreamCascade/Screenshots/AmbientShader_BlurredAmbient.png" width="200" height="150"></img></a></p>
<p>Then as a final stage we combine the blurred ambient map with the colour map (and any other layers, like a bloom map) to the framebuffer:</p>
<p><a href="http://www.triangularpixels.com/DreamCascade/Screenshots/AmbientShader_FinalComposite.png"><img src="http://www.triangularpixels.com/DreamCascade/Screenshots/AmbientShader_FinalComposite.png" width="200" height="150"></img></a></p>
<p>A pretty neat effect I think - it's certainly got a lot more depth than the basic colour version, and the shadows on moving objects really help them feel like they're part of the world.</p>
<p>And if anyone wants to play around with this, here's the GLSL shader to generate the raw ambient map:</p>
<pre class="c">&nbsp;
&nbsp;
uniform sampler2D depthMap;
&nbsp;
<span style="color: #993333;">const</span> <span style="color: #993333;">int</span> numSamples = <span style="color: #cc66cc;">16</span>;
<span style="color: #993333;">const</span> <span style="color: #993333;">float</span> divisor = <span style="color: #cc66cc;">1.0</span> / <span style="color: #993333;">float</span><span style="color: #66cc66;">&#40;</span>numSamples<span style="color: #66cc66;">&#41;</span>;
&nbsp;
vec2 samples<span style="color: #66cc66;">&#91;</span>numSamples<span style="color: #66cc66;">&#93;</span>;
&nbsp;
<span style="color: #993333;">void</span> main<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#123;</span>
	<span style="color: #808080; font-style: italic;">// Our generated poisson disc sample offsets</span>
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0.007937789</span>, <span style="color: #cc66cc;">0.73124397</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">-0.10177308</span>, <span style="color: #cc66cc;">-0.6509396</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">-0.9906806</span>, <span style="color: #cc66cc;">-0.63400936</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">-0.5583586</span>, <span style="color: #cc66cc;">-0.3614012</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">4</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0.7163085</span>, <span style="color: #cc66cc;">0.22836149</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">5</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">-0.65210974</span>, <span style="color: #cc66cc;">0.37117887</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">6</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">-0.12714535</span>, <span style="color: #cc66cc;">0.112056136</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">7</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0.48898065</span>, <span style="color: #cc66cc;">-0.66669613</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">8</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">-0.9744036</span>, <span style="color: #cc66cc;">0.9155904</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">9</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0.9274436</span>, <span style="color: #cc66cc;">-0.9896486</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0.9782181</span>, <span style="color: #cc66cc;">0.90990245</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0.96427417</span>, <span style="color: #cc66cc;">-0.25506377</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">12</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">-0.5021933</span>, <span style="color: #cc66cc;">-0.9712455</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">13</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0.3091557</span>, <span style="color: #cc66cc;">-0.17652994</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">14</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0.4665941</span>, <span style="color: #cc66cc;">0.96454906</span><span style="color: #66cc66;">&#41;</span>;
	samples<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">15</span><span style="color: #66cc66;">&#93;</span> = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">-0.461774</span>, <span style="color: #cc66cc;">0.9360856</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
	<span style="color: #808080; font-style: italic;">// Sample spread distance</span>
	<span style="color: #993333;">float</span> spread = <span style="color: #cc66cc;">0.007</span>;
&nbsp;
	<span style="color: #808080; font-style: italic;">// Offset to make shadows set slightly down and left from their caster</span>
	vec2 depthOffset = vec2<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0.001</span>, <span style="color: #cc66cc;">0.003</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
	<span style="color: #808080; font-style: italic;">// Grab the base texture coord</span>
	vec2 baseCoord = gl_TexCoord<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#93;</span>.<span style="color: #202020;">xy</span>;
&nbsp;
	<span style="color: #993333;">float</span> baseDepth = texture2D<span style="color: #66cc66;">&#40;</span>depthMap, baseCoord<span style="color: #66cc66;">&#41;</span>.<span style="color: #202020;">r</span>;
&nbsp;
	<span style="color: #993333;">float</span> ambient = <span style="color: #cc66cc;">1.0</span>;
	<span style="color: #b1b100;">for</span> <span style="color: #66cc66;">&#40;</span><span style="color: #993333;">int</span> i=<span style="color: #cc66cc;">0</span>; i&amp;lt;numSamples; i++<span style="color: #66cc66;">&#41;</span>
	<span style="color: #66cc66;">&#123;</span>
		<span style="color: #993333;">float</span> offsetDepth = texture2D<span style="color: #66cc66;">&#40;</span>depthMap, baseCoord + depthOffset +
					<span style="color: #66cc66;">&#40;</span>samples<span style="color: #66cc66;">&#91;</span>i<span style="color: #66cc66;">&#93;</span> * spread<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span>.<span style="color: #202020;">r</span>;
		<span style="color: #993333;">float</span> diff = offsetDepth - baseDepth; <span style="color: #808080; font-style: italic;">// diff is +itive if offset depth</span>
							<span style="color: #808080; font-style: italic;">// is in front of us</span>
&nbsp;
		<span style="color: #993333;">float</span> cutoff = <span style="color: #cc66cc;">0.08</span>;	<span style="color: #808080; font-style: italic;">// limits how far objects can cast a shadow</span>
		<span style="color: #993333;">float</span> threshold = <span style="color: #cc66cc;">0.01</span>;	<span style="color: #808080; font-style: italic;">// must cross this threshold to cast a shdow</span>
&nbsp;
		<span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>diff &amp;lt; cutoff &amp;&amp; diff &amp;gt; <span style="color: #cc66cc;">0.01</span><span style="color: #66cc66;">&#41;</span>
		<span style="color: #66cc66;">&#123;</span>
			diff = clamp<span style="color: #66cc66;">&#40;</span>diff, <span style="color: #cc66cc;">0.0</span>, cutoff<span style="color: #66cc66;">&#41;</span>;
			diff = cutoff - diff;
&nbsp;
			ambient -= diff;
		<span style="color: #66cc66;">&#125;</span>
	<span style="color: #66cc66;">&#125;</span>
&nbsp;
	gl_FragColor = vec4<span style="color: #66cc66;">&#40;</span>ambient, ambient, ambient, <span style="color: #cc66cc;">1.0</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #66cc66;">&#125;</span></pre>
<p>All of the other shaders are trivial, so I won't include those. And the above is probably pretty sub-optimal as it was written for clarity rather than speed but it seems to fly along at a nice smooth framerate regardless. <img src='http://triangularpixels.net/games/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>If anyone experiments further with this I'd be interested in hearing about your results and comments. Ta.</p>
]]></content:encoded>
			<wfw:commentRss>http://triangularpixels.net/games/games/2008/07/25/2d-ambient-shadows/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Jumping, launch velocities and rounding errors</title>
		<link>http://triangularpixels.net/games/games/2008/07/18/jumping-launch-velocities-and-rounding-errors/</link>
		<comments>http://triangularpixels.net/games/games/2008/07/18/jumping-launch-velocities-and-rounding-errors/#comments</comments>
		<pubDate>Fri, 18 Jul 2008 09:19:49 +0000</pubDate>
		<dc:creator>JC</dc:creator>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Games]]></category>

		<guid isPermaLink="false">http://triangularpixels.net/games/games/2008/07/18/jumping-launch-velocities-and-rounding-errors/</guid>
		<description><![CDATA[The physics behind a jump in a platformer is pretty simple and something I must have written a thousand times, but having an AI player jump and land where it wants to is considerably trickier. My initial attempt was to string a bezier curve between the start and end points and just make it follow [...]]]></description>
			<content:encoded><![CDATA[<p>The physics behind a jump in a platformer is pretty simple and something I must have written a thousand times, but having an AI player jump and land where it wants to is considerably trickier. My initial attempt was to string a bezier curve between the start and end points and just make it follow that - this is easy to do and very reliable (as it will always get to the exact end point) but produces unconvincing motion. It really needs to use the proper physics otherwise it looks out of place.</p>
<p>So if we're using the proper physics we want to calculate a launch velocity then just let the simulation do the rest. However finding a suitable launch velocity isn't easy - there's lots of unknowns and variables, largely because there's lots of potential jump arcs which take you between two points. You need to nail down a few of the variables so that ideally only one solution pops out.</p>
<p>After several failed attempts I've found that specifying the jump apex gives nice consistent and controllable results. I can pick the apex by applying an offset from the highest of the start and end points then split the jump into three components- the vertically to the apex, vertically from the apex, and horizontally for the whole jump:</p>
<pre class="cpp">&nbsp;
ImmutableVector2f startPos = enemy.<span style="color: #00eeff;">getPosition</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>;
ImmutableVector2f endPos = nextWaypoint.<span style="color: #00eeff;">getPosition</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>;
&nbsp;
<span style="color: #ff0000;">// First, find jump apex</span>
final <span style="color: #0000ff;">float</span> highestY = Math.<span style="color: #00eeff;">max</span><span style="color: #000000;">&#40;</span>startPos.<span style="color: #00eeff;">y</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>, endPos.<span style="color: #00eeff;">y</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>;
final <span style="color: #0000ff;">float</span> apexY = highestY + <span style="color: #0000dd;">100</span>;
&nbsp;
<span style="color: #ff0000;">// Vertically, to apex</span>
<span style="color: #ff0000;">// t = sqrt( 2s / a )</span>
&nbsp;
final <span style="color: #0000ff;">float</span> s1 = apexY - startPos.<span style="color: #00eeff;">y</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>;
final <span style="color: #0000ff;">float</span> t1 = <span style="color: #000000;">&#40;</span><span style="color: #0000ff;">float</span><span style="color: #000000;">&#41;</span>Math.<span style="color: #0000dd;">sqrt</span><span style="color: #000000;">&#40;</span> <span style="color: #000000;">&#40;</span><span style="color: #0000dd;">2</span> * s1<span style="color: #000000;">&#41;</span> / -FallBehaviour.<span style="color: #00eeff;">GRAVITY</span><span style="color: #000000;">&#41;</span>;
&nbsp;
<span style="color: #ff0000;">// What's our launch speed for this section?</span>
final <span style="color: #0000ff;">float</span> vy = -FallBehaviour.<span style="color: #00eeff;">GRAVITY</span> * t1;
&nbsp;
<span style="color: #ff0000;">// Vertically from apex</span>
&nbsp;
final <span style="color: #0000ff;">float</span> s2 = apexY - endPos.<span style="color: #00eeff;">y</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>;
final <span style="color: #0000ff;">float</span> t2 = <span style="color: #000000;">&#40;</span><span style="color: #0000ff;">float</span><span style="color: #000000;">&#41;</span>Math.<span style="color: #0000dd;">sqrt</span><span style="color: #000000;">&#40;</span> <span style="color: #000000;">&#40;</span><span style="color: #0000dd;">2</span> * s2<span style="color: #000000;">&#41;</span> / -FallBehaviour.<span style="color: #00eeff;">GRAVITY</span><span style="color: #000000;">&#41;</span>;
&nbsp;
<span style="color: #ff0000;">// Total time for entire jump</span>
final <span style="color: #0000ff;">float</span> tTotal = t1 + t2;
&nbsp;
<span style="color: #ff0000;">// Horizontally</span>
final <span style="color: #0000ff;">float</span> s3 = <span style="color: #000000;">&#40;</span>endPos.<span style="color: #00eeff;">x</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> - startPos.<span style="color: #00eeff;">x</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>;
final <span style="color: #0000ff;">float</span> vx = s3 / tTotal;
&nbsp;
brain.<span style="color: #00eeff;">jump</span><span style="color: #000000;">&#40;</span> <span style="color: #0000dd;">new</span> Vector2f<span style="color: #000000;">&#40;</span>vx, vy<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#41;</span>;
&nbsp;</pre>
<p>Unfortunately this has two down sides - the structure of a level means that sometimes there is an interveaning platform that the AI wants to jump "through" but the simulation causes it to land there instead. The other down side is that rounding errors mean you don't always hit the target exactly, and since my collision is all sub-pixel that means you can miss the edge of the platform by a fraction and end up plummetting to your doom.</p>
<p>The solution is to also calculate the expected time length of the jump and when that time is reached snap the enemy to the target point (and disable all other ground collisions in between). This gives us the best of both approaches - the AI always ends up exactly where it wanted to, but while following a convincing curve. And since we're doing a proper simulation if something happens during the jump (like we get hit) we can easily turn off the special collision handling and let the physics take over.</p>
<p>On an entirely different note, <a href="http://www.indiegames.com/blog/2008/07/freeware_game_pick_deaths_jess.html">Deaths</a> (thanks indie gamer) is a really neat idea for a platformer with a twist (and, amusingly, no AI whatsoever). Passive online interaction like this is something I've been thinking about for a while but can never manage to come up with an idea where it's an important part of the gameplay rather than just a novelty - Deaths manages this quite well I think.</p>
]]></content:encoded>
			<wfw:commentRss>http://triangularpixels.net/games/games/2008/07/18/jumping-launch-velocities-and-rounding-errors/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hello world!</title>
		<link>http://triangularpixels.net/games/games/2008/06/16/hello-world/</link>
		<comments>http://triangularpixels.net/games/games/2008/06/16/hello-world/#comments</comments>
		<pubDate>Mon, 16 Jun 2008 12:00:19 +0000</pubDate>
		<dc:creator>JC</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Games]]></category>

		<guid isPermaLink="false">http:/?p=1</guid>
		<description><![CDATA[My website has been neglected lately, so I've decided it's time for a makeover. As well as a fresh new look and a new url I've decided to move my journal from GameDev.net over to here. The reliability of gamedev has been pretty low recently, and I've much more space and flexibility over here for [...]]]></description>
			<content:encoded><![CDATA[<p>My website has been neglected lately, so I've decided it's time for a makeover. As well as a fresh new look and a new url I've decided to move my journal from GameDev.net over to here. The reliability of gamedev has been pretty low recently, and I've much more space and flexibility over here for things like bigger images, RSS and embedding videos.</p>
<p>Since I've got a whole load of journal entries over at the previous journal I don't want to loose I'm going to be "reposting" some of the more interesting ones over here. I say "reposting" because they'll probably get reworked and multiple smaller entries merged into a more cohesive whole rather than just straight copy-paste to bring them up to date and make them a little more focused.</p>
]]></content:encoded>
			<wfw:commentRss>http://triangularpixels.net/games/games/2008/06/16/hello-world/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

