<?xml version="1.0" encoding="UTF-8" ?><rss version="2.0">
<channel>
<title>Brian MacIntosh (Blog)</title>
<link>https://www.brianmacintosh.com/blog/</link>
<description>A blog for sharing free game development resources and insights.</description>
<copyright>Copyright &#169; 2010-2021 Brian MacIntosh</copyright>
<language>en-us</language>
<webMaster>webmaster@brianmacintosh.com (Brian MacIntosh)</webMaster>
<docs>https://validator.w3.org/feed/docs/rss2.html</docs>
<image>
	<url>https://www.brianmacintosh.com/blog/blogfeed_img.png</url>
	<title>Brian MacIntosh (Blog)</title>
	<link>https://www.brianmacintosh.com/blog/</link>
</image>
<lastBuildDate>Thu, 24 Nov 2022 15:48:18 -0600</lastBuildDate>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>An index of website security features</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=106</guid><link>https://brianmacintosh.com/blog/comments.php?post=106</link><description>&lt;p&gt;I recently took a bit of dive into website security. As the developer of a website, of course I&#039;d like my website to be secure, even if it doesn&#039;t handle any sensitive user data. It&#039;s also just a fun way to learn more about how the web we use every day works. I read about and implemented a number of security features that I gathered from various blogs, lists, and validation tools, and I wanted to collect them in one spot for my own reference and for anyone else who might find them useful.&lt;/p&gt;
&lt;p&gt;I&#039;ll include a few words about what each of them do, but Google will get you all the in-depth information you need, so this is mostly intended as an index of some features that exist so you can look into them more.&lt;/p&gt;
&lt;p&gt;Example code is in PHP.&lt;/p&gt;
&lt;p&gt;This list is certainly not exhaustive. Here are a few other sources I referenced:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.troyhunt.com/hack-yourself-first-how-to-go-on/&quot;&gt;Hack Yourself First by Troy Hunt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://owasp.org/www-project-top-ten/&quot;&gt;OWASP Top Ten&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.veracode.com/blog/2014/03/guidelines-for-setting-security-headers&quot;&gt;Guidelines for Setting Security Headers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;CSP (Content Security Policy)&lt;/h2&gt;

&lt;p&gt;The &lt;b&gt;Content Security Policy&lt;/b&gt; is an HTTP header that decribes what types of media, scripts, styles, and other content your page will have on it. This allows the user&#039;s browser to block any unexpected content that may have somehow been injected by an attacker (maybe in a forum post, or via an XSS attack).&lt;/p&gt;
&lt;p&gt;Every HTML page served should have a CSP. My workflow for adding them is to add the following maximally-restrictive CSP, load the page in a browser, check the developer console for CSP errors, and add entries to permit those things. For embedded styles or scripts, the console will report a hash you can add to the CSP.&lt;/p&gt;
&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&quot;color:#000000;background:#ffffff;&quot;&gt;
&lt;span style=&quot;color:#400000; background:#ffffe8; &quot;&gt;header&lt;/span&gt;&lt;span style=&quot;color:#808030; background:#ffffe8; &quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0000e6; background:#ffffe8; &quot;&gt;&quot;Content-Security-Policy: &quot;&lt;/span&gt;&lt;span style=&quot;color:#000000; background:#ffffe8; &quot;&gt;&lt;/span&gt;
&lt;span style=&quot;color:#000000; background:#ffffe8; &quot;&gt;	&lt;/span&gt;&lt;span style=&quot;color:#808030; background:#ffffe8; &quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#0000e6; background:#ffffe8; &quot;&gt;&quot;default-src &#039;none&#039;;&quot;&lt;/span&gt;&lt;span style=&quot;color:#000000; background:#ffffe8; &quot;&gt;&lt;/span&gt;
&lt;span style=&quot;color:#000000; background:#ffffe8; &quot;&gt;	&lt;/span&gt;&lt;span style=&quot;color:#808030; background:#ffffe8; &quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#0000e6; background:#ffffe8; &quot;&gt;&quot;frame-ancestors &#039;none&#039;;&quot;&lt;/span&gt;&lt;span style=&quot;color:#000000; background:#ffffe8; &quot;&gt;&lt;/span&gt;
&lt;span style=&quot;color:#000000; background:#ffffe8; &quot;&gt;	&lt;/span&gt;&lt;span style=&quot;color:#808030; background:#ffffe8; &quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#0000e6; background:#ffffe8; &quot;&gt;&quot;base-uri &#039;none&#039;;&quot;&lt;/span&gt;&lt;span style=&quot;color:#000000; background:#ffffe8; &quot;&gt;&lt;/span&gt;
&lt;span style=&quot;color:#000000; background:#ffffe8; &quot;&gt;	&lt;/span&gt;&lt;span style=&quot;color:#808030; background:#ffffe8; &quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#0000e6; background:#ffffe8; &quot;&gt;&quot;form-action &#039;none&#039;;&quot;&lt;/span&gt;&lt;span style=&quot;color:#808030; background:#ffffe8; &quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#800080; background:#ffffe8; &quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#000000; background:#ffffe8; &quot;&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/code&gt;
&lt;p&gt;You cannot use inline styles or Javascript events with a CSP without adding the &#039;unsafe-inline&#039; item, which defeats much of the purpose of having a CSP.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Mitigates:&lt;/b&gt; XSS, clickjacking&lt;/p&gt;

&lt;h2&gt;SSL (HTTPS)&lt;/h2&gt;

&lt;p&gt;Most other security measures can be circumvented if an attacker can intercept the communications between a user and the server (such as via ARP poisoning). Acquiring an SSL certificate and using the HTTPS protocol will allow your site to use encrypted communications, making this impossible. Many hosting providers are now providing ways to acquire free certificates&lt;/p&gt;
&lt;p&gt;You must also redirect insecure HTTP requests to HTTPS, such as via this htaccess rule:&lt;/p&gt;
&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;RewriteEngine&lt;/span&gt; &lt;span style=&#039;color:#074726; &#039;&gt;On&lt;/span&gt;
&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;RewriteCond&lt;/span&gt; %{HTTPS} &lt;span style=&#039;color:#074726; &#039;&gt;off&lt;/span&gt;
&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;RewriteRule&lt;/span&gt; ^&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;.*&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;$ https://%{HTTP_HOST}%{REQUEST_URI} [L&lt;span style=&#039;color:#808030; &#039;&gt;,&lt;/span&gt;R=&lt;span style=&#039;color:#008c00; &#039;&gt;301&lt;/span&gt;]
&lt;/pre&gt;
&lt;/code&gt;

&lt;h2&gt;Strict-Transport-Security (HSTS)&lt;/h2&gt;

&lt;p&gt;Now that your site supports HTTPS, add the &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;Strict-Transport-Security: max-age=&amp;lt;expire-time&amp;gt;&lt;/span&gt; header to every file served. This directs the user&#039;s browser to only use HTTPS when connecting to your site. This performs a slightly different function than a server-side 301 redirect to HTTPS, in that the browser itself will upgrade future requests to HTTPS before ever sending them to the server.&lt;/p&gt;
&lt;p&gt;Via htaccess:&lt;/p&gt;
&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;Header&lt;/span&gt; &lt;span style=&#039;color:#074726; &#039;&gt;set&lt;/span&gt; Strict&lt;span style=&#039;color:#808030; &#039;&gt;-&lt;/span&gt;Transport&lt;span style=&#039;color:#808030; &#039;&gt;-&lt;/span&gt;Security &lt;span style=&#039;color:#0000e6; &#039;&gt;&quot;max-age=31536000&quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;/code&gt;
&lt;p&gt;&lt;b&gt;Mitigates:&lt;/b&gt; man-in-the-middle attacks&lt;/p&gt;

&lt;h2&gt;X-Frame-Options: deny&lt;/h2&gt;

&lt;p&gt;Add the &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;X-Frame-Options: deny&lt;/span&gt; header to every HTML page served. This header instructs the browser to not permit your page to be framed on another page.&lt;/p&gt;
&lt;p&gt;Via htaccess:&lt;/p&gt;
&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;filesMatch&lt;/span&gt; &lt;span style=&#039;color:#0000e6; &#039;&gt;&quot;.(php|html|htm)$&quot;&lt;/span&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&gt;&lt;/span&gt;
	&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;Header&lt;/span&gt; &lt;span style=&#039;color:#074726; &#039;&gt;set&lt;/span&gt; X&lt;span style=&#039;color:#808030; &#039;&gt;-&lt;/span&gt;Frame&lt;span style=&#039;color:#808030; &#039;&gt;-&lt;/span&gt;Options &lt;span style=&#039;color:#0000e6; &#039;&gt;&quot;deny&quot;&lt;/span&gt;
&lt;span style=&#039;color:#a65700; &#039;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;filesMatch&lt;/span&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/code&gt;
&lt;p&gt;&lt;b&gt;Mitigates:&lt;/b&gt; clickjacking&lt;/p&gt;

&lt;h2&gt;X-Content-Type-Options: nosniff&lt;/h2&gt;

&lt;p&gt;Add the &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;X-Content-Type-Options: nosniff&lt;/span&gt; header to every file served. In some cases, browsers will ignore the MIME type set by the server and try to determine it by looking at the file. This can be a security risk if your site hosts user-provided files, which could have a harmless extension such as .txt but be interpretted by browsers as executable code such as Javascript.&lt;/p&gt;
&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;Header&lt;/span&gt; &lt;span style=&#039;color:#074726; &#039;&gt;set&lt;/span&gt; X&lt;span style=&#039;color:#808030; &#039;&gt;-&lt;/span&gt;Content&lt;span style=&#039;color:#808030; &#039;&gt;-&lt;/span&gt;Type&lt;span style=&#039;color:#808030; &#039;&gt;-&lt;/span&gt;Options &lt;span style=&#039;color:#0000e6; &#039;&gt;&quot;nosniff&quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;/code&gt;
&lt;p&gt;&lt;b&gt;Mitigates:&lt;/b&gt; MIME confusion&lt;/p&gt;

&lt;h2&gt;Remove X-Powered-By&lt;/h2&gt;

&lt;p&gt;Some web technologies, such as PHP, will identify themselves in the X-Powered-By header of responses. This could help an attacker find weaknesses in the site to attack. Remove this header from all responses.&lt;/p&gt;
&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;Header&lt;/span&gt; &lt;span style=&#039;color:#074726; &#039;&gt;unset&lt;/span&gt; X&lt;span style=&#039;color:#808030; &#039;&gt;-&lt;/span&gt;Powered&lt;span style=&#039;color:#808030; &#039;&gt;-&lt;/span&gt;By
&lt;/pre&gt;
&lt;/code&gt;
&lt;p&gt;&lt;b&gt;Mitigates:&lt;/b&gt; fingerprinting&lt;/p&gt;

&lt;h2&gt;MySQL Prepared Statements&lt;/h2&gt;

&lt;p&gt;Always use &lt;b&gt;prepared statements&lt;/b&gt; to make dynamic SQL queries. Forming queries by concatenating strings may allow an attacker to perform SQL injection, if user-provided data can find its way into any of the components in the query. The attacker might be able to extract private data from tables, insert malicious data, or vandalize or drop data.&lt;/p&gt;
&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;
&lt;span style=&#039;color:#797997; background:#ffffe8; &#039;&gt;$query&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;=&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#797997; background:#ffffe8; &#039;&gt;$connection&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;-&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;&gt;&lt;/span&gt;&lt;span style=&#039;color:#400000; background:#ffffe8; &#039;&gt;prepare&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#0000e6; background:#ffffe8; &#039;&gt;&quot;INSERT INTO blog (id, date, title, text) VALUES (NULL, NOW(), ?, ?)&quot;&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#800080; background:#ffffe8; &#039;&gt;;&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt;&lt;/span&gt;
&lt;span style=&#039;color:#797997; background:#ffffe8; &#039;&gt;$query&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;-&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;&gt;&lt;/span&gt;&lt;span style=&#039;color:#400000; background:#ffffe8; &#039;&gt;bind_param&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#0000e6; background:#ffffe8; &#039;&gt;&quot;ss&quot;&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;,&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#797997; background:#ffffe8; &#039;&gt;$unsafeTitle&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;,&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#797997; background:#ffffe8; &#039;&gt;$unsafeText&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#800080; background:#ffffe8; &#039;&gt;;&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt;&lt;/span&gt;
&lt;span style=&#039;color:#797997; background:#ffffe8; &#039;&gt;$query&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;-&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;&gt;&lt;/span&gt;&lt;span style=&#039;color:#400000; background:#ffffe8; &#039;&gt;execute&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#800080; background:#ffffe8; &#039;&gt;;&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/code&gt;
&lt;p&gt;&lt;b&gt;Mitigates:&lt;/b&gt; SQL injection&lt;/p&gt;

&lt;h2&gt;Data sanitization&lt;/h2&gt;

&lt;p&gt;Sanitize user-provided data as necessary before using it in any context. Use a function like PHP&#039;s &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;strip_tags&lt;/span&gt; for text. If you expect data to be a number or bool, run it through &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;intval&lt;/span&gt;, &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;floatval&lt;/span&gt;, or &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;boolval&lt;/span&gt;. This will prevent an attacker from inserting malicious code into pages (XSS attack).&lt;/p&gt;
&lt;p&gt;I like to name any user-provided variable that hasn&#039;t been thoroughly sanitized yet with the prefix &quot;unsafe&quot;. This helps me remember that that data may need to be sanitized before being used.&lt;/p&gt;
&lt;p&gt;This applies equally to data that was previously provided by a user and stored (&quot;second-order attack&quot;).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Mitigates:&lt;/b&gt; XSS, SQL injection&lt;/p&gt;

&lt;h2&gt;Hash Passwords&lt;/h2&gt;

&lt;p&gt;Passwords on the server should always be stored as hashes; the original password should not be present on the server. This will prevent an attacker who finds a way to extract data from the server from logging in with those passwords (without cracking the hashes).&lt;/p&gt;
&lt;p&gt;In PHP, you can generate a salted password hash like so (either offline or online depending on your needs):&lt;/p&gt;
&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;
&lt;span style=&#039;color:#797997; background:#ffffe8; &#039;&gt;$passwordHash&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;=&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt; password_hash&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#0000e6; background:#ffffe8; &#039;&gt;&quot;PASSWORD&quot;&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;,&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt; PASSWORD_DEFAULT&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#800080; background:#ffffe8; &#039;&gt;;&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/code&gt;
&lt;p&gt;And check it like so:&lt;/p&gt;
&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;
&lt;span style=&#039;color:#797997; background:#ffffe8; &#039;&gt;$unsafePassword&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;=&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#797997; background:#ffffe8; &#039;&gt;$_POST&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;[&lt;/span&gt;&lt;span style=&#039;color:#0000e6; background:#ffffe8; &#039;&gt;&#039;pword&#039;&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;]&lt;/span&gt;&lt;span style=&#039;color:#800080; background:#ffffe8; &#039;&gt;;&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt;&lt;/span&gt;
&lt;span style=&#039;color:#800000; background:#ffffe8; font-weight:bold; &#039;&gt;if&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt;password_verify&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#797997; background:#ffffe8; &#039;&gt;$unsafePassword&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;,&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#0000e6; background:#ffffe8; &#039;&gt;&#039;PASSWORD_HASH&#039;&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#808030; background:#ffffe8; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt;&lt;/span&gt;
&lt;span style=&#039;color:#800080; background:#ffffe8; &#039;&gt;{&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt;&lt;/span&gt;
&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt;	&lt;/span&gt;&lt;span style=&#039;color:#696969; background:#ffffe8; &#039;&gt;// Restricted code&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt;&lt;/span&gt;
&lt;span style=&#039;color:#800080; background:#ffffe8; &#039;&gt;}&lt;/span&gt;&lt;span style=&#039;color:#000000; background:#ffffe8; &#039;&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/code&gt;
&lt;p&gt;&lt;b&gt;Mitigates:&lt;/b&gt; password leakage&lt;/p&gt;

&lt;h2&gt;Restrict MySQL user privileges&lt;/h2&gt;

&lt;p&gt;Scripts generating pages should use a MySQL user that has only the privileges it needs (for example, only the SELECT privilege on tables containing public data). This will prevent an attacker who finds an injection vulnerability from using it to modify or delete data.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Mitigates:&lt;/b&gt; SQL injection&lt;/p&gt;

&lt;h2&gt;Files on your server are public&lt;/h2&gt;

&lt;p&gt;Even if there are no links to them, any file on your server that isn&#039;t protected by an actual access control mechanism should be considered public. Do not upload &lt;b&gt;.git&lt;/b&gt; folders, documents containing passwords, pre-minified source, etc., or an attacker might be able to enumerate and download them. Obscurity is not security.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Mitigates:&lt;/b&gt; data leakage, fingerprinting&lt;/p&gt;

&lt;h2&gt;Use rel=&amp;quot;noopener&amp;quot; on external links that open in new tabs&lt;/h2&gt;

&lt;p&gt;When a user follows a link that opens a new tab, older browsers may provide the new page with the &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;window.opener&lt;/span&gt; property, a reference to your page&#039;s window. The target page could use this to do certain operations on your page (in particular, navigate to a different URL).&lt;/p&gt;
&lt;p&gt;Browsers will restrict this by default since late 2018, but you can be sure it&#039;s done by providing &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;rel=&amp;quot;noopener&amp;quot;&lt;/span&gt; on any external &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;target=&amp;quot;_blank&amp;quot;&lt;/span&gt; links.&lt;/p&gt;
&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;a&lt;/span&gt;&lt;span style=&#039;color:#274796; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#074726; &#039;&gt;href&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt;&lt;span style=&#039;color:#0000e6; &#039;&gt;&quot;https://example.com&quot;&lt;/span&gt;&lt;span style=&#039;color:#274796; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#074726; &#039;&gt;target&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt;&lt;span style=&#039;color:#0000e6; &#039;&gt;&quot;_blank&quot;&lt;/span&gt;&lt;span style=&#039;color:#274796; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#074726; &#039;&gt;rel&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt;&lt;span style=&#039;color:#0000e6; &#039;&gt;&quot;noopener&quot;&lt;/span&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&gt;&lt;/span&gt;Link&lt;span style=&#039;color:#a65700; &#039;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;a&lt;/span&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/code&gt;
&lt;p&gt;&lt;b&gt;Mitigates:&lt;/b&gt; phishing attacks&lt;/p&gt;

&lt;h2&gt;Subresource Integrity&lt;/h2&gt;

&lt;p&gt;If your site loads resources such as scripts or stylesheets from an external domain such as CloudFlare or Google Fonts, how do you know the provider (or an attacker) hasn&#039;t inserted something malicious into them? The answer is to add a hash of the file&#039;s expected contents to the &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;integrity&lt;/span&gt; parameter on the relevant HTML tag. The browser will refuse to use the content if the hash doesn&#039;t match the file served.&lt;/p&gt;
&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;script&lt;/span&gt;&lt;span style=&#039;color:#274796; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#074726; &#039;&gt;src&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt;&lt;span style=&#039;color:#0000e6; &#039;&gt;&quot;https://example.com/example-framework.js&quot;&lt;/span&gt;&lt;span style=&#039;color:#274796; &#039;&gt;&lt;/span&gt;
&lt;span style=&#039;color:#274796; &#039;&gt;	integrity&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt;&lt;span style=&#039;color:#0000e6; &#039;&gt;&quot;sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC&quot;&lt;/span&gt;&lt;span style=&#039;color:#274796; &#039;&gt;&lt;/span&gt;
&lt;span style=&#039;color:#274796; &#039;&gt;	crossorigin&lt;/span&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&gt;&lt;/span&gt;
&lt;span style=&#039;color:#a65700; &#039;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;script&lt;/span&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/code&gt;
&lt;p&gt;&lt;b&gt;Mitigates:&lt;/b&gt; supply-chain compromise&lt;/p&gt;

&lt;h2&gt;Use captchas before sending emails&lt;/h2&gt;

&lt;p&gt;This is a weird one that I learned about when it actually happened on my site. If your site accepts e-mail addresses from users, you must perform a captcha on the user before sending any mail to verify they are not a bot.&lt;/p&gt;
&lt;p&gt;Why? If an attacker has compromised a user account on some other site (such as a bank) and intends to perform some action that might send the user an e-mail alert, they can have a bot automatically feed that user&#039;s e-mail address to any site with a form that will take it. The intent is to flood that inbox with e-mails in the hope that the user will not notice the important one. This is basically a kind of DDoS attack.&lt;/p&gt;
&lt;p&gt;This isn&#039;t just bad for the target: it could also land your domain on a spam blacklist, which can be difficult to fix.&lt;/p&gt;
&lt;p&gt;Google provides a free, low-friction captcha called &lt;a href=&quot;https://developers.google.com/recaptcha&quot;&gt;reCAPTCHA&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Mitigates:&lt;/b&gt; email flooding&lt;/p&gt;

&lt;h2&gt;Serve /.well-known/security.txt&lt;/h2&gt;

&lt;p&gt;This is a simple text file on your server. It provides, &lt;a href=&quot;https://securitytxt.org/&quot;&gt;at minimum&lt;/a&gt;, an e-mail address for security researchers to contact if they find a security problem with your site. I&#039;ve received two such reports for my site that were quite helpful.&lt;/p&gt;
&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;
Contact: example@example.com
Preferred-Languages: en
Canonical: https://example.com/.well-known/security.txt
&lt;/pre&gt;
&lt;/code&gt;
&lt;p&gt;&lt;b&gt;Mitigates:&lt;/b&gt; anything a security researcher might notice&lt;/p&gt;</description><pubDate>Thu, 24 Nov 2022 15:48:18 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Running a laser with Marlin and the Ender 3 board</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=105</guid><link>https://brianmacintosh.com/blog/comments.php?post=105</link><description>&lt;p&gt;I recently started working on building a laser cutter/engraver. I wanted to use the Ender 3 v1.1.4 board and Marlin firmware because I already had them and was familiar with them. This didn&#039;t end up being too complicated, but it did require a few unexpected changes, which I&#039;ll document here. This isn&#039;t a step-by-step, just a summary of what worked for me.&lt;/p&gt;
&lt;p&gt;I&#039;m not an electrical engineer. This process worked for me, but I don&#039;t know if it will work you. Electricity is dangerous. Lasers are dangerous. Wear appropriate laser eye protection before powering the board with a laser connected.&lt;/p&gt;
&lt;p&gt;You&#039;ll need to know how to build and upload firmware to the Ender 3 board to follow this. I have a little bit of info about that &lt;a href=&quot;https://www.brianmacintosh.com/blog/comments.php?post=103&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I started with Marlin &lt;a href=&quot;https://github.com/BrianMacIntosh/Marlin/commit/80980d62ff22eb27cf87fd78f983a12b71b54fdf&quot;&gt;configured&lt;/a&gt; to run the Ender 3 Pro as a 3D printer. It&#039;s possible to run a laser in this configuration by plugging it into FAN1, the header for the part cooling fan. This is a 24V PWM signal with a pretty low frequency that you can probably increase by uncommenting &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;FAST_PWM_FAN&lt;/span&gt;. However, I wanted Marlin to actually understand that this is a laser to improve the LCD interface and make sure I&#039;m getting anything Marlin can do to optimize the results. So the first thing I did was just take a pass through &#039;Configuration.h&#039; and &#039;Configuration_adv.h&#039; making the obvious changes (&lt;a href=&quot;https://github.com/BrianMacIntosh/Marlin/commit/592b62a444027b9a878ba73e80c81421cc9c9ad3&quot;&gt;diffs&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Commenting/disabling the extruder axis&lt;/li&gt;
&lt;li&gt;Disabling the heaters and temperature sensors&lt;/li&gt;
&lt;li&gt;Disabling the status screen images except &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;STATUS_CUTTER_ANIM&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Most importantly, enabling &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;LASER_FEATURE&lt;/span&gt; and &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;LASER_POWER_INLINE&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This will actually work just work as far as Marlin is concerned, but I didn&#039;t know that at this point, because Marlin is actually no longer sending the laser PWM signal to the FAN1 header. This is because it would like to use the chip&#039;s faster hardware PWM for the laser instead of the slower software PWM it uses for the fan. Instead, it&#039;s actually moved the X stepper to the E stepper header, and it&#039;s sending the laser signals to the X stepper driver. For more info on this, see the bottom of &#039;pins_SANGUINOLOLU_11.h&#039;.&lt;/p&gt;
&lt;p&gt;Unfortunately we can&#039;t pick those signals up from the X stepper header because there&#039;s a stepper driver between the header and the board, and we can&#039;t easily remove the driver on this board (unlike some other boards that have socketed drivers). We have to follow the traces and find another spot on the PCB to pick it up. The laser PWM is configured in &#039;pins_SANGUINOLOLU_11.h&#039; to come from pin 16 (PD7) on the microcontroller. I used the microcontroller &lt;a href=&quot;https://ww1.microchip.com/downloads/en/DeviceDoc/doc8059.pdf&quot;&gt;datasheet&lt;/a&gt; to locate that pin, then used the PCB images from &lt;a href=&quot;https://github.com/Creality3DPrinting/Ender-3/blob/master/Ender-3%20PCB/Ender3_pcb_parts.PDF&quot;&gt;GitHub&lt;/a&gt; to follow the trace. I highlighted the trace in green below, and chose the via marked in red as the best place to insert a wire.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/ender3-pd7.png&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/ender3-pd7-thumb.png&quot; alt=&quot;Diagram of the traces of Ender 3 mainboard.&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Power up the board with just the LCD attached and use a voltmeter to test the voltage between the via and ground with the laser on and off to make sure you have the right one. I cut the end off a female Dupont connector (28 AWG) and soldered it through the via.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/ender3_pcb_laser.jpg&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/ender3_pcb_laser_thumb.jpg&quot; alt=&quot;Photo showing laser power and control wires attached to the Ender 3 mainboard.&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&#039;m using a 24V laser, so I&#039;m giving it 24V from the FAN1 header. I &lt;a href=&quot;https://github.com/BrianMacIntosh/Marlin/commit/bfbc01a94ae75481492d0898d43208fa73ba2229&quot;&gt;commented&lt;/a&gt; the FAN_PIN definitions from Marlin in order to get an always-on 24V from the fan headers. You could probably pick up 5V from an unused two-pin header or 12V from the bed terminals if that&#039;s what your laser requires.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/ender3_laser.jpg&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/ender3_laser_thumb.jpg&quot; alt=&quot;Photo showing laser power and control wires attached to the laser module.&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I tested the laser using this wiring, and it was on when enabled, off when disabled, and respected the configured power output percentage, so I think the electronic configuration is good to go.&lt;/p&gt;</description><pubDate>Sun, 26 Dec 2021 19:04:39 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Unity UI Gradient Shader v2</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=104</guid><link>https://brianmacintosh.com/blog/comments.php?post=104</link><description>&lt;p&gt;Some time ago, I shared a &lt;a href=&quot;https://www.brianmacintosh.com/blog/comments.php?post=94&quot;&gt;Unity shader&lt;/a&gt; for coloring a Unity UI element with a 2D gradient. That post seems to get a lot of traffic, so I thought I should share my improved version as well.&lt;/p&gt;
&lt;p&gt;The original shader uses the first UV channel to distribute the gradient color, which means it only works well with the Simple image type. The other Image types do funny things with that UV channel. To solve this, I created a special version of the &lt;b&gt;Image&lt;/b&gt; component that also produces a second UV channel. The second channel is always evenly distributed over the entire image, regardless of the Image Type.&lt;/p&gt;
&lt;p&gt;Get the new component and shader &lt;a href=&quot;https://gist.github.com/BrianMacIntosh/23275e79bb7489b42ad4ac0916a56824&quot;&gt;here on GitHib&lt;/a&gt;. My shader and modifications are free to use, but the Image source code is subject to the &lt;a href=&quot;https://unity3d.com/legal/licenses/Unity_Reference_Only_License/&quot;&gt;Unity Reference-Only License&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/unity-gradient2.png&quot; alt=&quot;Comparison of the new and old gradient shaders.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Future work could add support for the Tiled and Filled image types as well.&lt;/p&gt;</description><pubDate>Thu, 04 Mar 2021 13:06:17 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Troubleshooting Ender 3 Pro Firmware Update</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=103</guid><link>https://brianmacintosh.com/blog/comments.php?post=103</link><description>&lt;p&gt;I recently installed Marlin firmware on my 3D printer (an Ender 3 Pro, 1.1.4 mainboard) so I could increase the size of the build space. You can find several step-by-step guides on how to do this online, and I used &lt;a href=&quot;https://howchoo.com/ender3/ender-3-bootloader-firmware-update-marlin&quot;&gt;this one from Howchoo&lt;/a&gt;. It was, on the whole, very helpful, but I had to troubleshoot several unexpected issues along the way (and you should definitely expect to, also). I&#039;m documenting them for anyone else who wants to follow the linked guide with an Ender 3 Pro. I was using a Windows 10 computer.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Wiring the Arduino (Howchoo step 5):&lt;/b&gt; don&#039;t forget to wire the Reset pin on the printer board to the ~10 pin on the Arduino. This isn&#039;t super clearly depicted in the pictures. If you don&#039;t do this, you&#039;ll see an error like this when burning the bootloader:&lt;/p&gt;

&lt;code class=&quot;codeblock&quot;&gt;&lt;pre&gt;
avrdude: Yikes!  Invalid device signature.
         Double check connections and try again, or use -F to override
         this check.

Error while burning bootloader.
&lt;/pre&gt;&lt;/code&gt;

&lt;p&gt;&lt;b&gt;Compiling Marlin (Howchoo step 8):&lt;/b&gt; when I did this, the current version of the Arduino IDE was incapable of linking the current version of Marlin. This was because it was attempting to make a long shell call to the linker that exceeded Windows&#039; maximum length. You&#039;ll see the following error message in the Arduino IDE after clicking &quot;Verify&quot; or &quot;Upload&quot; if this happens:&lt;/p&gt;

&lt;code class=&quot;codeblock&quot;&gt;&lt;pre&gt;
fork/exec C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-gcc.exe: The filename or extension is too long.
Error compiling for board Sanguino.
&lt;/pre&gt;&lt;/code&gt;

&lt;p&gt;As the call was largely using relative paths, I saw no way to easily reduce its length. Fortunately, there are plenty of other ways to compile and upload firmware (all of them are essentially wrappers around a compiler such as gcc and the uploader, avrdude, by the way), so at this point, I ditched Arduino and switched to following &lt;a href=&quot;https://marlinfw.org/docs/basics/install_platformio_vscode.html&quot;&gt;this guide from Marlin&lt;/a&gt; using Visual Studio Code.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;PlatformIO Environment (Marlin step 2):&lt;/b&gt; the default_envs for the Ender 3 Pro in this configuration is &lt;b&gt;melzi_optiboot&lt;/b&gt;. If you get this wrong you might see a series of errors like this on upload (the trailing hex value will vary):&lt;/p&gt;

&lt;code class=&quot;codeblock&quot;&gt;&lt;pre&gt;
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x00
&lt;/pre&gt;&lt;/code&gt;

&lt;p&gt;&lt;b&gt;Uploading firmware (Marlin step 2 [okay, like this entire tutorial is in step 2]):&lt;/b&gt; If you haven&#039;t (successfully) connected your printer to a computer via USB before, you might need to install drivers. If that&#039;s the case, you won&#039;t see the Ender in Device Manager (under Ports) or under the Arduino IDE&#039;s Ports list. PlatformIO might give you an error like this on upload:&lt;/p&gt;

&lt;code class=&quot;codeblock&quot;&gt;&lt;pre&gt;
Error: Please specify upload_port for environment or use global --upload-port option.
&lt;/pre&gt;&lt;/code&gt;

&lt;p&gt;All the Ender 3 Pro boards use the CH340 drivers, which you can find &lt;a href=&quot;https://support.th3dstudio.com/hc/downloads/drivers/ch340-drivers-th3d-uno-creality-v1-1-x-v4-2-x-board/&quot;&gt;here&lt;/a&gt;. Always restart your computer after installing drivers.&lt;/p&gt;</description><pubDate>Sat, 06 Feb 2021 15:35:37 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Ludum Dare 46 - The Wrecker</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=102</guid><link>https://brianmacintosh.com/blog/comments.php?post=102</link><description>&lt;p&gt;It&#039;s been a few Ludum Dares since I participated, but last weekend I jumped in for the Ludum Dare 46 with audio designer Christian Camargo. This Dare saw a big spike in participation this time around, probably due to the stay-at-home orders in many places. The theme was &quot;Keep it Alive&quot;. We worked in Unity with Wwise.&lt;/p&gt;
&lt;p&gt;After starting, as always, by spamming a heap of ideas out on (virtual) paper, I started trying to mash two or more of the ideas together into a hybrid idea. &quot;The Wrecker&quot; was born from the union of a game about a factory poisoning a town, and my recent playthrough of Red Faction: Guerrilla and love for its granular destruction systems. We also grabbed two other elements from the doc we wanted to include: a time limit to push the player forward, and the idea that the player is also dying and needs to prioritize their own health against that of the town. That more than was enough to get started!&lt;/p&gt;
&lt;p class=&quot;centeralign&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/ld46_thewrecker.png&quot; alt=&quot;&#039;The Wrecker&#039; logo&quot;&gt;&lt;/p&gt;
&lt;h2&gt;What We Learned&lt;/h2&gt;
&lt;h3&gt;Wwise&lt;/h3&gt;
&lt;p&gt;The decision to use Wwise for our audio had some pros and cons. Despite being relatively unfamiliar with it as the programmer of the team, I was able to hook in pretty easily by making a single call to posting a string-named event when audio cues should be played or stopped. Christian was able to do a lot of customization in Wwise, such as randomizing the sounds played and their parameters, that I didn&#039;t need to implement.&lt;/p&gt;
&lt;p&gt;On the down side, however, Wwise did not play nicely with Unity&#039;s Collab source control, which only synchronizes the Unity project data and did not understand that there was also a Wwise project to synchronize. This effectively siloed off the audio work until we manually transfered the project, and I didn&#039;t hear most of the audio until a few hours before the deadline. Theoretically, Wwise is capable of building audio banks into the project that could be synced, but in the jam crunch we never got that working.&lt;p&gt;
&lt;p&gt;I also discovered late on Saturday (making an early test build to catch any build problems - I definitely recommend it) that WWise is not compatible with Unity WebGL builds, which are the optimal way to get Ludum Dare raters into the game quickly. Fortunately this does not appear to be affecting our ability to get ratings.&lt;/p&gt;
&lt;h3&gt;Physics Gameplay&lt;/h3&gt;
&lt;p class=&quot;centeralign&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/ld46_screen01.jpg&quot; alt=&quot;Screenshot of the player smashing down some walls.&quot;&gt;&lt;/p&gt;
&lt;p&gt;I chose to implement the game&#039;s progression through three different weapons, each capable of breaking more objects than the last, and only the final weapon was able to break through the doors into the factory. It&#039;s a pretty time-honored design. However, I opted to implement the destruction with Unity&#039;s breakable physics joint system, in which each joint has a specified Break Force.&lt;/p&gt;
&lt;p&gt;This was a quick way to get everything up and running, but the result was a huge number of breakable joints scattered throughout the game&#039;s prefabs, many of which needed to be carefully balanced so they were only breakable by the appropriate weapon. Any change to physics parameters, such as the player&#039;s movement speed or weapon swing speed, could throw off everything. If I did this over, I would probably try to implement explicit, hard limitations on which objects can be broken by which weapons rather than relying on the implicit interactions of the physics engine to gate crit-path gameplay.&lt;/p&gt;
&lt;h3&gt;Vector Graphics&lt;/h3&gt;
&lt;p class=&quot;centeralign&quot;&gt;&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/ld46_artboard.jpg&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/ld46_artboard_thumb.jpg&quot; alt=&quot;Adobe Illustrator artboard containing game graphics.&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I used Adobe Illustrator to produce all the art for the game. This was very efficient, and I was able to turn out assets incredibly quickly and get back to coding. I made all the assets on two artboards (Game and UI), which made it quick and easy to ensure everything was at a consistent scale and stroke width. I used a simple visual language that I think contributes significantly to the game&#039;s clean look - collidable objects have a black stroke and background objects have none. Additionally, control prompts are always a key in a rounded white rectangle.&lt;/p&gt;
&lt;br&gt;
&lt;p&gt;If you haven&#039;t check out the game yet, you can download it for free &lt;a href=&quot;https://www.brianmacintosh.com/projects/ld46/LD46_TheWrecker.zip&quot;&gt;from this link&lt;/a&gt;, or watch a video &lt;a href=&quot;https://youtu.be/syinomsV-po&quot;&gt;right over here&lt;/a&gt;! If you are a Ludum Dare participant, you can rate the game at its &lt;a href=&quot;https://ldjam.com/events/ludum-dare/46/the-wrecker&quot;&gt;Ludum Dare page&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Tue, 28 Apr 2020 02:45:46 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>How I make infinite procedural swords</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=101</guid><link>https://brianmacintosh.com/blog/comments.php?post=101</link><description>&lt;p&gt;If you haven&#039;t seen my &lt;a href=&quot;https://www.brianmacintosh.com/iconmachine?class=blades&quot;&gt;procedural sword generator&lt;/a&gt;, you can check it out at that link.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/iconmachine?class=blades&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/procswords2.png&quot; alt=&quot;Four randomly-generated sword sprites.&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is a custom algorithm written specifically to produce swords - not using any kind of generic machine-learning. I&#039;m pretty happy with the amount of variety it can produce - each piece (the blade shape, the crossguard, the hilt, and the pommel) is generated from scratch from a variety of randomized parameters. So how does it work?&lt;/p&gt;
&lt;h2&gt;Process Note&lt;/h2&gt;
&lt;p&gt;I usually start a procgen project by trying to draw the thing I&#039;m making by hand. This helps me analyze how it&#039;s made - in particular, how colors combine and where shadows and highlights go. After a quick web search for &quot;pixel art sword&quot; and some experimentation and iteration, I came up with this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/demopixelsword.png&quot; alt=&quot;Simple, hand-drawn pixel art sword sprite.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Pretty basic, but it helped me figure out how to color the blade (a key part of the art I was unsure about) with a light half and a dark half, a gradient that starts dark at the hilt and runs up the blade, and a rim of very light pixels to hint at &quot;sharpness&quot;.
&lt;h2&gt;The Algorithm&lt;/h2&gt;
&lt;p&gt;You can follow along in the &lt;a href=&quot;https://www.brianmacintosh.com/iconmachine/random.js&quot;&gt;Javascript source code&lt;/a&gt; (drawRandomBlade function) if you&#039;d like to see more implementation details.&lt;/p&gt;
&lt;p&gt;Off the top, I randomize and calculate a bunch of values within ranges I set (and tweaked over time), such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The pommel, hilt, crossguard, and blade lengths&lt;/li&gt;
&lt;li&gt;The blade&#039;s start width and taper&lt;/li&gt;
&lt;li&gt;The blade&#039;s chance to acquire a &quot;jog&quot; or a &quot;curve&quot;, and the max magnitude of those&lt;/li&gt;
&lt;li&gt;Parameters for a cosine wave that can vary the blade&#039;s width&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, I generate the shape of the blade. I start where the top of the crossguard is going to be with a forward angle of 45 degrees, then step forward one pixel at a time. Each time, I push the point into an array, along with some metadata like the current direction, how far along the blade it is, and the width at that point (which can vary based on the cosine wave I mentioned before). After recording the point, I randomly check to see if the blade should &quot;jog&quot;, making a sharp angle, or acquire a curve. Then, move on to the next point.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/procswords_controlpoints.png&quot; alt=&quot;A curved line showing the generated sword shape.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now I actually render the blade. Walking along the control points drawing segments is intuitive, but it seemed tricky to make sure the space between each segment gets filled in properly. So instead, I actually iterate over every pixel in the image. I determine which control point is closest to that pixel, then check the distance to it. If it&#039;s within the blade&#039;s radius, we&#039;ll draw it.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Color:&lt;/b&gt; here&#039;s how I decide what color a blade pixel will be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the point metadata, I previously saved a &lt;b&gt;normal&lt;/b&gt; vector that points to the &quot;left&quot; of the control point. I can do a &lt;b&gt;dot product&lt;/b&gt; between that and the vector between the pixel and the control point to figure out if it&#039;s on the left or right side of the blade. I pick the light color or the dark color based on that.&lt;/li&gt;
&lt;li&gt;Darken the color based on how far along the blade the control point is (another value I stored in the metadata).&lt;/li&gt;
&lt;li&gt;If the pixel is very close to the edge of the blade (i.e. the distance between it and the control point is close to the blade width), I blend in the very light &quot;edge&quot; color.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For most of these operations, I&#039;m using &lt;b&gt;linear interpolation&lt;/b&gt; to blend two different colors together.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/procswords_blade.png&quot; alt=&quot;Only the blade of a random sword.&quot;&gt;&lt;br&gt;
&lt;i&gt;It&#039;s not the same sword, sorry, I don&#039;t have seeding yet.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Next, it&#039;s on to the hilt. This is much simpler: I generate another cosine wave to control the lines of the grip, a width, and a color. When randomizing colors, I usually work in HSV and convert to RGB before drawing because I&#039;m not so interested in controlling how red or green or blue the color is, but I&#039;m much more interesting in controlling how bright (V) and how colorful (S) it is. In this case I make sure the color has a high V so it has room to get darker to make shadows.&lt;/p&gt;
&lt;p&gt;Then I just walk along the hilt drawing slices. There is some rounding trickery to make sure I get all the pixels filled in nicely. The color of each pixel is based on the value of a cosine wave, and darkened somewhat toward the right side.&lt;/p&gt;
&lt;p&gt;Now the crossguard. The process for this is nearly the same as that for the blade - just in a different direction. I generate two different curves for the left and right parts, but with a high probability I just discard one of them and use the other, mirrored.&lt;/p&gt;
&lt;p&gt;Finally, the pommel. I was getting itchy to share my work at this point, so I didn&#039;t do too much here. Just generate a random radius, and draw a circle in the same color as the crossguard that&#039;s shaded darker to the bottom-right and lighter to the top-left.&lt;/p&gt;
&lt;p&gt;Oh, and the black border is added here at the very end. Any pixel that&#039;s empty or at the edge of the canvas, and orthogonally adjacent to a filled pixel, gets filled in black.&lt;/p&gt;
&lt;p&gt;I hope that gives you some interesting ideas! Since you made it through all that, here&#039;s a gif of the process:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/procsword.gif&quot; alt=&quot;An animation of a sword being drawn pixel-by-pixel.&quot;&gt;&lt;/p&gt;</description><pubDate>Sun, 26 Jan 2020 20:21:39 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Infinite Sword and Blade Sprites</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=100</guid><link>https://brianmacintosh.com/blog/comments.php?post=100</link><description>&lt;p&gt;A few years ago, I made a web app that generated unlimited procedural potion icons. I&#039;ve just expanded that with a new module that generates swords (well...bladed weapons, anyway). Generated icons are free for your use!&lt;/p&gt;
&lt;a href=&quot;https://www.brianmacintosh.com/iconmachine?class=blades&quot;&gt;&lt;p&gt;Icon Machine&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/procswords.png&quot; alt=&quot;A grid of procedurally-generated swords&quot;&gt;&lt;/p&gt;&lt;/a&gt;</description><pubDate>Sat, 25 Jan 2020 23:40:59 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>No BeginPlay calls in Unreal 4? Here&#039;s why.</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=99</guid><link>https://brianmacintosh.com/blog/comments.php?post=99</link><description>&lt;p&gt;Here&#039;s a strange and difficult-to-track-down bug that happened to me, so I wanted to share the solution in case someone else who needs it might find it. You&#039;re working in Unreal and suddenly none of your actors are receiving BeginPlay. This breaks your game.&lt;/p&gt;
&lt;p&gt;If you search for this, you&#039;ll find a lot of people who overrode BeginPlay and forgot to include a call to Super (C++) or Parent (Blueprints). That will cause the BeginPlays of that object&#039;s parents to not be called, and is definitely a common and subtle bug. But what if it&#039;s happening to all your actors, even ones that have no inheriting children?&lt;/p&gt;
&lt;p&gt;I only found this in &lt;a href=&quot;https://www.youtube.com/watch?v=drGgjgQE2Gk&quot;&gt;a single YouTube video&lt;/a&gt;, which fortunately had the answer - when creating custom Game States or Game Modes, you must consistently inherit from &lt;b&gt;AGameStateBase&lt;/b&gt; and &lt;b&gt;AGameModeBase&lt;/b&gt; or &lt;b&gt;AGameState&lt;/b&gt; and &lt;b&gt;AGameMode&lt;/b&gt;. You can&#039;t mix and match them, or you will break the code that calls BeginPlay, which lives in the game mode.&lt;/p&gt;
&lt;p&gt;Which should you use? According to the header, &lt;b&gt;AGameState&lt;/b&gt; and &lt;b&gt;AGameMode&lt;/b&gt; are intended for use with match-based multiplayer games. So if you&#039;re making one of those, use them, otherwise, use the Base ones.&lt;/p&gt;
</description><pubDate>Sun, 22 Dec 2019 12:41:51 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Periodic Deliveries Postmortem - Time-Saving Tricks</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=98</guid><link>https://brianmacintosh.com/blog/comments.php?post=98</link><description>&lt;p&gt;I&#039;m releasing a Unity 2018 game called &lt;a href=&quot;https://store.steampowered.com/app/1176580/Periodic_Deliveries/&quot;&gt;Periodic Deliveries&lt;/a&gt;! Development of any game is fraught with little speedbump tasks that slowly soak up dev time and make it a little less fun, too. Here are a few tricks I did to knock out some of those bumps in my process that you can easily implement in your Unity projects, too.&lt;/p&gt;

&lt;h3&gt;Use the MenuItem attribute to create developer cheats&lt;/h3&gt;
&lt;p&gt;In a larger game with a larger team, you might implement a developer console you can activate with a key press and type commands into. That will scale well if you have a lot of commands, and it will work in standalone builds. But if your game is small, this is a quick and effective approach. Quick implementation is important because it will encourage you to add cheats more often, and those will save you time as development goes on.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://brianmacintosh.com/blog/images/pd_cheatmenu.png&quot; alt=&quot;Screenshot of a dropdown menu containing cheat commands&quot;&gt;&lt;/p&gt;
&lt;p&gt;I put them all in a static class called &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;CheatCommands&lt;/span&gt;. Don&#039;t forget to add a validation function, which will disable the option when it doesn&#039;t make sense and improve your own experience.&lt;/p&gt;

&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;static&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;class&lt;/span&gt; CheatCommands
&lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt;
	&lt;span style=&#039;color:#808030; &#039;&gt;[&lt;/span&gt;MenuItem&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#800000; &#039;&gt;&quot;&lt;/span&gt;&lt;span style=&#039;color:#0000e6; &#039;&gt;Cheats/Infinity Money&lt;/span&gt;&lt;span style=&#039;color:#800000; &#039;&gt;&quot;&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;,&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;true&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;]&lt;/span&gt;
	&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;static&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;bool&lt;/span&gt; ValidateInfinityMoney&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;
	&lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt;
		&lt;span style=&#039;color:#696969; &#039;&gt;// Disables the item in Edit Mode and in the Main Menu&lt;/span&gt;
		&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;return&lt;/span&gt; InGameManager&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;Instance&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;PlayerCompany &lt;span style=&#039;color:#808030; &#039;&gt;!&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;null&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;
	&lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;

	&lt;span style=&#039;color:#808030; &#039;&gt;[&lt;/span&gt;MenuItem&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#800000; &#039;&gt;&quot;&lt;/span&gt;&lt;span style=&#039;color:#0000e6; &#039;&gt;Cheats/Infinity Money&lt;/span&gt;&lt;span style=&#039;color:#800000; &#039;&gt;&quot;&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;]&lt;/span&gt;
	&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;static&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;void&lt;/span&gt; InfinityMoney&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;
	&lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt;
		InGameManager&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;Instance&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;PlayerCompany&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;AddMoney&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;PeriodicInt&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;PositiveInfinity&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;
	&lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;
	
	&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;
&lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;!--Created using ToHtml.com on 2020-01-04 18:21:32 UTC --&gt;
&lt;/code&gt;

&lt;h3&gt;Make custom property drawers for structs that show up in the Inspector&lt;/h3&gt;
&lt;p&gt;Using &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;Serializable&lt;/span&gt; structs for common data patterns can help you avoid writing similar code multiple times. But you&#039;ll have to expand a foldout every time you want to edit this data in the Inspector. If you can write a custom property drawer quickly, you can save yourself a lot of clicks over the entire development of your project.&lt;/p&gt;
&lt;p&gt;Here is a base class for a common property drawer I used several times. You can inherit from it to create a custom property drawer for any struct that represents a &quot;quantity&quot; of a &quot;thing&quot; (like a stack of items in a loot container, or an ingredient requirement in a recipe).&lt;/p&gt;

&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;using&lt;/span&gt; UnityEditor&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;
&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;using&lt;/span&gt; UnityEngine&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;

&lt;span style=&#039;color:#696969; &#039;&gt;// Author: Brian MacIntosh (The Periodic Group)&lt;/span&gt;
&lt;span style=&#039;color:#696969; &#039;&gt;// MIT License&lt;/span&gt;

&lt;span style=&#039;color:#696969; &#039;&gt;/// &amp;lt;summary&gt;&lt;/span&gt;
&lt;span style=&#039;color:#696969; &#039;&gt;/// Base class that can be extended to quickly create a property drawer for a structure containing&lt;/span&gt;
&lt;span style=&#039;color:#696969; &#039;&gt;/// data like &quot;quantity&quot; of &quot;thing&quot;.&lt;/span&gt;
&lt;span style=&#039;color:#696969; &#039;&gt;/// &amp;lt;/summary&gt;&lt;/span&gt;
&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;abstract&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;class&lt;/span&gt; ItemQuantityPropertyDrawer &lt;span style=&#039;color:#808030; &#039;&gt;:&lt;/span&gt; PropertyDrawer
&lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt;
	&lt;span style=&#039;color:#696969; &#039;&gt;/// &amp;lt;summary&gt;&lt;/span&gt;
	&lt;span style=&#039;color:#696969; &#039;&gt;/// Name of the quantity/stack size property.&lt;/span&gt;
	&lt;span style=&#039;color:#696969; &#039;&gt;/// &amp;lt;/summary&gt;&lt;/span&gt;
	&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;abstract&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;string&lt;/span&gt; QuantityPropName &lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;get&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt; &lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;

	&lt;span style=&#039;color:#696969; &#039;&gt;/// &amp;lt;summary&gt;&lt;/span&gt;
	&lt;span style=&#039;color:#696969; &#039;&gt;/// Name of the item/object property.&lt;/span&gt;
	&lt;span style=&#039;color:#696969; &#039;&gt;/// &amp;lt;/summary&gt;&lt;/span&gt;
	&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;abstract&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;string&lt;/span&gt; ItemPropName &lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;get&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt; &lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;

	&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;override&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;void&lt;/span&gt; OnGUI&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;Rect position&lt;span style=&#039;color:#808030; &#039;&gt;,&lt;/span&gt; SerializedProperty property&lt;span style=&#039;color:#808030; &#039;&gt;,&lt;/span&gt; GUIContent label&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;
	&lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt;
		EditorGUI&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;BeginProperty&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;position&lt;span style=&#039;color:#808030; &#039;&gt;,&lt;/span&gt; label&lt;span style=&#039;color:#808030; &#039;&gt;,&lt;/span&gt; property&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;

		position &lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt; EditorGUI&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;PrefixLabel&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;position&lt;span style=&#039;color:#808030; &#039;&gt;,&lt;/span&gt; GUIUtility&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;GetControlID&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;FocusType&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;Passive&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;,&lt;/span&gt; label&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;

		&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;int&lt;/span&gt; indent &lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt; EditorGUI&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;indentLevel&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;
		EditorGUI&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;indentLevel &lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt; &lt;span style=&#039;color:#008c00; &#039;&gt;0&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;

		Rect quantityPosition &lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt; position&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;
		quantityPosition&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;width &lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt; 40f&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;
		Rect resourcePosition &lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt; position&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;
		resourcePosition&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;xMin &lt;span style=&#039;color:#808030; &#039;&gt;+&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt; quantityPosition&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;width &lt;span style=&#039;color:#808030; &#039;&gt;+&lt;/span&gt; 4f&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;
		EditorGUI&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;PropertyField&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;quantityPosition&lt;span style=&#039;color:#808030; &#039;&gt;,&lt;/span&gt; property&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;FindPropertyRelative&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;QuantityPropName&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;,&lt;/span&gt; GUIContent&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;none&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;
		EditorGUI&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;PropertyField&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;resourcePosition&lt;span style=&#039;color:#808030; &#039;&gt;,&lt;/span&gt; property&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;FindPropertyRelative&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;ItemPropName&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;,&lt;/span&gt; GUIContent&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;none&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;

		EditorGUI&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;indentLevel &lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt; indent&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;

		EditorGUI&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;EndProperty&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;
	&lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;
&lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/code&gt;
&lt;p&gt;Alternatively, get it from &lt;a href=&quot;https://gist.github.com/BrianMacIntosh/94afe7e08b3c0edd75d71a6d59d41d1b&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here&#039;s an example use:&lt;/p&gt;

&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;&lt;span style=&#039;color:#696969; &#039;&gt;//RecipeComponent.cs&lt;/span&gt;

&lt;span style=&#039;color:#808030; &#039;&gt;[&lt;/span&gt;Serializable&lt;span style=&#039;color:#808030; &#039;&gt;]&lt;/span&gt;
&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;class&lt;/span&gt; RecipeComponent
&lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt;
	&lt;span style=&#039;color:#808030; &#039;&gt;[&lt;/span&gt;Tooltip&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#800000; &#039;&gt;&quot;&lt;/span&gt;&lt;span style=&#039;color:#0000e6; &#039;&gt;The resource.&lt;/span&gt;&lt;span style=&#039;color:#800000; &#039;&gt;&quot;&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;]&lt;/span&gt;
	&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; ResourceData Resource&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;

	&lt;span style=&#039;color:#808030; &#039;&gt;[&lt;/span&gt;Tooltip&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#800000; &#039;&gt;&quot;&lt;/span&gt;&lt;span style=&#039;color:#0000e6; &#039;&gt;The quantity of the resource.&lt;/span&gt;&lt;span style=&#039;color:#800000; &#039;&gt;&quot;&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;]&lt;/span&gt;
	&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;int&lt;/span&gt; Quantity &lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt; &lt;span style=&#039;color:#008c00; &#039;&gt;1&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;

	&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; RecipeComponent&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;ResourceData resource&lt;span style=&#039;color:#808030; &#039;&gt;,&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;int&lt;/span&gt; quantity&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;
	&lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt;
		Resource &lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt; resource&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;
		Quantity &lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt; quantity&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;
	&lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;

	&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;override&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;string&lt;/span&gt; ToString&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;
	&lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt;
		&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;return&lt;/span&gt; Quantity&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;ToString&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt; &lt;span style=&#039;color:#808030; &#039;&gt;+&lt;/span&gt; &lt;span style=&#039;color:#800000; &#039;&gt;&quot;&lt;/span&gt;&lt;span style=&#039;color:#0000e6; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#800000; &#039;&gt;&quot;&lt;/span&gt; &lt;span style=&#039;color:#808030; &#039;&gt;+&lt;/span&gt; Resource&lt;span style=&#039;color:#808030; &#039;&gt;.&lt;/span&gt;name&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;
	&lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;
&lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;!--Created using ToHtml.com on 2020-01-04 18:21:50 UTC --&gt;
&lt;/code&gt;

&lt;code class=&quot;codeblock&quot;&gt;
&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;&lt;span style=&#039;color:#696969; &#039;&gt;//RecipeComponentPropertyDrawer.cs&lt;/span&gt;

&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;using&lt;/span&gt; UnityEditor&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;

&lt;span style=&#039;color:#808030; &#039;&gt;[&lt;/span&gt;CustomPropertyDrawer&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;typeof&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;(&lt;/span&gt;RecipeComponent&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;)&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;]&lt;/span&gt;
&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;class&lt;/span&gt; RecipeComponentPropertyDrawer &lt;span style=&#039;color:#808030; &#039;&gt;:&lt;/span&gt; ItemQuantityPropertyDrawer
&lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt;
	&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;override&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;string&lt;/span&gt; ItemPropName
	&lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt;
		&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;get&lt;/span&gt; &lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;return&lt;/span&gt; &lt;span style=&#039;color:#800000; &#039;&gt;&quot;&lt;/span&gt;&lt;span style=&#039;color:#0000e6; &#039;&gt;Resource&lt;/span&gt;&lt;span style=&#039;color:#800000; &#039;&gt;&quot;&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt; &lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;
	&lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;

	&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;public&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;override&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;string&lt;/span&gt; QuantityPropName
	&lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt;
		&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;get&lt;/span&gt; &lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt; &lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;return&lt;/span&gt; &lt;span style=&#039;color:#800000; &#039;&gt;&quot;&lt;/span&gt;&lt;span style=&#039;color:#0000e6; &#039;&gt;Quantity&lt;/span&gt;&lt;span style=&#039;color:#800000; &#039;&gt;&quot;&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt; &lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;
	&lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;
&lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;!--Created using ToHtml.com on 2020-01-04 18:22:32 UTC --&gt;
&lt;/code&gt;

&lt;h3&gt;Separate your code files into &#039;Game&#039; and &#039;SDK&#039; folders&lt;/h3&gt;
&lt;p&gt;Put any code files that are specific to this game in the &#039;Game&#039; folder. Put any code files that might be useful on your future games in the &#039;SDK&#039; folder. The idea here is to create a folder that you can literally copy and paste into your next project (or you can use a &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Tools-Submodules&quot;&gt;git submodule&lt;/a&gt; if you jump back and forth between a lot of projects).&lt;/p&gt;
&lt;p&gt;You need to follow one rule to make this work: &lt;b&gt;&lt;i&gt;code in the &#039;SDK&#039; folder can never reference code in the &#039;Game&#039; folder&lt;/i&gt;&lt;/b&gt;. If this happens, either (1) rework your SDK code so the Game code can insert its own behavior - for example, provide an event it can subscribe to, or virtual methods it can override - or (2) put that code in the Game folder.&lt;/p&gt;
&lt;p&gt;My SDK folder contains things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Static classes full of utility functions (&lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;MathUtility&lt;/span&gt;, &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;ListUtility&lt;/span&gt;, etc).&lt;/li&gt;
&lt;li&gt;The abstract property drawer above (in an Editor subfolder).&lt;/li&gt;
&lt;li&gt;My generic input context system.&lt;/li&gt;
&lt;li&gt;Generic helper components, like &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;PositionAtMouse&lt;/span&gt;, &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;MirrorColor&lt;/span&gt;, &lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;GameObjectPool&lt;/span&gt;...&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If do this, you will write better, reusable code and save yourself time debugging this project and implementing these functions on the next.&lt;/p&gt;

&lt;h3&gt;Use a GlobalData ScriptableObject&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;font-family:Consolas,monospace&quot;&gt;ScriptableObject&lt;/span&gt;s are a great tool for organizing data. I like creating a scriptable object for each item, ability, and other such thing in my game to hold all the data associated with it. On Periodic Deliveries, I also created a monolithic &#039;GlobalData&#039; object. This object holds all those global configuration options that usually end up throughout the project on various manager components and code constants. Putting them in one place meant I never had to spend time tracking down where so particular value was. The scriptable object also diffs much better in source control than a component in a scene, in case you need to look back through the history.&lt;/p&gt;

&lt;p&gt;The GlobalData object can be held on a global singleton component somewhere, or maybe loaded with the new Addressable Asset system (I haven&#039;t played with it yet).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://brianmacintosh.com/blog/images/pd_globaldata.png&quot; alt=&quot;Screenshot of the Global Data object inspector&quot;&gt;&lt;/p&gt;

&lt;p&gt;I hope some of these tips can make your development a little faster and more fun. If you&#039;re into space, simulation, or management games, don&#039;t forget to check out &lt;a href=&quot;https://store.steampowered.com/app/1176580/Periodic_Deliveries/&quot;&gt;Periodic Deliveries&lt;/a&gt; on Steam!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://store.steampowered.com/app/1176580/Periodic_Deliveries/&quot;&gt;&lt;video autoplay loop muted width=&quot;640&quot; height=&quot;360&quot;&gt;&lt;source src=&quot;https://www.brianmacintosh.com/blog/images/periodic_deliveries_02.mp4&quot; type=&quot;video/mp4&quot;&gt;&lt;/video&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Mon, 09 Dec 2019 00:21:55 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Periodic Deliveries - Steam Release!</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=96</guid><link>https://brianmacintosh.com/blog/comments.php?post=96</link><description>&lt;p&gt;Way back in &lt;a href=&quot;http://ludumdare.com/compo/ludum-dare-30/?action=preview&amp;uid=15030&quot;&gt;Ludum Dare 30&lt;/a&gt; Justin Britch and I made a game called Space Transport Tycoon (which you can still &lt;a href=&quot;http://brianmacintosh.com/projects/ld30/&quot;&gt;play in your browser for free&lt;/a&gt;. Four years later, we still remember it fondly as the the game we spent the most time actually playing after making it. This year, we finally resurrected it as &lt;a href=&quot;https://store.steampowered.com/app/1176580/Periodic_Deliveries/&quot;&gt;Periodic Deliveries&lt;/a&gt; and we&#039;re publishing it on December 17th on Steam!&lt;/p&gt;
&lt;p&gt;Check out this before-and-after:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/stt1.png&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/stt1_thumb.jpg&quot; alt=&quot;Space Transport Tycoon screenshot&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;video autoplay loop muted width=&quot;640&quot; height=&quot;360&quot; poster=&quot;https://www.brianmacintosh.com/blog/images/periodic_deliveries_01.png&quot;&gt;&lt;source src=&quot;https://www.brianmacintosh.com/blog/images/periodic_deliveries_01.mp4&quot; type=&quot;video/mp4&quot;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;We&#039;ve obviously upgraded the visual quality, thanks to our real artist, John Lewis. The game still features the same core mechanic - configuring trade routes between planets to move certain goods from where they&#039;re produced to where they&#039;re needed - but we changed several peripheral mechanics. In the game jam, I wanted to create a game with multiple views shown simultaneously. That&#039;s how we got the planetary view at the bottom-right, where you could relocate factories to tiles that had more optimal conditions, based on the type of factory. This ended up being one of those features that had a lot of cool stuff in the implementation but didn&#039;t work in practice - it was just a quick chore to do once on each new planet. We removed it to focus on the main view.&lt;/p&gt;
&lt;p&gt;One small change had a big impact: we prohibited trade routes from crossing each other. In Space Transport Tycoon, you&#039;d often build a crisscrossing web of routes that wasn&#039;t terribly satisfying. The new restriction requires the player to use certain planets as hubs and create arterial intermediate routes, which we think is an important and cool part of the shipping fantasy.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/screenshot01.jpg&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/screenshot01_thumb.jpg&quot; alt=&quot;Periodic Deliveries screenshot&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The UI also got a big rework. The old UI was &quot;planet-centric&quot; - that is, you selected a trade route and were presented with a list of every planet on that route, with controls to configure the behavior at each planet. This allows the player to picture everything that happens at a particular planet little more easily, but it requires extra mental steps to think about what happens to a particular good across the entire route - the later being much more useful to the player than the former. The list can also get arbitrarily long, which is kind of a UI nightmare. Periodic Deliveries now uses a goods-centric UI, where the player sees a list of goods that are involved with the route, and configures which planets import or export that good.&lt;/p&gt;
&lt;p&gt;That&#039;s just a few of the larger changes we made for Periodic Deliveries. If it sounds like something you&#039;d like, try out &lt;a href=&quot;http://brianmacintosh.com/projects/ld30/&quot;&gt;Space Transport Tycoon&lt;/a&gt; right now and wishlist Periodic Deliveries below!&lt;p&gt;
&lt;p class=&quot;centeralign&quot;&gt;&lt;iframe title=&quot;Buy Periodic Deliveries on Steam&quot; src=&quot;https://store.steampowered.com/widget/1176580/&quot; frameborder=&quot;0&quot; width=&quot;646&quot; height=&quot;190&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&lt;i&gt;This post has been updated: the explanation of planet-centric vs. goods-centric UI was backwards.&lt;/i&gt;&lt;/p&gt;</description><pubDate>Sat, 07 Dec 2019 16:36:17 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Sizing elements to fit their contents in Unity UI</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=95</guid><link>https://brianmacintosh.com/blog/comments.php?post=95</link><description>&lt;p&gt;You have a UI widget that contains a number of different elements (text, images, etc). These are all children of a background element, which you want to automatically resize to encompass all of these children.&lt;/p&gt;
&lt;p&gt;You read a bunch of forum threads and the &lt;a href=&quot;https://docs.unity3d.com/Manual/HOWTO-UIFitContentSize.html&quot;&gt;documentation&lt;/a&gt; and it just won&#039;t work. Me too. I figured it out, though, so I&#039;m documenting it here. This was written with reference to Unity 2018.3.3.&lt;/p&gt;
&lt;p&gt;To demonstrate, I&#039;ll be creating a tooltip. I&#039;m starting with a naive implementation - a few different widgets that are children of a VerticalLayoutGroup.&lt;/p&gt;
&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/uilayout-01-first-try.png&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/uilayout-01-first-try-thumb.png&quot; alt=&quot;The results of the naive implemention. There are large gaps between the different elements and the background is the wrong size.&quot;&gt;&lt;/a&gt;
&lt;p&gt;The first important concept to understand is the idea of &quot;preferred&quot; size. Preferred size is an internal value that some UI components have (specifically, ones that implement the ILayoutElement interface). It doesn&#039;t have anything to do with any of the values of the RectTransform on that element. Some examples of components that have a preferred size:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Image&lt;/b&gt; - The preferred size is the original size of the sprite being used.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Text&lt;/b&gt; - The preferred size is the size of the actual visible text.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Layout Groups&lt;/b&gt; - The preferred size is the size of the bounds encompassing all of the group&#039;s children.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Layout Element&lt;/b&gt; - Allows you manually set the preferred size for an object.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By default, Layout Groups look at the RectTransform size of their children when deciding how to position them, &lt;i&gt;not&lt;/i&gt; the preferred size&lt;sup&gt;1&lt;/sup&gt;. Remember that for Text components, the visual size of the rendered text is the preferred size, not the RectTransform size. So in order to include Text in a Layout Group and have it respond to the actual rendered text, we need to set the text&#039;s RectTransform size to match its preferred size.&lt;/p&gt;
&lt;p&gt;There is a built-in component for this called ContentSizeFitter. When attached to a GameObject with a UI component on it, it can set the RectTransform size of that object to match the preferred size.&lt;/p&gt;
&lt;p&gt;I&#039;ll attached ContentSizeFitters to each of the Text objects and set the Vertical Fit to &quot;Preferred Size&quot;. You may have to disable and re-enable the VerticalLayoutGroup to get it to refresh. You&#039;ll also see a warning message on the ContentSizeFitter component about the parent layout group, which you can ignore for now (but see footnote 1).&lt;/p&gt;
&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/uilayout-02-text-sized.png&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/uilayout-02-text-sized-thumb.png&quot; alt=&quot;The results of the second attempt. The contents are correctly positioned but the background is still the wrong size.&quot;&gt;&lt;/a&gt;
&lt;p&gt;This is getting closer, but the background (an Image component on the Tooltip object) isn&#039;t resizing yet. Remember that the preferred size of the VerticalLayoutGroup is the size of the bounds encompassing all its children. So let&#039;s just add a ContentSizeFitter to the VerticalLayoutGroup object and set both fits to &quot;Preferred Size&quot;.&lt;/p&gt;
&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/uilayout-03-tooltip-sized.png&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/uilayout-03-tooltip-sized-thumb.png&quot; alt=&quot;The results of the third attempt. The contents are correctly positioned and the background is the correct size.&quot;&gt;&lt;/a&gt;
&lt;p&gt;And that&#039;s pretty much it. You can use the Padding and Spacing properties on the Layout Group to clean it up.&lt;/p&gt;
&lt;p&gt;&lt;sup&gt;1&lt;/sup&gt; Layout Groups have two checkboxes for &quot;Child Controls Size&quot;, one for the Width and one for the Height. Checking these boxes causes the Layout Group to automatically perform the function of the ContentSizeFitter - changing the RectTransforms of the children to match their preferred size. This allows you achieve the same result without ContentSizeFitters, and it is apparently how Unity now intends it to be done; however, it affects ALL the children of the layout group. That includes the divider in this case, which we didn&#039;t want to resize. We could have fixed this by adding a LayoutElement component to the divider and setting its preferred height to 1.&lt;/p&gt;
&lt;h3&gt;One more thing&lt;/h3&gt;
&lt;p&gt;What if I wanted to introduce a second part of the background - a border? Ordinarily, I would make the border a child of the background and set the RectTransform Anchors to stretch both dimensions. But that won&#039;t work in this case because the background can no longer find the content items (Layout Groups only operate on their immediate children), so it won&#039;t grow to match them.&lt;/p&gt;
&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/uilayout-04-border-problem.png&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/uilayout-04-border-problem-thumb.png&quot; alt=&quot;The results of attempting to add a border. The border is the correct size, but the background is not.&quot;&gt;&lt;/a&gt;
&lt;p&gt;What we really want in this case is to pass the size &lt;i&gt;up&lt;/i&gt; from a Layout Group on the border. I move the Layout Group and ContentSizeFitter from the background to the border. Now the border is sizing correctly, but I need to get the background to match it as well.&lt;/p&gt;
&lt;p&gt;Remember that Layout Groups set their own preferred size to the size of the bounds encompassing all of the group&#039;s children. So we can achieve this by adding a Horizontal or Vertical Layout Group to the background (they will produce the same result with only one child), which sets the preferred size, and then adding a ContentSizeFitter to the background, resizing the RectTransform to match.&lt;/p&gt;
&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/uilayout-05-border-done.png&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/uilayout-05-border-done-thumb.png&quot; alt=&quot;A tooltip with a correctly-sized border and background.&quot;&gt;&lt;/a&gt;</description><pubDate>Wed, 10 Apr 2019 11:19:09 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Unity UI Gradient Shader</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=94</guid><link>https://brianmacintosh.com/blog/comments.php?post=94</link><description>&lt;p&gt;&lt;b&gt;EDIT:&lt;/b&gt; An updated version of this shader that supports Sliced images is available &lt;a href=&quot;https://www.brianmacintosh.com/blog/comments.php?post=104&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I created a variant of Unity&#039;s default UI shader; instead of using a solid tint color across the entire element, it uses a four-color gradient. The source is MIT-licensed and available on &lt;a href=&quot;https://gist.github.com/BrianMacIntosh/38ae43541d4bb31b5866b0dc58ff579c&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/unity-tint-gradient.png&quot; alt=&quot;Unity UI Gradient shader example image&quot;&gt;&lt;/p&gt;</description><pubDate>Thu, 14 Feb 2019 15:01:23 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Unfair (Board Game) Card Blanks</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=93</guid><link>https://brianmacintosh.com/blog/comments.php?post=93</link><description>&lt;p&gt;In a departure from my usual medium of digital games, I&#039;ve created blank card templates for every type of card in the game Unfair. These are based on the print-and-play version of the game, so they have some compression artifacts and Print-And-Play watermarks, but they do nicely for personal use. They&#039;re in Photoshop PSD format. Click this image to download.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/files/unfair-blanks.zip&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/files/unfair-blanks-preview-thumb.jpg&quot; alt=&quot;Unfair card templates preview image&quot;&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Mon, 11 Jun 2018 14:34:36 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>UCI Game Developers Week Lecture: Tools in Unity</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=92</guid><link>https://brianmacintosh.com/blog/comments.php?post=92</link><description>&lt;p&gt;I spoke yesterday at the UC Irvine Video Game Development Club&#039;s &lt;a href=&quot;https://sites.google.com/view/vgdcuci/events/gdw&quot;&gt;Game Developers Week&lt;/a&gt;. I discussed the four major methods for creating tools in Unity (property drawers, custom inspectors, editor windows, and gizmos) to help develop and debug Unity games, and showed some specific examples of each from Pillars of Eternity and Pillars of Eternity II: Deadfire. I also shared about my tool for browsing references to and from any asset in a Unity project, which is now available on &lt;a href=&quot;https://github.com/BrianMacIntosh/UnityProjectBrowser/&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Click this image to view the slides:&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/files/uci-gdw-2018.pdf&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/uci-gdw-2018-cover.png&quot; alt=&quot;Making huge games in Unity with tools, by Brian MacIntosh&quot;&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Sun, 27 May 2018 00:49:50 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>ASCII Art Generator</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=91</guid><link>https://brianmacintosh.com/blog/comments.php?post=91</link><description>&lt;p&gt;A few years ago, I wrote a program that could produce ASCII art from raster input images. I was going to use it to generate paperdoll images for the equipment screen in an ASCII roguelike game. It worked great, but it was written using XNA and the images to convert had to be set at compile-time. Ick!&lt;/p&gt;
&lt;p&gt;Now, I&#039;ve finished converting the program to Javascript/HTML5, and made a number of other improvements. You can try it right here!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://brianmacintosh.com/asciiart/&quot; target=&quot;_blank&quot;&gt;http://brianmacintosh.com/asciiart/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/asciiart/&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/ascii-image-sample-sun.jpg&quot; alt=&quot;ASCII Art generator sample&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can find a number of ASCII art generators on the internet, but they usually operate simply by selecting characters with more or less &quot;ink&quot; based on the brightness of each character-sized cell in the image. This method requires pretty large output sizes for the image to be recognizable. My generator uses edge detection to find characters that actually follow the lines of the input image, which holds up a lot better at smaller sizes. The downside is that noisier images (such as photographs) can produce noisy output that requires a lot of cleanup, though there are some steps that try to mitigate this.&lt;/p&gt;
&lt;p&gt;The source code is under the GPL (3.0), and images produced with the page are free to use. You can visualize what each step looks like by adjusting the &lt;b&gt;Debug Stage&lt;/b&gt; in the &lt;b&gt;Advanced&lt;/b&gt; settings, and there are a number of sliders to play with the tweak the results. Here is an overview of the steps in the algorithm.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Greyscale the input image.&lt;/li&gt;
&lt;li&gt;Gaussian blur the image to reduce noise.&lt;/li&gt;
&lt;li&gt;Use &lt;a href=&quot;https://www.google.com/search?q=sobel+edge+detection&quot;&gt;Sobel edge detection&lt;/a&gt; to produce a greyscale image representing the edges present.&lt;/li&gt;
&lt;li&gt;Threshold the edge-detected image, leaving us with a black image with white lines.&lt;/li&gt;
&lt;li&gt;(Optional) &lt;a href=&quot;https://www.google.com/search?q=image+processing+dilate&quot;&gt;Dilate&lt;/a&gt; the image, thickening the edges.&lt;/li&gt;
&lt;li&gt;(Optional) &lt;a href=&quot;https://www.google.com/search?q=image+processing+erode&quot;&gt;Erode&lt;/a&gt; the image, reducing the edges. When used in combination with equivalent dilation, this can help reduce noise.&lt;/li&gt;
&lt;li&gt;Blur the line image. This makes it easier for us to match up characters in the next step when the best match doesn&#039;t precisely line up with the grid.&lt;/li&gt;
&lt;li&gt;Split the image into a letter-sized grid. For each grid cell, overlay (&quot;convolute&quot; is the technical term) each ASCII character over the content. Whichever character best matches the content of that cell is the one we&#039;ll use. We also try the characters at small offsets to try to catch, say, a vertical line that doesn&#039;t land quite in the middle of a cell.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/image-proc-steps-basic.jpg&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/image-proc-steps-basic-thumb.jpg&quot; alt=&quot;ASCII Art steps: original image, Sobel edge detection, overlaid ASCII characters&quot;&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Mon, 26 Mar 2018 01:27:06 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>A Different Approach to Pip-Based Bars</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=90</guid><link>https://brianmacintosh.com/blog/comments.php?post=90</link><description>&lt;p&gt;I&#039;ve been checking out a number of different systems in &lt;a href=&quot;https://www.factorio.com/&quot;&gt;Factorio&lt;/a&gt; while experimenting with making a factory-building game. While looking through the game&#039;s assets, I noticed an interesting health bar graphic that revealed Factorio&#039;s rather neat way of handling pip-based health bars. A pip-based bar uses filled or unfilled pips to indicate progress or health, rather than a continuous line:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/factorio_pips.png&quot; alt=&quot;Factorio health bar screenshot&quot;&gt;&lt;/p&gt;&lt;p&gt;The most obvious way to implement this element would be to use a number of different sprite instances, and have each of them flip between a &quot;green&quot; and a &quot;grey&quot; image as appropriate. This can be done in one draw call, if the two states are on one image, and one quad per pip. Here&#039;s the asset you would need to implement this:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/flip_pips.png&quot; alt=&quot;Two health bar pips, one green, one grey&quot;&gt;&lt;/p&gt;&lt;p&gt;So I was initially confused when I saw that Factorio&#039;s health bar asset actually looked like this:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/health-bar-green.png&quot; alt=&quot;Factorio health bar with lots of green pips followed by lots of grey pips&quot;&gt;&lt;/p&gt;&lt;p&gt;Can you figure out how this asset might be used? My guess is that the bar is drawn as a single quad that&#039;s mapped to an appropriate part of this image using its UV coordinates. For example, if you wanted a 7-pip bar with 5 pips filled, you could map your UVs like so:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/health-bar-green_quad.png&quot; alt=&quot;Factorio health bar asset with UV mapping illustration&quot;&gt;&lt;/p&gt;&lt;p&gt;This is more efficient because you only have to draw one quad. More significantly, it&#039;s simpler to implement because you only need a single sprite or entity in your engine, rather than having to create several and manage their positions. Your asset just needs to have twice as many pips as the maximum pip count you want to use.&lt;/p&gt;</description><pubDate>Thu, 23 Nov 2017 03:35:44 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Necromasser Release</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=89</guid><link>https://brianmacintosh.com/blog/comments.php?post=89</link><description>&lt;p&gt;We just released a new online, in-browser game called &lt;b&gt;Necromasser&lt;/b&gt;. Necromasser is an always-on multiplayer world where you try to build the most massive zombie horde to hit the top of the leaderboard. You can &lt;a href=&quot;https://www.brianmacintosh.com/projects/necromasser&quot;&gt;play it in your browser right now&lt;/a&gt;!&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/projects/necromasser&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/necromasser_thumb.jpg&quot; alt=&quot;Necromasser Screenshot&quot;&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Sat, 25 Mar 2017 15:50:02 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Procedural Potion Icon Generator</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=88</guid><link>https://brianmacintosh.com/blog/comments.php?post=88</link><description>&lt;p&gt;Randomly inspired by a coworker, I took a weekend afternoon and made a webpage that procedurally generates 32px potion icons.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/iconmachine/&quot;&gt;Make potions here&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/iconmachine/&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/procpotions.png&quot; alt=&quot;Sample procedural potion sheet&quot;&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Wed, 08 Mar 2017 02:35:57 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Persistent data in the Alexa Skills nodejs SDK</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=87</guid><link>https://brianmacintosh.com/blog/comments.php?post=87</link><description>&lt;p&gt;I recently started use the &lt;a href=&quot;https://github.com/alexa/alexa-skills-kit-sdk-for-nodejs&quot;&gt;Alexa Skills Kit SDK for nodejs&lt;/a&gt; to write an Amazon Alexa skill. I ran into one rather silly roadblock, which I will now share so others can avoid.&lt;/p&gt;&lt;p&gt;This SDK handles persisent data (with the same session and across sessions) by providing an &lt;code&gt;attributes&lt;/code&gt; property on the skill handler (accessed by &lt;code&gt;this.attributes&lt;/code&gt;). My problem was that sometimes properties I set on this object were apparently completely ignored by the next request (even if I kept the session open with an &lt;code&gt;this.emit(&quot;:ask&quot;, ...)&lt;/code&gt; response). It is perhaps obvious in hindsight, but you must make all your changes to &lt;code&gt;this.attributes&lt;/code&gt; &lt;i&gt;before&lt;/i&gt; calling &lt;code&gt;emit&lt;/code&gt;, as &lt;code&gt;emit&lt;/code&gt; will immediately and synchronously prepare and send the response to Alexa, including the attributes you&#039;re trying to persist into the next session. But it took me quite some time to figure this out.&lt;/p&gt;</description><pubDate>Sun, 05 Feb 2017 00:59:07 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Contact Listeners in box2d.js</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=86</guid><link>https://brianmacintosh.com/blog/comments.php?post=86</link><description>&lt;p&gt;To implement physics in Porcupine Dogfight, I used Alon &quot;kripken&quot; Zakai&#039;s &lt;a href=&quot;https://github.com/kripken/box2d.js/&quot;&gt;emscripten port&lt;/a&gt; of Box2D to Javascript. It was very easy to get working and almost entirely identical to the original Box2D implementation, however, it lacks documentation for some of the differences. After some experimentation and trying to read the crazy auto-generated source code, I finally figured out how to implement a Contact Listener. There are two things that are not immediately obvious: the listener must be an instance of &lt;b&gt;JSContactListener&lt;/b&gt;, and the parameters passed in are not objects, but pseudo-pointers that need to be dereferenced with &lt;b&gt;wrapPointer&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;I post some &lt;a href=&quot;https://gist.github.com/BrianMacIntosh/fefca14bcc5ff82491f3&quot;&gt;sample code&lt;/a&gt; on Github for the benefit of anyone else who has this problem in the future.&lt;/p&gt;</description><pubDate>Mon, 20 Apr 2015 17:49:56 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Ludum Dare 32 Brainstorming</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=85</guid><link>https://brianmacintosh.com/blog/comments.php?post=85</link><description>&lt;p&gt;Brainstorming thought process for Ludum Dare 32: &lt;b&gt;An Unconventional Weapon&lt;/b&gt;.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;I like airships.&lt;/li&gt;&lt;li&gt;Unconventional airship warfare?&lt;/li&gt;&lt;li&gt;Porcupines.&lt;/li&gt;&lt;li&gt;What&#039;s more fun than airships slinging porcupines at each other?&lt;/li&gt;&lt;li&gt;Porcupines flying airships, slinging themselves at each other!&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/ld32_1.jpg&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/ld32_1_thumb.jpg&quot; alt=&quot;Screenshot of porcupines flying balloons.&quot;&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Sat, 18 Apr 2015 12:31:16 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Camera Obscura Indie Royale</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=84</guid><link>https://brianmacintosh.com/blog/comments.php?post=84</link><description>&lt;p&gt;I&#039;m excited to have Camera Obscura featured in this week&#039;s Indie Royale game bundle! Pay what you want for Camera Obscura and 5 other games. No reason not to pick it up now!&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.indieroyale.com/?royale=216&quot;&gt;The Venetian Bundle&lt;/a&gt;&lt;/p&gt;</description><pubDate>Wed, 25 Mar 2015 17:28:07 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Camera Obscura Steam Release</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=83</guid><link>https://brianmacintosh.com/blog/comments.php?post=83</link><description>&lt;p&gt;It&#039;s happening. Three years after its inception, Camera Obscura has made it through Steam Greenlight.  We&#039;ve been hard at work through January getting everything ready for release, and it&#039;s coming on &lt;b&gt;February 19th&lt;/b&gt;.  I&#039;m excited to finally get the game out to players so they can enjoy it!&lt;/p&gt;&lt;p&gt;&lt;iframe title=&quot;Camera Obscura Release Trailer&quot; width=&quot;640&quot; height=&quot;360&quot; src=&quot;https://www.youtube.com/embed/UfahLj7-8gM?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;p&gt;For more information, visit &lt;a href=&quot;https://www.cameraobscuragame.com/&quot;&gt;cameraobscuragame.com&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Tue, 10 Feb 2015 03:05:29 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Magic Mobile Website Compatibility</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=82</guid><link>https://brianmacintosh.com/blog/comments.php?post=82</link><description>&lt;p&gt;I recently started working on making these pages more compatible with mobile devices. One piece of advice I found quickly was to include the following meta tag in my HTML header:&lt;/p&gt;
&lt;code class=&quot;codeblock&quot;&gt;&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;meta&lt;/span&gt;&lt;span style=&#039;color:#274796; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#074726; &#039;&gt;name&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt;&lt;span style=&#039;color:#0000e6; &#039;&gt;&quot;viewport&quot;&lt;/span&gt;&lt;span style=&#039;color:#274796; &#039;&gt; &lt;/span&gt;&lt;span style=&#039;color:#074726; &#039;&gt;content&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;=&lt;/span&gt;&lt;span style=&#039;color:#0000e6; &#039;&gt;&quot;width=device-width,initial-scale=1&quot;&lt;/span&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;!--Created using ToHtml.com on 2020-01-04 18:32:57 UTC --&gt;&lt;/code&gt;
&lt;p&gt;It took me a bit longer to figure out exactly what this seemingly magic piece of code actually means for a site being rendered in a mobile browser, and to convince myself that yes, this code can magically make your website display much better on small mobile devices - &lt;i&gt;but&lt;/i&gt; only if your website&#039;s CSS is already set up in a nice, size-independent way.&lt;/p&gt;
&lt;p&gt;By default, mobile browsers assume that most of the internet is not designed to display well in a very small format. For that reason, they will render webpages at a large resolution more comparable to a desktop, and force the user to zoom and pan to see the content. What this code is actually doing is informing the browser that, yes, your content is fine to be displayed in a very small window - you are promising that it will resize itself and nothing will bleed off the page. This causes the browser to disable the extra-large render, freeing users from needing to zoom or scroll content sideways. So, if you&#039;ve set up all your CSS to use percentages instead of fixed positions, it should result in an instant improvement in user experience as users can now simply scroll vertically through your content.&lt;/p&gt;
&lt;p&gt;In my case, there was one other change needed to make this site&#039;s content mostly mobile-compatible. I often use screenshot images here, and those images are usually wider than a typical phone display, so I need them to scale down if the window is smaller than they are. This was accomplished easily enough by including the following CSS in the HTML header:&lt;/p&gt;
&lt;code class=&quot;codeblock&quot;&gt;&lt;pre style=&#039;color:#000000;background:#ffffff;&#039;&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;style&lt;/span&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&gt;&lt;/span&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;img&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;{&lt;/span&gt;&lt;span style=&#039;color:#bb7977; font-weight:bold; &#039;&gt;max-width&lt;/span&gt;&lt;span style=&#039;color:#808030; &#039;&gt;:&lt;/span&gt;&lt;span style=&#039;color:#008c00; &#039;&gt;100&lt;/span&gt;&lt;span style=&#039;color:#006600; &#039;&gt;%&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;;&lt;/span&gt;&lt;span style=&#039;color:#800080; &#039;&gt;}&lt;/span&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#039;color:#800000; font-weight:bold; &#039;&gt;style&lt;/span&gt;&lt;span style=&#039;color:#a65700; &#039;&gt;&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;!--Created using ToHtml.com on 2020-01-04 18:33:25 UTC --&gt;&lt;/code&gt;
&lt;p&gt;Which simply instructs every img element on the page to be no wider than its parent element. Aspect ratio is preserved automatically.&lt;/p&gt;
&lt;p&gt;There are plenty of other small UX adjustments that can be made, but now my site renders in a much more convenient format for visitors on phones.&lt;/p&gt;</description><pubDate>Sat, 31 Jan 2015 21:39:45 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Outpost: New World (Ludum Dare 31)</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=81</guid><link>https://brianmacintosh.com/blog/comments.php?post=81</link><description>&lt;p&gt;Just a few weeks ago, Justin and I participated in the &lt;a href=&quot;http://ludumdare.com/compo/ludum-dare-31/&quot;&gt;31st Ludum Dare&lt;/a&gt;. The theme: &lt;b&gt;Entire Game On One Screen&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;We decided ahead of time that we wanted to make a game that was more action-packed and also more polished than our usual fare. I&#039;m not sure we totally succeeded in overcoming our propensity for making fairly complicated simulation games, but we did manage to make our most polished jam game yet. Play it here!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/projects/ld31&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/outpostNW_thumb.jpg&quot; alt=&quot;Outpost: New World Screenshot&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://www.brianmacintosh.com/projects/ld31&quot;&gt;Outpost: New World&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our past experience with game jams lead us to decide that we wanted to be done with the core game by early afternoon of the second day (sooner than halfway through the jam). We would then use the second half of the jam entirely for polish. While we fell behind on that goal, finished the core game around 6 in the evening of the second day, that still left us the entirety of Sunday for polish. It worked out very well - I was able to put together a very dramatic opening cinematic, a generate a full range of sfxr-generated sound effects, and record some moody cello music (three elements that we usually don&#039;t have time for in jams).&lt;/p&gt;&lt;p&gt;While I&#039;m not a huge fan of how the final gameplay turned out, others seem to be enjoying it much more than any of our previous attempts. We&#039;ll see what the results show in about 21 hours.&lt;/p&gt;</description><pubDate>Mon, 29 Dec 2014 00:28:43 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Ludum Dare #30 Results</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=80</guid><link>https://brianmacintosh.com/blog/comments.php?post=80</link><description>&lt;p&gt;Results for the past weeks&#039; Ludum Dare judging are in!  While we knew we had made a game that was ill-suited to the judging style of the Ludum Dare, in which people have to play and judge a lot of games in a short time period, there were definitely some who really enjoyed the complexity and took time to learn the game.&lt;/p&gt;&lt;table cellpadding=5&gt;&lt;tr&gt;&lt;td align=center&gt;&lt;td&gt;Coolness&lt;td align=right&gt;84%&lt;tr&gt;&lt;td align=center&gt;#99&lt;td&gt;Theme(Jam)&lt;td align=right&gt;3.76&lt;tr&gt;&lt;td align=center&gt;#345&lt;td&gt;Innovation(Jam)&lt;td align=right&gt;3.11&lt;tr&gt;&lt;td align=center&gt;#487&lt;td&gt;Humor(Jam)&lt;td align=right&gt;2.13&lt;tr&gt;&lt;td align=center&gt;#487&lt;td&gt;Overall(Jam)&lt;td align=right&gt;3.06&lt;tr&gt;&lt;td align=center&gt;#532&lt;td&gt;Graphics(Jam)&lt;td align=right&gt;2.98&lt;tr&gt;&lt;td align=center&gt;#597&lt;td&gt;Fun(Jam)&lt;td align=right&gt;2.64&lt;tr&gt;&lt;td align=center&gt;#618&lt;td&gt;Mood(Jam)&lt;td align=right&gt;2.61&lt;tr&gt;&lt;td align=center&gt;#629&lt;td&gt;Audio(Jam)&lt;td align=right&gt;1.83&lt;/table&gt;&lt;p&gt;I played some other really cool games while I was judging. Here are a few that I stumbled across:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://andrewmorrish.net/?page_id=731&quot;&gt;Tough Love Machine&lt;/a&gt; - A remarkable innovation on the classic sliding-block puzzle.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://dl.dropboxusercontent.com/u/10197361/LD30/index.html&quot;&gt;This little piggy&lt;/a&gt; - It has bacon in it.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://adharris.github.io/LD30/&quot;&gt;Bidimensional Landscaping&lt;/a&gt; - A quick game with a unique new mechanic.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://dl.dropboxusercontent.com/u/2963538/Games/LD30/FluidPerspectivesByJezzamon.swf&quot;&gt;Fluid Perspectives&lt;/a&gt; - A very nice little platformer&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://dl.dropboxusercontent.com/u/204076271/ferryman_ashdnazg_ld30.zip&quot;&gt;Ferryman&lt;/a&gt; - It&#039;s a humorous and witty take on the theme.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://justmillingaroundonline.com/LD30/&quot;&gt;Toward Toward Heaven&lt;/a&gt; - Shares our plight of being pretty complicated, but I kept coming back for more of it. A unique take on &quot;multiplayer&quot; games.&lt;/li&gt;&lt;/ul&gt;</description><pubDate>Wed, 17 Sep 2014 11:48:54 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Space Transport Tycoon</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=79</guid><link>https://brianmacintosh.com/blog/comments.php?post=79</link><description>&lt;p&gt;And the game is done as of last night. I think this one went well, considering Justin didn&#039;t stop playing it for 4 hours after we finished.&lt;/p&gt;&lt;p&gt;It&#039;s a space economy simulation game. You the player must build a network of trading routes to move materials to factories and consumers.&lt;/p&gt;&lt;p&gt;Play in your browser!&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/projects/ld30/&quot;&gt;Space Transport Tycoon&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/stt1.png&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/stt1_thumb.jpg&quot; alt=&quot;Space Transport Tycoon screenshot&quot;&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Mon, 25 Aug 2014 11:09:37 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Ludum Dare 30 Go Time</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=78</guid><link>https://brianmacintosh.com/blog/comments.php?post=78</link><description>&lt;p&gt;Just starting the first real day of coding for the 30th &lt;a href=&quot;http://www.ludumdare.com/compo/&quot;&gt;Ludum Dare&lt;/a&gt;.  I started off this jam thinking of making some kind of simulation game - something where you, in a relatively low-pressure environment, could build up a system or a network and watch it do its work, like SimCity.&lt;/p&gt;&lt;p&gt;Justin and I had a short brainstorming session when the theme - &lt;b&gt;Connected Worlds&lt;/b&gt; - was announced.  They say to never go with your first idea - however, after considering two-screen tower-defense games, games where dinosaurs are attacking the modern world, games with constellations (I really liked that one and I hope some other people do it), and meeting Kevin Bacon, we eventually went with just that.  This will be a game where you build up an interstellar shipping empire, moving goods between planets.&lt;/p&gt;&lt;p&gt;I also wanted to try to make use of multiple windows or views, and that goes well with theme.  We&#039;re pretty sure we know what we are going to do with them.  Early screenshot:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/ld30-scr1.png&quot; alt=&quot;Ludum Dare 30 screenshot&quot;&gt;&lt;/p&gt;</description><pubDate>Sat, 23 Aug 2014 11:13:05 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Some Pixel Art</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=77</guid><link>https://brianmacintosh.com/blog/comments.php?post=77</link><description>&lt;p&gt;Indiana Jones-themed pixel art. Maybe a game, some day?&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/truck.png&quot; alt=&quot;Pixel art of a truck and workers&quot;&gt;&lt;/p&gt;</description><pubDate>Sun, 03 Aug 2014 20:31:27 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Ludum Dare #29 Results</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=76</guid><link>https://brianmacintosh.com/blog/comments.php?post=76</link><description>&lt;p&gt;The results are in from Ludum Dare #29. Fun being probably the most important category to me, I am quite happy with my rankings. I&#039;m definitely improving over my scores from the last two jams, and I was happier with the game as well. The Dare had a record-breaking 2497 submissions this year.&lt;/p&gt;&lt;table cellpadding=5&gt;&lt;tr&gt;&lt;td align=center&gt;&lt;td&gt;Coolness&lt;td align=right&gt;82%&lt;tr&gt;&lt;td align=center&gt;#64&lt;td&gt;Theme(Jam)&lt;td align=right&gt;3.84&lt;tr&gt;&lt;td align=center&gt;#140&lt;td&gt;Fun(Jam)&lt;td align=right&gt;3.42&lt;tr&gt;&lt;td align=center&gt;#211&lt;td&gt;Mood(Jam)&lt;td align=right&gt;3.43&lt;tr&gt;&lt;td align=center&gt;#240&lt;td&gt;Innovation(Jam)&lt;td align=right&gt;3.30&lt;tr&gt;&lt;td align=center&gt;#249&lt;td&gt;Overall(Jam)&lt;td align=right&gt;3.39&lt;tr&gt;&lt;td align=center&gt;#316&lt;td&gt;Audio(Jam)&lt;td align=right&gt;3.18&lt;tr&gt;&lt;td align=center&gt;#318&lt;td&gt;Humor(Jam)&lt;td align=right&gt;2.70&lt;tr&gt;&lt;td align=center&gt;#485&lt;td&gt;Graphics(Jam)&lt;td align=right&gt;3.07&lt;/table&gt;&lt;p&gt;During the judging period, I played 60-something games. You can find lots of &quot;best-of&quot; lists around - here are the best games I happened to play.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-29/?action=preview&amp;amp;uid=37445&quot;&gt;Infection&lt;/a&gt; - A pretty tower defense game in Unity.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-29/?action=preview&amp;amp;uid=4232&quot;&gt;Kinetectonic&lt;/a&gt; - A very fun-to-figure-out puzzle-type game.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-29/?action=preview&amp;amp;uid=12297&quot;&gt;Ben Eath the Surf Ace&lt;/a&gt; - A surfing game that&#039;s totally rad, dude.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-29/?action=preview&amp;amp;uid=3275&quot;&gt;Shark, Shark, Shark&lt;/a&gt; - Shark, shark, shark, I&#039;m a shark. It has claymation!&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-29/?action=preview&amp;amp;uid=2952&quot;&gt;A Glorious Escape for a Lich King&lt;/a&gt; - A really solid all-around tower defense game.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-29/?action=preview&amp;amp;uid=32991&quot;&gt;Jumpland Underground&lt;/a&gt; - This game is art.&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-29/?action=preview&amp;amp;uid=37338&quot;&gt;Damned Scouts&lt;/a&gt; - A fun puzzle game about camping safety.&lt;/li&gt;&lt;/ul&gt;</description><pubDate>Mon, 19 May 2014 23:37:58 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>.gitignore: permit only certain paths with negation</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=75</guid><link>https://brianmacintosh.com/blog/comments.php?post=75</link><description>&lt;p&gt;Today I was trying to create a &lt;b&gt;.gitignore&lt;/b&gt; file for a project that has to live in the same directory as a number of different folders. I wanted the git repo to only include folders that start with the string &lt;b&gt;heroscape&lt;/b&gt;, while excluding any other folder.&lt;/p&gt;&lt;p&gt;The gitignore &lt;a href=&quot;http://git-scm.com/docs/gitignore&quot;&gt;man pages&lt;/a&gt; point out that you can negate a pattern by putting a &lt;b&gt;!&lt;/b&gt; in front of it. I didn&#039;t notice at first that this does &lt;i&gt;not&lt;/i&gt; ignore anything that does not match the pattern. Instead, it re-includes any previously ignored paths that match the negated pattern.&lt;/p&gt;&lt;p&gt;So to achieve what I wanted, I had to do the following, first ignoring &lt;b&gt;all&lt;/b&gt; folders, then re-including folders that begin with &quot;heroscape&quot;.&lt;/p&gt;&lt;p&gt;&lt;code class=&quot;codeblock&quot;&gt;*/&lt;br&gt;!heroscape*/&lt;/code&gt;&lt;/p&gt;</description><pubDate>Thu, 15 May 2014 19:13:04 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Dawn: Infinite Runner Game</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=74</guid><link>https://brianmacintosh.com/blog/comments.php?post=74</link><description>&lt;p&gt;Between the Ludum Dare, school, and everything else, I&#039;ve been turning out a lot of small projects this month. I recently participated in a &lt;a href=&quot;http://forum.thegamecreators.com/?m=forum_view&amp;amp;t=210188&amp;amp;b=2&quot;&gt;competition&lt;/a&gt; on &lt;a href=&quot;http://www.thegamecreators.com/&quot;&gt;The Game Creators&lt;/a&gt;. The competition, inspired by Flappy Bird, presented one goal: make the most addictive infinite game possible.&lt;/p&gt;&lt;p&gt;My entry, titled &lt;i&gt;Dawn&lt;/i&gt;, also draws inspiration from the classic &lt;i&gt;Canabalt&lt;/i&gt;. It&#039;s a sidescrolling runner in which you play a man who must jump, smash, and fly his way through a scrolling obstacle course as the days pass by.&lt;/p&gt;&lt;div class=&quot;centeralign&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/projects/dawn/runscreen2.jpg&quot; alt=&quot;Dawn Screenshot&quot; width=&quot;600&quot;&gt;&lt;/div&gt;&lt;p&gt;This competition was focused on addictive potential, so I implemented a few different ideas in an attempt to grab the attention of players of the game:&lt;ul&gt;&lt;li&gt;&lt;b&gt;Online Highscores&lt;/b&gt;: they give the player something to shoot for. He can see what other people have done, know that it&#039;s possible, and attempt to prove himself better than them.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Day/Night Cycles&lt;/b&gt;: My idea here was to give the player a concrete sense of progress - more visceral goals to shoot for than the elusive high score.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Feel&lt;/b&gt;: Polish. If the game simply feels good to play, I reasoned, people will want to play it more! Key elements of this in &lt;i&gt;Dawn&lt;/i&gt; include particles when smashing through walls and a good set of character animations that makes you feel awesome when you crash through those girders. At the suggestion of Justin Britch, I took a minute to implement a simple animation at the game end: quickly ticking up the user&#039;s score from 0, rather than just displaying it. This gives the score a sense of weight and grants the player extra satisfaction at his achievement.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;It remains to be seen how effective these strategies were. Clearly Flappy Bird didn&#039;t need many of these things to become what it did!&lt;/p&gt;</description><pubDate>Sun, 11 May 2014 03:17:31 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Ludum Dare #29 Complete</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=73</guid><link>https://brianmacintosh.com/blog/comments.php?post=73</link><description>&lt;p&gt;A few weeks ago, I participated in the 29th &lt;a href=&quot;http://www.ludumdare.com/compo/&quot;&gt;Ludum Dare&lt;/a&gt;. It has been a while, but not many posts, since I last participated in the Dare. The theme for this one was &quot;Beneath the Surface&quot;.&lt;/p&gt;&lt;p&gt;I worked with Justin Britch on this one. We met just after the theme was announced to brainstorm. I really liked this theme - it evokes mystery and exploration, provides an easy setting (underground or underwater) to start with, and could simultaneously be tied into gameplay elements. While we thought it would have been a lot of fun to make &quot;Ben Eath, the Surf Ace&quot;, we ultimately decided that we really wanted to go after the mystery, the thrill of exploration, fear of the unknown, and such themes. We also knew that we wanted to attempt to introduce some sort of narrative into the world.&lt;/p&gt;&lt;div class=&quot;centeralign&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/projects/ld29/screen3.png&quot; width=&quot;600&quot; alt=&quot;Thunder Fish game work in progress.&quot;&gt;&lt;br&gt;&lt;i&gt;The beginnings of the conversation system.&lt;/i&gt;&lt;/div&gt;&lt;p&gt;The design was ambitiously scoped for a jam, and I&#039;m happy I was able to turn out so many features.&lt;/p&gt;&lt;div class=&quot;centeralign&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/projects/ld29/screen4.png&quot; width=&quot;600&quot; alt=&quot;Thunder Fish game finished conversation system&quot;&gt;&lt;br&gt;&lt;i&gt;More conversation.&lt;/i&gt;&lt;/div&gt;&lt;p&gt;&lt;b&gt;The Good&lt;/b&gt;: Dedicating time &lt;i&gt;during&lt;/i&gt; the development process for polish worked well for the game. When polish gets left as a task for the end of the jam, there&#039;s often no time to actually do it. I didn&#039;t leave a feature until it was in a state it could stay in.&lt;/p&gt;&lt;p&gt;I also didn&#039;t run into too many momentum-killer problems.  I&#039;ve worked on several smaller projects using HTML5 and ThreeJS over the past few months, so I knew some of its quirks and was able to work continuously without getting stuck on strange bugs, even though the codebase for &lt;i&gt;Thunder Fish&lt;/i&gt; pushed way past the size of my previous HTML games.  Familiarity is key for jams, and it definitely pays off in the ability to continue grinding out features.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Learned&lt;/b&gt;: Yet again, I completely failed to allocate time for audio. Fortunately, I was already in the Jam category for this one, so I pulled some free music from &lt;a href=&quot;https://www.soundclick.com/bands/default.cfm?bandID=1236552&quot;&gt;NGXmusical&lt;/a&gt; in the last hour. Sound effects could have improved the feel even further, though.&lt;/p&gt;&lt;p&gt;You can play &lt;a href=&quot;https://brianmacintosh.com/projects/ld29/&quot;&gt;The Legend of the Thunder Fish&lt;/a&gt; on the web!&lt;/p&gt;&lt;p&gt;Also some of the other Dare games, here: &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-29/&quot;&gt;Ludum Dare 29&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Sun, 11 May 2014 02:43:50 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>What is Flatricide Pulgamitude Anyway?</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=72</guid><link>https://brianmacintosh.com/blog/comments.php?post=72</link><description>&lt;p&gt;I recently released a small game called Flatricide Pulgamitude.  This game is an experiment for me in pseudo-multiplayer game development.  By that, I mean &quot;I really like games you can play with other people, but I don&#039;t want to have to manage a real-time game server&quot;.  Therefore, I set out to make a game that you could play with others online with only some PHP scripts and a MySQL database.&lt;/p&gt;
&lt;p&gt;The result of that is a game in which you wander a strange abstract world built by people who have come before you.  You can&#039;t see other people in real-time, but you can explore their work and build your own for others to find.&lt;/p&gt;
&lt;p&gt;So why the strange name?  The other impetus behind this project is a class competition to get a page to the #1 spot in Google Search for the term &quot;Flatricide Pulgamitude&quot;.  To that end, I&#039;d appreciate it if you could share a link on your own site!&lt;/p&gt;
&lt;p&gt;You want to check it out? Just click on this pulgamitude (whatever that is):&lt;/p&gt;
&lt;div class=&quot;centeralign&quot;&gt;&lt;a href=&quot;https://www.brianmacintosh.com/fp/&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/fp/pulgamicon.png&quot; alt=&quot;Pulgamitude&quot;&gt;&lt;/a&gt;&lt;/div&gt;</description><pubDate>Sat, 01 Mar 2014 18:42:19 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Keeping cmd windows open with /K</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=71</guid><link>https://brianmacintosh.com/blog/comments.php?post=71</link><description>&lt;p&gt;I like using .BAT files to run common tasks like compiling Java code or starting my NodeJS server.  It&#039;s very convenient to just execute a .BAT where you&#039;ve already written out all the proper parameters rather than typing out an entire call every time you need it.  This does cause a problem, though - if any of the programs that execute from the .BAT returns an error code, the command window will immediately close.  This makes it impossible to debug those programs.&lt;/p&gt;&lt;p&gt;I tried adding the &lt;b&gt;pause&lt;/b&gt; command at the end of each file, but to no avail - the command window exits immediately when a program returns an error and doesn&#039;t execute the rest of the file (which is responsible of it, admittedly).&lt;/p&gt;&lt;p&gt;The solution was to use a parameter to the cmd program itself:&lt;/p&gt;&lt;p&gt;&lt;b&gt;cmd /K bat/mybat.bat&lt;/b&gt;&lt;/p&gt;&lt;p&gt;The /K parameter keeps the window open even if the .BAT stops executing.  I simply copied all my .BATs to a subdirectory and created wrapper bats using this line.&lt;/p&gt;</description><pubDate>Wed, 29 Jan 2014 13:28:34 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Ludum Dare #27 Complete</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=70</guid><link>https://brianmacintosh.com/blog/comments.php?post=70</link><description>&lt;p&gt;Last weekend, I participated in the 27th &lt;a href=&quot;http://www.ludumdare.com/&quot;&gt;Ludum Dare&lt;/a&gt;.  For anyone who doesn&#039;t know, the Ludum Dare is a competition held a few times a year in which participants attempt to make a game in 48 hours.  Games made for this Ludum Dare had to follow the theme &quot;10 Seconds&quot;.&lt;/p&gt;&lt;p&gt;When I first heard the theme, I was a bit put off.  I thought it was too shallow, too easy to just tack onto an arcade clone.  Fortunately, many brilliant people proved me wrong.  However, I opted to take the theme a little more laterally, interpretting &quot;seconds&quot; as a &lt;a href=&quot;https://en.wikipedia.org/wiki/Longitude#Noting_and_calculating_longitude&quot;&gt;measure of distance&lt;/a&gt; based on global lat/lon coordinates.  I thought, &quot;what if there were only 10 square seconds of the earth left?&quot;  The earth would just be a really small section of the surface (about 300 ft on each edge) and a huge slice of the core dropping off into nothingness.&lt;/p&gt;&lt;p&gt;That sounded like a great setting for a survival-horror game, something I hadn&#039;t tried before.  The design I ended up attempting to implement was very ambitious.  Overall, I think this was a good plan, even though I certainly didn&#039;t get to everything I wanted to.  I was considering and developing a lot of extra content for the game, rather than just taking the first few things I thought of and ending design because of scope.  Of course, over-scoping is still a terrible thing, but by prioritizing things that needed to get done, I was able to still have a playable game after 48 hours even while not reaching all my goals.&lt;/p&gt;&lt;p&gt;I did neglect the gameplay aspect of the game a bit during this jam.  Had I been able to implement some form of combat and developed the building mechanics more, the game would have become much more viable from a gameplay perspective.  So perhaps the scope did kill me there.  I ended up getting to explore ideas for creating ambiances and environments, though, and I think on that front it went fairly well.&lt;/p&gt;&lt;p&gt;You can play my entry here: &lt;a href=&quot;http://www.ludumdare.com/compo/ludum-dare-27/?action=preview&amp;amp;uid=15030&quot;&gt;&lt;b&gt;The 91st Parallel&lt;/b&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/projects/ld27/ld27_2.jpg&quot; alt=&quot;The 91st Parallel Screenshot&quot;&gt;&lt;/p&gt;</description><pubDate>Mon, 02 Sep 2013 22:26:06 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Forays in Web Crawling</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=69</guid><link>https://brianmacintosh.com/blog/comments.php?post=69</link><description>&lt;p&gt;I&#039;ve always been really interested in the idea of gathering data from the internet.  It probably stems from my love of organizing, classifying, and recording stuff. I finally took an opportunity to exercise this interest this week.&lt;/p&gt;&lt;p&gt;On the forums for the (amazing) game &lt;i&gt;Dwarf Fortress&lt;/i&gt;, there is a thread dedicated to illustrating &quot;forgotten beasts&quot; from the game.  Forgotten beasts are terrifying monsters that are randomly generated by the game and lurk in the depths of the earth.  Because forgotten beasts are rarely alike, the thread has seen a great variety of works from some outstanding artists.  I wanted to collect these illustrations and organize them into an archive where people could browse them by artist or by the beast.&lt;/p&gt;&lt;p&gt;To collect what ended up being over 650 images from a 150-page forum thread, I created a web robot in C#.  This part of the task provided some interesting challenges. The robot had to collect the URLs of any images that were posted in the thread and their authors, as well as the actual text descriptions of the beasts being illustrated, which were sometime in text form or in the form of screenshots from the game. Fortunately, the descriptions follow a certain identifiable formula that made it possible to pick them out with good success from all the other text in the thread. To actually associated the beast pictures with the proper descriptions and to find and transcribe the descriptions that were embedded in screenshots, I turned to a sort of &quot;crowdsourcing&quot; model - I set up a simple PHP page to show images to viewers and ask them to classify them. This was an easy way to finish these tasks that would have been impossible for an automated program to do (though I contemplated incorporating some kind of OCR to look for text descriptions in the images and transcribe them).&lt;/p&gt;&lt;p&gt;To check out some of the great art this thread has produced, visit the archive page: &lt;a href=&quot;https://www.brianmacintosh.com/beasts/&quot;&gt;https://www.brianmacintosh.com/beasts/&lt;/a&gt;&lt;/p&gt;</description><pubDate>Tue, 16 Apr 2013 02:02:21 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>New Blog Feature: Tags</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=68</guid><link>https://brianmacintosh.com/blog/comments.php?post=68</link><description>&lt;p&gt;I&#039;ve updated the blog again with another new feature - tags.  Each post is now tagged with a number of strings based on what it&#039;s about.  To see more posts about the same subject, just click on one of the tags in the top line.&lt;/p&gt;</description><pubDate>Sat, 23 Mar 2013 19:04:17 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Computers in computers - Camera Obscura Adder</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=66</guid><link>https://brianmacintosh.com/blog/comments.php?post=66</link><description>&lt;p&gt;It&#039;s always fun to see people building computer-like circuits in games like Minecraft and Dwarf Fortress.  While it&#039;s outlandishly impractical to build computers in computers, it&#039;s just so much fun and so educational.  Well, today I figured out how to do it in the Camera Obscura engine using moving platforms and I was irrationally excited about it, so I built a four-bit &lt;a href=&quot;https://en.wikipedia.org/wiki/Adder_(electronics)&quot;&gt;adder&lt;/a&gt; circuit.  It adds two four-bit numbers together and show the results.  Check it out:&lt;/p&gt;
&lt;p&gt;&lt;iframe title=&quot;Camera Obscura Adder Video&quot; width=&quot;480&quot; height=&quot;360&quot; src=&quot;https://www.youtube.com/embed/29uXM4a7D3s?rel=0&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;You can download the level &lt;a href=&quot;https://www.brianmacintosh.com/cameraobscura/level/adder.cmb&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Boring details on how this works: there are several very small sets of &lt;a href=&quot;https://en.wikipedia.org/wiki/Logic_gate&quot;&gt;logic gates&lt;/a&gt;, the basic building blocks of electronic chips, that can be provably used to create every other possible logic gate (trivia: NAND gates alone are sufficient, as are NOR gates).  Camera Obscura&#039;s mechanics are capable of creating two gates: OR, by simply linking multiple sources to the same moving platform, and NOT (at least as far as I&#039;ve discovered).  Fortunately these two gates together are sufficient.  Information can propagate through the system because moving platforms can press buttons that trigger other platforms...and so forth.&lt;/p&gt;
&lt;p&gt;This possibility also provides some pseudo-scripting functionality to game levels.  Imagine a passcode-protected vault that only opens when you enter the right number, or even a game of &lt;a href=&quot;https://en.wikipedia.org/wiki/Mastermind_(board_game)&quot;&gt;Mastermind&lt;/a&gt; within the level.&lt;/p&gt;</description><pubDate>Sun, 17 Mar 2013 01:00:53 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Camera Obscura Demo Release</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=65</guid><link>https://brianmacintosh.com/blog/comments.php?post=65</link><description>&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/camico1.jpg&quot; alt=&quot;Super awesome Camera Obscura title image&quot;&gt;&lt;/p&gt;
&lt;p&gt;This week marks the first public release of a playable demo for Camera Obscura!  The released demo contains 20 levels out of the 100 total in the full game.  We have also included the full level editor, so you can make and share custom levels without limit.&lt;/p&gt;
&lt;p&gt;We are very excited to be at this stage where we can finally begin to get solid feedback from people based on how the game actually plays.  Please download it and let us know what you think, and remember to support us on &lt;a href=&quot;https://steamcommunity.com/sharedfiles/filedetails/?id=121847415&quot;&gt;Greenlight&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Download&lt;/b&gt;&lt;br&gt;
&lt;a href=&quot;https://www.brianmacintosh.com/cameraobscura/CameraObscuraDemo_msi.zip&quot;&gt;Demo Installer (Recommended)&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;https://www.brianmacintosh.com/cameraobscura/CameraObscuraDemo_zip.zip&quot;&gt;Demo ZIP&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The process of releasing a demo was a surprisingly lengthy one.  I always thought I would just compile a release build, stick a readme file in it, and send it out to the internet.  As it turned out, however, there were numerous aspects of the game that had to be examined and tweaked to make sure publication went (and continues to go) smoothly.  In addition to the normal, everyday tasks of polishing features and tackling bugs, I had to consider what parts of the user&#039;s saves needed to be kept for future versions of the game (like their options and achievements) and which parts would need to be thrown out later, and build in a mechanism for allowing that.  I also had to build an installer to ensure the users would have all the right dependencies (runtime dependencies can suck).  And, of course, we had to test the heck out of every other aspect of the game, as well.  The thought of someone putting aside the game because it crashed on the menu screen is not a nice one.  So there&#039;s my semi-educational post-mortem thing for publishing a demo.&lt;/p&gt;</description><pubDate>Thu, 28 Feb 2013 04:05:47 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>XNA Bitmap Font Library Release</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=64</guid><link>https://brianmacintosh.com/blog/comments.php?post=64</link><description>&lt;p&gt;I&#039;ve just released some code I&#039;ve had for a while. This library allows you to use bitmap font images to draw fancy and stylish text to the screen in an XNA project. It was used in &lt;a href=&quot;https://brianmacintosh.com/projects/project.php?proj=6&quot;&gt;Music Island&lt;/a&gt; to strings using bamboo-styled text.&lt;/p&gt;
&lt;p&gt;More information and downloads are available on the &lt;a href=&quot;https://www.brianmacintosh.com/code/code.php?id=5&quot;&gt;code page&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Thu, 31 Jan 2013 19:41:57 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Super Pirate Box Release</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=63</guid><link>https://brianmacintosh.com/blog/comments.php?post=63</link><description>&lt;p&gt;I finished up polishing the menus and high scores for Super Pirate Box. The completed game is now available on the &lt;a href=&quot;https://www.brianmacintosh.com/projects/project.php?proj=10&quot;&gt;project page!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Frantic pirate-shoving action&lt;/li&gt;
&lt;li&gt;Online high-score tables&lt;/li&gt;
&lt;li&gt;Silliness&lt;/li&gt;
&lt;li&gt;Local statistics and personal high-score tracking&lt;/li&gt;
&lt;li&gt;Electromagnets as cheap plot devices&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hope you enjoy it!&lt;/p&gt;</description><pubDate>Sat, 26 Jan 2013 15:33:43 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Camera Obscura on Steam Greenlight</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=62</guid><link>https://brianmacintosh.com/blog/comments.php?post=62</link><description>&lt;p&gt;Camera Obscura has been submitted to Steam Greenlight as of this Sunday! We&#039;ve very excited to have a shot at publishing the game as we approach 2 years of development.  Visit Greenlight here and vote for us:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://steamcommunity.com/sharedfiles/filedetails/?id=121847415&quot;&gt;Camera Obscura \ Steam Greenlight&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We&#039;ve also released a portion of the soundtrack on Youtube for your enjoyment:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=HqyBK9njHpc&amp;amp;list=PLvlKPp3QhJpuyuCNAd17k-hAmQjwYXXdG&quot;&gt;Camera Obscura Soundtrack&lt;/a&gt;&lt;/p&gt;</description><pubDate>Tue, 22 Jan 2013 14:41:28 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Super Pirate Box: 48 hours postmortem</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=61</guid><link>https://brianmacintosh.com/blog/comments.php?post=61</link><description>&lt;p&gt;Last weekend, I participated in a 48-hour game jam with UCI&#039;s Video Game Development Club. I had a lot of fun pulling a couple of 14-hour workdays with my fellow game developers. Together, we turned out four games in the weekend, spanning platforms including XNA, Unity, and SDL.&lt;/p&gt;
&lt;p&gt;I decided to use my weekend to learn more about using SDL with C++ to develop a 2D game. I spent some time in the preceding weeks writing some libraries for spriting and controls to simplify the process, but of course, there were still a few issues during the weekend. For one thing, I hadn&#039;t realized that SDL doesn&#039;t load PNG images natively. I was able to implement the SDL_image library, but that set me back a bit.&lt;/p&gt;
&lt;p&gt;Anyway, the game itself it an arcade-style top-down game. You play as a pirate who must repel legions of enemy pirates who try to board your ship. However, for some reason neither you nor any of the other pirates have weapons. So what do you do? You attempt to shove them overboard, of course. It&#039;s fast-paced action, easy to pick up, but difficult to master - and one slip-up means starting over from zero!&lt;/p&gt;
&lt;p&gt;I hope to be able to wrap the game up within a week with some basic menus and online highscores.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/superpirate1.jpg&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/superpirate1_ico.jpg&quot; alt=&quot;Super Pirate Box screenshot&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Update&lt;/b&gt;: Get the game &lt;a href=&quot;https://www.brianmacintosh.com/projects/project.php?proj=10&quot;&gt;on the project page&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Sun, 20 Jan 2013 04:12:36 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Side Project: Random Music Generation</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=60</guid><link>https://brianmacintosh.com/blog/comments.php?post=60</link><description>&lt;p&gt;This week&#039;s random side project was inspired by my friend &lt;a href=&quot;http://www.bryanploof.com/&quot;&gt;Bryan Ploof&lt;/a&gt; and my Music and Technology class.  We&#039;ve been discussing music generated by computers with little or no human influence, including attempts to map anything from &lt;a href=&quot;https://www.youtube.com/watch?v=V47C7AlTEUw&quot;&gt;fractals&lt;/a&gt; to &lt;a href=&quot;https://www.youtube.com/watch?v=t8g-iYGHpEA&quot;&gt;sorting algorithms&lt;/a&gt; to musical notes.  Michael Matthews gave a lecture on his research in creating music using cellular automata. &lt;a href=&quot;https://en.wikipedia.org/wiki/Cellular_automaton&quot;&gt;Cellular automata&lt;/a&gt; are sets of simple rules that define how a grid of &quot;cells&quot; evolves over time.  They provide very interesting possibilities in the generation of music because their rules often generate musically interesting patterns and progressions.  Michael&#039;s approach was to use a one-dimensional automata to control the pitches and timbres of sound available to a player, who modulated the sound directly through motions picked up by a webcam.&lt;/p&gt;
&lt;p&gt;My goal was to make a system that could act autonomously to create a unified tune with a strong melody.  My approach was to create three seperate automata to control different aspects of the music. One controls the rhythm of the song by selecting the timing of each note (quarter, eighth, etc). The other two control the notes that are played: one selects a chord from a pre-defined set, and the other selects which notes from the chord are activated.&lt;/p&gt;
&lt;p&gt;Here&#039;s a sample! This video uses a few chords selected from the Star Wars theme to generate a tune.&lt;/p&gt;
&lt;p&gt;&lt;iframe title=&quot;Automata Music Generator Video&quot; width=&quot;480&quot; height=&quot;360&quot; src=&quot;https://www.youtube.com/embed/AmKJ3FN87Bs?rel=0&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;An executable and the full C++ source are available on my &lt;a href=&quot;https://www.brianmacintosh.com/code/code.php?id=4&quot;&gt;code page&lt;/a&gt;.  Future plans for the project may include replacing the chord-selection mechanism with a Markov chain to make it more musically coherent, and implementing samples and ADSR so the notes can be things other than sine and square waves.&lt;/p&gt;</description><pubDate>Mon, 10 Dec 2012 21:18:09 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Camera Obscura IGF Update</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=59</guid><link>https://brianmacintosh.com/blog/comments.php?post=59</link><description>&lt;p&gt;Here&#039;s a long overdue update on Camera Obscura.  It&#039;s been quite a while since I&#039;ve posted about it, but work has been continuing on. We submitted the game to the &lt;a href=&quot;http://www.igf.com/php-bin/entry2013.php?id=1076&quot;&gt;Independent Games Festival&lt;/a&gt;, for which the results are expected in January. The current plan is to beginning working on release at that point, hopefully with some more recognitions to our name!&lt;/p&gt;

&lt;p&gt;There&#039;s tons of new stuff now, including over 50 levels, a vast array of background and tile art, and a number of new features for tracking statistics, best scores, and achievements. Oh, and a final level, complete with cutscenes and a &quot;final boss&quot; of sorts. This video should demonstrate some of the new shinies:&lt;/p&gt;

&lt;p&gt;&lt;iframe title=&quot;Camera Obscura Update Video&quot; width=&quot;640&quot; height=&quot;360&quot; src=&quot;https://www.youtube.com/embed/wwlQCN16P6M&quot;  allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;</description><pubDate>Sun, 02 Dec 2012 22:39:23 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Windows Phone Code Release</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=58</guid><link>https://brianmacintosh.com/blog/comments.php?post=58</link><description>&lt;p&gt;About a year back I wrote a couple of classes to aid rapid Windows Phone app development in my development group. I&#039;ve decided to release them on my site and announce them in the hopes that anyone else might be able to make use of them.&lt;/p&gt;
&lt;p&gt;This includes these three files: The static TMicrophone class and the static TAccelerometer class, which provide wrappers on the the existing microphone and accelerometer APIs that greatly simplify their use - most useful functionality is available through simple wrapper methods. The final file contains Sprite and SpriteSheet classes that provide simple, lightweight spritesheet loading and sprite creation, with variable-speed playback and circle-to-circle and box-to-box collision.&lt;/p&gt;
&lt;p&gt;For more detailed information and downloads, visit this page: &lt;a href=&quot;https://www.brianmacintosh.com/code/code.php?id=3&quot;&gt;https://www.brianmacintosh.com/code/code.php?id=3&lt;/a&gt;&lt;/p&gt;</description><pubDate>Mon, 26 Nov 2012 15:48:15 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Primeval (Tiles) Update</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=57</guid><link>https://brianmacintosh.com/blog/comments.php?post=57</link><description>&lt;p&gt;I just uploaded a small update to &lt;i&gt;Primeval&lt;/i&gt;. It fixes a bug where the music did not loop, and improves the animations for transitioning from win and lose states.&lt;/p&gt;</description><pubDate>Fri, 09 Nov 2012 14:57:36 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>New Game: Primeval</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=55</guid><link>https://brianmacintosh.com/blog/comments.php?post=55</link><description>&lt;p&gt;I just posted a small game I&#039;ve been working on lightly since the Ludum Dare 24. The game, &lt;i&gt;Primeval&lt;/i&gt; (not to be confused with &lt;i&gt;Primeval Labs&lt;/i&gt;), is the second of the two ideas I was considering for the Ludum Dare. It&#039;s a rather mind-bending tile-swapper combining mechanics of Conway&#039;s Game of Life and Rock-Paper-Scissors. My goal in creating this game was to learn Flash and ActionScript 3 while experimenting with this idea.  I had opted to create the more traditional and straightforward &lt;i&gt;Primeval Labs&lt;/i&gt; for the Dare because I wasn&#039;t sure how well these mechanics would balance or whether the game would even be viable. After a few iterations in Flash, fortunately, it is, and now you can play it &lt;a href=&quot;https://www.brianmacintosh.com/projects/primevaltiles/&quot;&gt;right here&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Here&#039;s a picture:&lt;/P&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/projects/primevaltiles/&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/projects/primevaltiles/primevaltiles2.jpg&quot; width=&quot;400&quot; alt=&quot;Primeval tiles screenshot&quot;&gt;&lt;/a&gt;&lt;/p&gt;</description><pubDate>Wed, 31 Oct 2012 18:49:41 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Side-Project of the Week: Randomized Dungeons</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=54</guid><link>https://brianmacintosh.com/blog/comments.php?post=54</link><description>&lt;p&gt;This week, my friends Chris and Kevin and I were hanging out late one night.  This, of course, led to  a number of crazy ideas being bounced around (this, of course, is how most software engineering gets started).  I actually decided that one of these crazy ideas might be doable, cool, and useful: a program that procedurally generates tabletop-RPG-style dungeons: monsters, loot, and most importantly, interesting and complex maps. I&#039;m also using the project as an opportunity to learn more about rendering custom controls in a native Windows Forms project.&lt;/p&gt;

&lt;p&gt;This is what it looks like, about three days later:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/daedalus1.jpg&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/daedalus1.jpg&quot; width=&quot;480&quot; alt=&quot;Random dungeon generator screenshot&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It can certainly generate some very entertaining map layouts, what with the occasional hallway where the floor is lava.&lt;/p&gt;</description><pubDate>Wed, 03 Oct 2012 14:55:16 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>48 Hours Later</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=53</guid><link>https://brianmacintosh.com/blog/comments.php?post=53</link><description>&lt;p&gt;The game, entitled &quot;Primeval Laboratories&quot;, is done as of 6:00 PM yesterday!  I think it turned out well.  I had a lot of fun making it and testing it, and seeing a genetic algorithm finally working is very satisfying.&lt;/p&gt;

&lt;p&gt;I&#039;ve always been decent at art for a programmer, and I guess I assumed that I&#039;d be able to do music and sound as well. Well, not in 48 hours, at least.  So I learned that I stink at that!&lt;/p&gt;

&lt;p&gt;Check it out &lt;a href=&quot;https://www.ludumdare.com/compo/ludum-dare-24/?action=preview&amp;amp;uid=15030&quot;&gt;here&lt;/a&gt;. I&#039;ll probably be making a page for it on my site here as well.&lt;/p&gt;</description><pubDate>Mon, 27 Aug 2012 19:12:26 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Genetic Algorithms are Interesting</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=52</guid><link>https://brianmacintosh.com/blog/comments.php?post=52</link><description>&lt;p&gt;The game is looking pretty cool, by the way, at least in my opinion. Maybe I&#039;ve just overly fascinated with this genetic thing.&lt;/p&gt;

&lt;p&gt;I&#039;m not quite convinced that it&#039;s working correctly, though. One trial run I did thought it would be a good idea to breed out every single weapon gene except for a single (rather mediocre) lime-green laser beam. To make matters worse, the children kept wasting their mutations on stupid things like turning the laser hot pink. I&#039;m bumping up the importance of dealing damage to try to tackle this. It&#039;s possible that we&#039;re just suffering from an extremely small sample size.&lt;/p&gt;</description><pubDate>Sun, 26 Aug 2012 02:49:59 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Particles</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=51</guid><link>https://brianmacintosh.com/blog/comments.php?post=51</link><description>&lt;p&gt;They make everything better.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/primeval_3.png&quot; width=&quot;640&quot; alt=&quot;Phwooosh&quot;&gt;&lt;/p&gt;</description><pubDate>Sat, 25 Aug 2012 19:26:12 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>I think this will work</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=50</guid><link>https://brianmacintosh.com/blog/comments.php?post=50</link><description>&lt;p&gt;I had a moment just now that greatly reassured me with this game&#039;s design. I just finished implementing the basic enemy logic - shooting, dying, and finally moving. The game, as I mentioned, is about randomly generated enemies that evolve with genetics (i.e. the ones that do well get to reproduce and make new enemies).&lt;/p&gt;

&lt;p&gt;After several of the enemies bobbed around shooting me, all of a sudden one popped out of the spawner, dove to within 20 pixels of me, and starting circling and bobbing really fast. It proceeded to destroy my face.&lt;/p&gt;

&lt;p&gt;Here are some pictures, but I think I need a video or demo to really show it off.&lt;/p&gt;

&lt;p&gt;&lt;img width=&quot;400&quot; src=&quot;https://www.brianmacintosh.com/blog/images/primeval_1.png&quot; alt=&quot;Primeval screenshot&quot;&gt;&lt;br&gt;
&lt;i&gt;A big fat enemy&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;img width=&quot;400&quot; src=&quot;https://www.brianmacintosh.com/blog/images/primeval_2.png&quot; alt=&quot;Screenshot with different weapon types&quot;&gt;&lt;br&gt;
&lt;i&gt;Enemies can have three types of weapons - lasers, bullets, and missiles&lt;/i&gt;&lt;/p&gt;</description><pubDate>Sat, 25 Aug 2012 16:24:10 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Ludum Dare #24 Is Fun</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=49</guid><link>https://brianmacintosh.com/blog/comments.php?post=49</link><description>&lt;p&gt;As expected, I wishy-washied over my game ideas some more and finally settled back on the shootemup with evolving enemies.  I&#039;ve started writing code now, so what&#039;s done is done as far as that goes.  The skeleton code for genome selection, crossover, and mutation is all in place, and I&#039;ve working on fleshing out the actually movement and firing code for both the play and the bots - that&#039;s going pretty well.&lt;/p&gt;

&lt;p&gt;The plan is for the game to spawn little evo-bots at a rapidfire pace to try to kill you. They&#039;ll be ranked based on how long they live and how much damage they do to you. After a certain number of spawns, the best ones will be picked and crossover and mutation will occur. Repeat. The &quot;genes&quot; that will get messed around with include stat boosts, weapons (and their individual stats), other gadgets like armor plates, and such.&lt;/p&gt;

&lt;p&gt;Also, it&#039;s a bit late for my brain. In case you were wondering.&lt;/p&gt;</description><pubDate>Sat, 25 Aug 2012 02:08:57 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Ludum Dare #24 Game Jam</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=48</guid><link>https://brianmacintosh.com/blog/comments.php?post=48</link><description>&lt;p&gt;A few days ago I heard &lt;a href=&quot;https://www.twitch.tv/siralaran&quot;&gt;from a friend&lt;/a&gt; about a competition for crazy people. Its creators would have you, given nothing but 48 hours and a theme, make a complete game. Naturally, this sounded like a pretty worthy use of 48 hours to me, so this is what I am doing as of about an hour ago.&lt;/p&gt;

&lt;p&gt;The required theme this weekend is &quot;evolution&quot;. I was got pretty attached to the first idea that popped into my head, which was a shmup where the enemies come in waves, each with a variety of features like armor and shields and unique guns and stats like attack speed and power. Each successive wave would be born from the most successful enemies of the previous wave - the enemies gradually becoming more and more deadly. It took some doing, but I managed to convince myself to think through some other ideas. Here I am about a (rather emotionally trying) hour later, with a different, rather simpler idea that&#039;s going to look more like the puzzle game offspring of Rock-Paper-Scissors and Conway&#039;s Game of Life. It would take far too long to explain it now, and I&#039;ll probably change it all anyway, but that&#039;s where it stands. More as it happens!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.ludumdare.com/compo/&quot;&gt;http://www.ludumdare.com/compo/&lt;/a&gt;&lt;/p&gt;</description><pubDate>Fri, 24 Aug 2012 22:13:42 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Mage Cage - Thunderfish Entertainment</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=47</guid><link>https://brianmacintosh.com/blog/comments.php?post=47</link><description>&lt;p&gt;Thunderfish Entertainment will be submitting another game to XBox Live Indie Games soon...&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/magecage.jpg&quot; alt=&quot;Mage Cage Title Screen&quot;&gt;&lt;/p&gt;
&lt;p&gt;More information as we progress through the review process in the next few weeks.&lt;/p&gt;</description><pubDate>Sat, 23 Jun 2012 12:36:14 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Normal Mapping Code Released</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=46</guid><link>https://brianmacintosh.com/blog/comments.php?post=46</link><description>&lt;p&gt;I was working on adding specular mapping to the normal mapping demo (a technique that imitates the &quot;shininess&quot; of a surface), but I ultimately decided to release the basic code now and perhaps create an updated library later.  Enjoy :).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/code/code.php?id=1&quot;&gt;Download Here&lt;/a&gt;&lt;/p&gt;</description><pubDate>Sun, 22 Apr 2012 22:59:13 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Dynamically Lighting 2D Scenes with Normal Maps</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=45</guid><link>https://brianmacintosh.com/blog/comments.php?post=45</link><description>&lt;p&gt;My random inspiration of this week occurred when one of my professors, Dan Frost, mentioned basic lighting techniques in lecture.  It turns out that for any surface, the final color of that surface with a light on it can be calculated quite simply by multiplying the surface&#039;s color by the color of the light times the dot product of the surface normal and the normalized vector from the light to the surface.  I thought to myself, &quot;I could totally do that.&quot;  Any about an hour later, I had this demo up and running:&lt;/p&gt;
&lt;p&gt;&lt;iframe title=&quot;Normal Mapping Demo Video&quot; width=&quot;640&quot; height=&quot;480&quot; src=&quot;https://www.youtube.com/embed/-D0UWzJYJl4?rel=0&amp;amp;modestbranding=1&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;Normal mapping has been traditionally used in 3D games on surface textures for 3D models.  In this context, its use can easily make an extremely low-poly object appear much more detailed at a low processing cost by rendering textures with lighting such that they appear to &quot;pop out&quot;.  In this demo, I have instead used it to fake a 3D effect on a completely flat 2D plane.&lt;/p&gt;
&lt;p&gt;The process is fairly straightforward.  First, the standard scene is rendered to a render target cleared black, with nothing special done.  Then, the scene is rendered a second time to a second render target, but this time the normal maps for each image, if they have one, are drawn instead of the standard image.  Normal maps encode information about the &lt;a href=&quot;https://en.wikipedia.org/wiki/Normal_(geometry)&quot;&gt;&lt;i&gt;surface normal&lt;/i&gt;&lt;/a&gt;, or the direction the surface faces, of each pixel in an image.  In most implementations, the X, Y, and Z components of the normal vector are encoded as the R, G, and B components of the color of a pixel on an image.  This can be seen toward the end of the above video.  This second render target is cleared RGB(128, 128, 255) so that images that do not have normal maps can be rendered as flat planes.  Finally, both of these renders are passed to a shader that calculates the final color of each pixel in the first image using information about the locations and colors of all the lights in the scene, and the pixel&#039;s normal from the second image.&lt;/p&gt;
&lt;p&gt;I plan to post the code from this demo soon, after I get my work on ambient light, directional light, and multiple point lights in there, so look out for it!&lt;/p&gt;</description><pubDate>Fri, 13 Apr 2012 12:45:15 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Making Music Games (a programmer&#039;s postmortem)</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=44</guid><link>https://brianmacintosh.com/blog/comments.php?post=44</link><description>&lt;p&gt;Being a rhythm game, Music Island presented a number of unique and fun challeges from a programming perspective.  The great difficulty in programming rhythm-based games is in keeping gameplay synchronized with the game&#039;s music.  A fully-featured triple-A engine like BASS might be able to analyze the music in real-time and use it to guide gameplay.  However, for our one-programmer team, analyzing the stream in real-time was not really an option.  We would have to find some way to overlay music onto the game and force the game to keep pace with it.&lt;/p&gt;
&lt;p&gt;The concept was fairly simple.  We would use MP3 music.  With the length of the song, the number of measures, and the time signature, I can calculate the time in milliseconds between each beat - or any subdivision of the beat.  When the song is running, the program keeps track of which beat it is on simply by counting up with a Stopwatch.  When the time exceeds the amount of time per beat, we go to the next one (carrying over the leftover time).&lt;/p&gt;
&lt;p&gt;To have the game actually use this information, I determine what kind of beat the song was currently on (quarters, eighths, thirty-seconds, etc) and the distance in thirty-second notes from the nearest quarter note.  If that value is within a threshold, I accept input and generate a spell.&lt;/p&gt;
&lt;p&gt;I found that MP3 files were not actually a sufficient solution, for our resources at least (the XNA engine).  Despite our best efforts to get accurate timings, I could not make the game stay in sync with the music.  Within 5 or 10 seconds, they would be on off-beats, and XNA offered me no way to control how the MP3 was being played to attempt to correct this.  I concluded that XNA&#039;s MediaPlayer class, which was playing the MP3s, was probably the issue, so our solution was to split the songs up into segments of WAVs.  In addition, our songs were designed and composed such that they could be split up into layers by instrument.  So we ended up with a bunch of two-measure wave files of single-instrument lines.  I wrote an XML format so our composer could stack and sequence these segments however he liked.  This helped cut down on the otherwise-huge filesize wav files would have caused by re-using tunes multiple times in a song.&lt;/p&gt;
&lt;p&gt;Now with these segmented WAVs, we had far more control over the speed the music was played at, and we were able to synchronize the music periodically.  This was ultimately sufficient to keep the game as a whole completely in sync.  It was a feature we were still tweaking, though, even after the game&#039;s first submission!&lt;/p&gt;</description><pubDate>Tue, 20 Mar 2012 00:39:09 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Music Island RELEASE</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=43</guid><link>https://brianmacintosh.com/blog/comments.php?post=43</link><description>&lt;p&gt;That&#039;s right, it&#039;s OUT!  Music Island is finally through the XBox Live Indie Games review process, and was released just minutes ago on the same system.&lt;/p&gt;
&lt;p&gt;I&#039;m very excited to finally have been behind a truly published game.  We&#039;re giving out the trial version of the game for &lt;b&gt;free on the PC&lt;/b&gt;, and you can get it &lt;a href=&quot;http://dl.dropbox.com/u/13891352/MusicIslandDemoInstall.zip&quot;&gt;here as an installer&lt;/a&gt; that will take care of everything, or &lt;a href=&quot;http://dl.dropbox.com/u/13891352/MusicIslandDemoFiles.zip&quot;&gt;here as an executable&lt;/a&gt; if you already have the XNA and .NET frameworks.  And, of course, you should buy it on XBox Live Indie Games!&lt;/p&gt;</description><pubDate>Mon, 19 Mar 2012 15:28:05 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Music Island Release Date</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=42</guid><link>https://brianmacintosh.com/blog/comments.php?post=42</link><description>&lt;p&gt;Music Island has finally been approved by Xbox Live Indie Games, and the release date is set for &lt;b&gt;March 19th&lt;/b&gt;!  Finally, Thunderfish&#039;s first game will be out for purchase.  I think all the work we&#039;ve put in since June of last year has paid off, and we have a fine game to show for it.  Pick it up if you can, especially if you&#039;re a fan of rhythm- and beat-oriented games!&lt;/p&gt;

&lt;p&gt;&lt;iframe title=&quot;Music Island Launch Trailer&quot; width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/l2dnqivqFdU&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;</description><pubDate>Wed, 14 Mar 2012 13:03:19 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>RPG Engine Jam</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=41</guid><link>https://brianmacintosh.com/blog/comments.php?post=41</link><description>&lt;p&gt;Yesterday I got roped into an awesome programming jam session with fellow game programmers Stephen Herlihy, &lt;a href=&quot;http://www.alexnaraghi.com/&quot;&gt;Alex Naraghi&lt;/a&gt;, and &lt;a href=&quot;http://www.brendenbooth.com&quot;&gt;Brenden Booth&lt;/a&gt;, aided and abetted by production &lt;a href=&quot;http://www.justinbritch.com/&quot;&gt;Justin Britch&lt;/a&gt; and &lt;a href=&quot;http://www.bryanploof.com/&quot;&gt;Bryan Ploof&lt;/a&gt;.  Our goal: create an engine for a top-down role-playing game in the style of Diablo and Torchlight. Oh yeah, and users have to be able to build and play their own games in it with zero programming and scripting. Oh yeah, and we only had 12 hours.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/thunderquest.jpg&quot; alt=&quot;Thunderquest Editor Screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;It doesn&#039;t look like much (I&#039;m a programmer, Jim, not an artist), but this demo features enemies, melee combat, player death, an attack spell, and jumping. What&#039;s more, it is paired with a well-featured editor, and both are built on an extremely flexible component system that defines functionality for generic &quot;game objects&quot; by assigning them components like Combatable, Impassable, and Mobile. Users can add generic objects to the game, alter their appearance, and change their behaviors simply by adding and removing components. You&#039;ll be hearing more about this one in the future.&lt;/p&gt;</description><pubDate>Sun, 19 Feb 2012 17:08:35 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Music Island Back In Review...</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=40</guid><link>https://brianmacintosh.com/blog/comments.php?post=40</link><description>&lt;p&gt;The XBLIG review process has been long, but Music Island is in review for hopefully the final week or two before its release. Despite the lack of support for Live leaderboards for indie games, Music Island features a leaderboard system through the use of a distributed storage technique that should allow highscores to transfer through the system, giving players the chance to compare themselves to others in the game.&lt;/p&gt;

&lt;p&gt;One reviewer: &quot;My four year old couldn&#039;t get past the brown mask.   She just kept saying &#039;the guy looks too weird and creepy&#039;.  I thought the art was cute, so take those comments with a grain of salt!&quot;&lt;/p&gt;

&lt;div class=&quot;centeralign&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/idle_0.png&quot; alt=&quot;Crazy Island Man&quot; width=&quot;174&quot; height=&quot;206&quot; &gt;&lt;/div&gt;</description><pubDate>Sun, 05 Feb 2012 17:46:06 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Music Island Release</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=39</guid><link>https://brianmacintosh.com/blog/comments.php?post=39</link><description>&lt;p&gt;Our first XBox Live Indie game has been submitted to peer review this week!  This game was begun in June of last year and finished in early December.  The remainder of December was spent shooting bugs, which were quite prevalent!&lt;/p&gt;
&lt;p&gt;Music Island is a rhythm-based arcade-style game with generative music.  In it, you must defend an island from streams of invading sea creatures by casting the appropriate spell at them on the song&#039;s beat.  This action generates musical notes that build on the song&#039;s background rhythm.  The game features a 10-level Story or tutorial mode, and the highscore-based Infinite mode.&lt;/p&gt;
&lt;p&gt;This project was a good experience in working with a small team to make a clear, organized game.  The game was produced by Justin Britch, with music and sound by Bryan Ploof and art and design by Jacob Anderson.  The programming was done by myself.  I will post when the game is approved and available on the XBox Live Indie system.&lt;/p&gt;
&lt;p&gt;&lt;iframe title=&quot;Music Island Trailer&quot; width=&quot;640&quot; height=&quot;360&quot; src=&quot;https://www.youtube.com/embed/bYNh9pMkWNo&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.thunderfishentertainment.com&quot;&gt;thunderfishentertainment.com&lt;/a&gt;&lt;/p&gt;</description><pubDate>Thu, 12 Jan 2012 02:22:20 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Camera Obscura Enemies</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=38</guid><link>https://brianmacintosh.com/blog/comments.php?post=38</link><description>&lt;p&gt;Some new enemy art going into Camera Obscura.  Aren&#039;t those walkers cute?&lt;/p&gt;
&lt;p&gt;&lt;iframe title=&quot;Camera Obscura Walkers Video&quot; width=&quot;640&quot; height=&quot;360&quot; src=&quot;https://www.youtube.com/embed/eJhSWp5Io3w?rel=0&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;</description><pubDate>Sun, 01 Jan 2012 13:06:19 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Orcs Must Die! Design Analysis</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=37</guid><link>https://brianmacintosh.com/blog/comments.php?post=37</link><description>&lt;p&gt;I haven&#039;t been moved to write one of these for a while, as you might have noticed.  However, I started up a game called Orcs Must Die! today, and I am enjoying it pretty thoroughly.  I had just finished hurling a column of hunched, waddling orcs into a pit full of acid with a wind spell and was watching my character drop some ridiculous dance moves when it occurred to me that the game was, on the whole, pretty silly.  Orcs Must Die! uses silliness pretty effectively to create a fun and satisfying game, and that&#039;s what I want to examine here.&lt;/p&gt;
&lt;p&gt;Watch this so you know what I&#039;m talking about: &lt;a href=&quot;https://www.youtube.com/watch?v=pioXot-rQ2U&quot;&gt;https://www.youtube.com/watch?v=pioXot-rQ2U&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Orcs Must Die! is a game about an apprentice whose master has just died defending a Rift from invading hordes of orcs.  In a departure from tradition, said apprentice is not wracked with grief, but is instead rather excited to have acquired his master&#039;s tome of traps and spells (&quot;Rest well, crazy old man!&quot;).  He takes up the task of defending various Rifts from the aforementioned hordes of orcs who would like nothing better than to fling themselves into them.&lt;/p&gt;
&lt;p&gt;The reason Orcs Must Die! is so successful as a game is that it knows exactly what it wants to be.  By that over-used saw, I mean that the developers had one guiding goal or theme for the game, it that theme is present in all parts of it.  For Orcs Must Die!, the theme is &quot;just have fun!&quot;  The short introduction cutscene sets the tone quite nicely, and the effect is maintained by the gameplay.  At every point in the game, the design maintains in the player the sense of non-seriousness it begins with.  Between the orc graphics, which are certainly cartoony in a Bastion sort of way, to the trap designs, which include such things as plates that fling orcs down the hall and the classic falling chandelier, there are certainly enough reminders of fun anywhere the player turns.  Perhaps the best, though, is the character himself.  The game is third person, and the main character has a definite identity seperate from the player.  He keeps up a stream of snarky comments (&quot;Here, mister orcky orcky&quot;) (&quot;Gee, I hope no one gets hurt.  Eh...not really.&quot;) that are the best anchor for the well-crafted atmosphere of &quot;just have fun&quot;.&lt;/p&gt;
&lt;p&gt;Of course, I don&#039;t believe that games that don&#039;t say &quot;just have fun&quot; are bad.  Amnesia, for example, is themed after mystery and horror and of course suceeds in creating a game focused on just that.  Where games fail is when they lose sight of the overarching themes they began with.  The serious opening cutscene narrated by the character&#039;s master serves only to make the main character even more comical by contrast when it becomes clear that the game is not as dire as he makes out.  A game similar to Orcs Must Die! that is, in my opinion, less successful in this field is Dungeon Defenders.  It is strikingly similar, in fact, so it makes an excellent comparision.  It has the potential and the setup to be a comical and fun experience like Orcs Must Die! - the opening describes how the four heroes that protect the land are lost, and it&#039;s up to their apprentices (miniature and caricaturized versions of the heroes themselves) to do so.  Dungeon Defenders, however, loses sight of this theme in the midst of an RPG-style leveling and equipment system that is very reminiscent of games like Torchlight.  It too uses a cartoony graphics style but there is little beyond that that follows up on any kind of overarching goal, and the themes of the game during gameplay don&#039;t extend much beyond &quot;medieval style&quot;.&lt;/p&gt;
&lt;p&gt;Now, there are a lot of Orcs Must Die! vs. Dungeon Defenders discussions on the internet, and they show that while these themes are important, people often buy games on criteria other than how fun the game was.  On commenter said, &quot;I&#039;m waving on the side of Dungeon Defenders even tho I enjoyed the OMD demo a lot more,&quot; referring to the higher expected replayability offered by Dungeon Defenders by its RPG elements and multiplayer support.  Themes and atmosphere are clearly not the only elements that make a successful game, but they factor in significantly.&lt;/p&gt;</description><pubDate>Fri, 23 Dec 2011 11:43:59 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Camera Obscura Trailer</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=36</guid><link>https://brianmacintosh.com/blog/comments.php?post=36</link><description>&lt;p&gt;&lt;iframe title=&quot;Camera Obscura Trailer&quot; width=&quot;640&quot; height=&quot;360&quot; src=&quot;https://www.youtube.com/embed/YuT4qOLSdq8?rel=0&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;We&#039;ve just recorded a new trailer of this nearly feature-complete version of Camera Obscura.  It demonstrates some of our cool new features, like the crawler enemies (shown briefly) that can climb walls and walk on ceilings.  One of my personal favorite features of the game so far.  It also demonstrates the basic ideas of the gameplay more clearly, without all that mucking around testing collision ;).&lt;/p&gt;</description><pubDate>Sun, 30 Oct 2011 00:53:29 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Camera Obscura Status Update</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=35</guid><link>https://brianmacintosh.com/blog/comments.php?post=35</link><description>&lt;p&gt;Camera Obscura is still trucking along.  Summer is drawing to a close, and we hope to be done with the game&#039;s code by the time school begins.  Most of the work that is left is with our level designers and our excellent artist, Dean Bottino.  More gameplay videos and maybe some post-mortem-type stuff will be forthcoming.&lt;/p&gt;</description><pubDate>Sat, 10 Sep 2011 12:18:05 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Far Cry Design Review</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=34</guid><link>https://brianmacintosh.com/blog/comments.php?post=34</link><description>&lt;p&gt;I played &lt;i&gt;Far Cry&lt;/i&gt; (yes, the first one - on the PC, by the way) a few weeks ago, and thoroughly enjoyed it (well, a good 90% of it, anyway).  While I&#039;m pretty tolerant in general and don&#039;t often find a game that I &lt;i&gt;don&#039;t&lt;/i&gt; like, there were a number of interesting design aspects of &lt;i&gt;Far Cry&lt;/i&gt; that I think made it good.  I wanted to look at a few of those, as they are things that others can easily emulate and that I think are better than their common alternatives.&lt;/p&gt;
&lt;p&gt;I&#039;m generally one of those people who says, &quot;oh boy, it&#039;s another generic first-person shooter where you can kill completely unrealistic numbers of generic aliens/soldiers/terrorists while following the terrible linear plotline&quot;.  And yes, &lt;i&gt;Far Cry&lt;/i&gt; is this.  But &lt;i&gt;Far Cry&lt;/i&gt; does this in an extremely interesting and fun way that made forget about its genericness and really enjoy playing it.  The main reason for this is the amazingly believable and interactive world &lt;i&gt;Far Cry&lt;/i&gt;&#039;s designers have crafted.  They have somehow created a world that is fun to interact with and explore, even though it&#039;s built around a cheesy rehash of the old Time Crisis mad scientist theme and populated by a really unlikely number of mercs.&lt;/p&gt;
&lt;p&gt;How do they achieve this?  What &lt;i&gt;Far Cry&lt;/i&gt; has done is thrown out every cop-out design choice commonly used by designers of first and third-person games and replaced them with elements that serve the same purpose, but also feel like a natural part of the world.  I guess the word to use here would be &quot;immersion&quot;, though it seems overused in this field.  I&#039;ve picked out some of the great features of &lt;i&gt;Far Cry&lt;/i&gt;&#039;s world below.&lt;/p&gt;
&lt;p&gt;There are no hard world boundaries or &quot;invisible walls&quot;, at least none that are reachable in the course of normal game play.  The gating that keeps the player moving roughly along the route built by the game designers is incorporated realistically into the world.  For example, steal a patrol boat and attempt to leave the island for the open sea?  Almost every other game would place an invisible wall at some point out in the ocean, or perhaps kill the player with no good explanation as to his cause of death.  We&#039;ve come to accept these methods, and we don&#039;t (conciously) hate them, even though they are lame and immersion-breaking.  But &lt;i&gt;Far Cry&lt;/i&gt; does better.  If you try to do this, the NPC narrator who keeps in contact with you via radio warns you that the mercenaries&#039; radar systems will spot you on the open water.  If you proceed, an attack helicopter flys to your location and guns you down.  If you&#039;re looking the right way, you can even see the helicopter take off from the jungle and pursue you.  This doesn&#039;t feel out-of-place or even unfair - I&#039;ve neutralized attack helicopters before, and I feel like I have a chance against this one, but they&#039;re powerful enough that I don&#039;t feel cheated when it does get me.  Most importantly, it doesn&#039;t break immersion like the repeated and highly unlikely excuse that there are &quot;enemy mortars covering the area&quot;, the &quot;return to the battlefield&quot; warning, or the invisible wall.&lt;/p&gt;
&lt;p&gt;The other common gating cop-out &lt;i&gt;Far Cry&lt;/i&gt; revises is the &quot;jungle path&quot;.  Games that take place in a jungle, as &lt;i&gt;Far Cry&lt;/i&gt; dominantly does, often try to keep the player on their neatly laid-out rails with walls of impassable shrubbery on either side of the path, or perhaps embankments that are &lt;i&gt;just&lt;/i&gt; too steep to climb.  These sorts of methods have the effect of slashing away huge portions of the game world in the player&#039;s mind.  It doesn&#039;t feel like one world that they happen to be currently inhabiting a small jungle path within.  It feels like a small path that exists only for them to run along it and complete the level.  &lt;i&gt;Far Cry&lt;/i&gt;, however, thrives on its small but (seemingly) unified world.  It avoids this &quot;jungle path&quot; effect in two ways.  One, it rarely tries to restrict the player closely to a path.  Most games have to do this because they have laid out their enemies and their cover such that they expect the player to approach the encounter from a specific point, and if the player were to approach from a different direction entirely, it would break the difficulty of the encounter.  &lt;i&gt;Far Cry&lt;/i&gt; allows its level design to ignore these narrow restrictions because its enemy placement and AI are designed around this idea.  The enemies mind their own business in camps and outposts until the player is spotted, at which time they are capable of taking cover, providing covering fire and attempting to flank and attack, and no matter where the player approaches from, they are capable of reacting dynamically to preserve the difficulty of the encounter.  This allows &lt;i&gt;Far Cry&lt;/i&gt; to achieve a very cool unity in its world, despite the fact that it is technically linear and divided up into a number of completely seperate &quot;levels&quot; as most games are.&lt;/p&gt;
&lt;p&gt;I could go on, but I&#039;m going to stop there for now.&lt;/p&gt;</description><pubDate>Sat, 30 Jul 2011 19:47:57 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Camera Obscura Early Gameplay Video</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=33</guid><link>https://brianmacintosh.com/blog/comments.php?post=33</link><description>&lt;p&gt;As promised, the game now has all the significant animations implemented, so here&#039;s a video!&lt;/p&gt;
&lt;p&gt;&lt;iframe title=&quot;Camera Obscura Early Gameplay Video&quot; width=&quot;425&quot; height=&quot;349&quot; src=&quot;https://www.youtube.com/embed/clMSiT0iwd4&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;</description><pubDate>Wed, 01 Jun 2011 02:11:20 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Camera Obscura Screenshots</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=32</guid><link>https://brianmacintosh.com/blog/comments.php?post=32</link><description>&lt;p&gt;Got some screenshot of Camera Obscura with our new player sprites. I plan to show a video as soon as all the frames are done.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/cameraobscura1.jpg&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/cameraobscura1thumb.jpg&quot; alt=&quot;Camera Obscura Screenshot&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/cameraobscura2.jpg&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/cameraobscura2thumb.jpg&quot; alt=&quot;Camera Obscura Screenshot&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In other news, the Video Game Development Club just released its first for-sale game on XBox Live! The game is Nucleon - it&#039;s a pretty intense puzzle/arcade/action game and several of the people on the Camera team are addicted to it. Check it out &lt;a href=&quot;http://marketplace.xbox.com/en-US/Product/Nucleon/66acd000-77fe-1000-9115-d80258550868?cid=search&quot;&gt;here&lt;/a&gt; (it&#039;s only a dollar!). We&#039;ve very interested in seeing how it does - personally I think that XBox Live gives indie games the short end of the stick. All indie games on the marketplace are only a dollar, which puts some honestly bad games on par with well-done ones like Nucleon and the surprisingly addictive and interesting I MAED A GAM3 W1TH Z0MB1ES!!!1, but we&#039;re still interested to see how Nucleon does.&lt;/p&gt;</description><pubDate>Sun, 29 May 2011 17:49:14 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Camera Obscura Update</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=31</guid><link>https://brianmacintosh.com/blog/comments.php?post=31</link><description>&lt;p&gt;Thought I should post what kind of progress is being made on Camera Obscura, as that is my focus as far as game programming right now. We just won $100 at UCI&#039;s Game Jam Popular Choice competition, at which 40-something people voted our game as one of the best shown (the second place team received 27 votes!)  This should cover the fees associated with the game&#039;s eventual publication to XBox Live. Programming progress is quite good - we&#039;ve fixed almost every known bug, and polished up a lot of the early levels to help teach players the game&#039;s mechanics.&lt;/p&gt;
&lt;p&gt;Inspiration for this part of the game is coming from games such as Portal and Braid: we want to ease the player into each of the game&#039;s mechanics, making him or her figure out how they work, guiding them to the solution and slowly giving them more and more to think about on their own. And we want to make absolutely minimal use of text boxes: show, don&#039;t tell.&lt;/p&gt;</description><pubDate>Thu, 12 May 2011 19:08:55 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Nonfunctional Games</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=30</guid><link>https://brianmacintosh.com/blog/comments.php?post=30</link><description>&lt;p&gt;It seems that Windows 7 Service Pack 1 broke &lt;i&gt;all&lt;/i&gt; games made in DarkBASIC Pro, which would include all of those posted here. I&#039;ll need to recompile all of them with the fixed DBP compiler and reupload them. If you get an error saying that the &quot;parameter is invalid&quot;, try downloading the game again.&lt;/p&gt;</description><pubDate>Sun, 17 Apr 2011 12:38:36 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Game Jam Press and Camera Obscura Download</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=28</guid><link>https://brianmacintosh.com/blog/comments.php?post=28</link><description>&lt;p&gt;The UCI Game Jam was featured rather prominently in the Orange County Register this week, and my team (Rainbow Dice Games) was interviewed for the article (though I was at class).  They provided download links for the four completed games that came out of the competition, so I guess I can&#039;t hide that any more: &lt;a href=&quot;http://ocunwired.ocregister.com/2011/04/13/uci-students-build-games-in-a-week/7131/&quot;&gt;link&lt;/a&gt;!  Remember that this is one week of work, and we plan to continue improving our game possibly into something saleable.&lt;/p&gt;</description><pubDate>Thu, 14 Apr 2011 15:59:59 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Spring Gam Jam END</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=27</guid><link>https://brianmacintosh.com/blog/comments.php?post=27</link><description>&lt;p&gt;This week has been so busy I didn&#039;t even have time to write a post in the middle of it.  But Game Jam is over and our game is done!  It turned out absolutely awesome, and the original idea was a great one.  There is talk of continuing to work on it and release on the XBox Live Arcade. I will try to post more info about the game itself soon.&lt;/p&gt;</description><pubDate>Tue, 12 Apr 2011 02:55:52 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Spring 2011 - Game Jam Again</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=26</guid><link>https://brianmacintosh.com/blog/comments.php?post=26</link><description>&lt;p&gt;It is Spring quarter here at UCI, and that means another Video Game Development Club one-week Game Jam! The teams are set up and every game must have something to do with &lt;b&gt;shadows&lt;/b&gt;.  Our team has the basics of a game idea pounded out, and by next Monday at 11:00 it needs to be functional. See you then ;).&lt;/p&gt;</description><pubDate>Tue, 05 Apr 2011 14:54:57 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>That TPS, Break, Part 2</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=22</guid><link>https://brianmacintosh.com/blog/comments.php?post=22</link><description>&lt;p&gt;Well, it&#039;s the second day since my last post. I had a lot of problems with playing two different animations on the same object (for example, making my player&#039;s lower body play a walking animation while his upper body pointed a gun). I tried about four different ways, and all of them were bugged in some unfathomable way and didn&#039;t &lt;i&gt;quite&lt;/i&gt; work right. I fell back on using two seperate objects, one with the lower body hidden and one with the upper body hidden, which I thought would create a terrible seam. Fortunately, it seems to be working okay (just wait &#039;til I get to crouching).&lt;/p&gt;
&lt;p&gt;Anyway, I should show some of those promised screenies:&lt;/p&gt;
&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/tps2.jpg&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/tps1thumb.jpg&quot; alt=&quot;Third Person Shooter Screenshot&quot;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;https://www.brianmacintosh.com/blog/images/tps1.jpg&quot;&gt;&lt;img src=&quot;https://www.brianmacintosh.com/blog/images/tps2thumb.jpg&quot; alt=&quot;Third Person Shooter Screenshot&quot;&gt;&lt;/a&gt;&lt;br&gt;
&lt;p&gt;So, outside of struggling with the animation, I put in grenades and started on the AI. It&#039;s gonna be AI for the next few days, I think.&lt;/p&gt;</description><pubDate>Thu, 24 Mar 2011 19:42:14 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Spring Break, Third Person Shooter Part 1</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=21</guid><link>https://brianmacintosh.com/blog/comments.php?post=21</link><description>&lt;p&gt;It&#039;s noon on Tuesday of Spring Break week, and I spend almost all of my waking hours since Sunday morning sitting here programming.  This is the project I&#039;ve mentioned a few times before.  The plan is to make a tactical, squad-based third-person shooter.  The game will play in a number of self-contained &quot;missions&quot;, each of which will be characterized by an important &quot;planning phase&quot; and then an &quot;execution phase&quot;.  During the planning phase, the player will complete a scouting mission (perhaps some sort of mini-game) to acquire information about the area the mission is targetted at (blueprints and maps and such), and will use it to lay out a rough plan for his squad members to follow. Then they and their squad complete the mission in the 3PS part of the game. The most notable elements in this part will be the ability to climb on and over walls and obstactles, and enemy AI and difficulty that should enable and encourage the use of stealth.&lt;/p&gt;
&lt;p&gt;So far, all of the work has been on the shooting part. I have the basics (movement and collision), some very fun particle effects (flying shell casings, dropped clips, and bullet holes and impact effects), and a simplistic climbing system that allows hanging from and climbing onto map elements (just a few big boxes so far). I will post screenshots tomorrow, by which time I hope to have the split animation system worked out so the player character will stop looking like some kind of crazy contortionist.&lt;/p&gt;</description><pubDate>Tue, 22 Mar 2011 15:06:53 -0500</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Soul Hunter</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=20</guid><link>https://brianmacintosh.com/blog/comments.php?post=20</link><description>&lt;p&gt;School is busy filling my head with binary trees, hash maps, and recurrence relations at the moment, but when spring break arrives I intend to put some more work into Nebula and my as of yet unnamed tech demo.  In the meantime, I thought I&#039;d plug a game that has been in progress in DarkBASIC Classic for an impressive amount time: &lt;a href=&quot;http://soulhunter.bytegrove.com&quot;&gt;SoulHunter&lt;/a&gt; by zzz (Jarl Larsson), a dark Zelda-esque RPG. Jarl started the game six years ago, and it is just now reaching its Alpha stage, so go check it out!&lt;/p&gt;</description><pubDate>Mon, 28 Feb 2011 14:20:23 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Those Dam Beavers! Update</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=18</guid><link>https://brianmacintosh.com/blog/comments.php?post=18</link><description>&lt;p&gt;An after-competition improved version of Those Dam Beavers is &lt;a href=&quot;http://www.clubs.uci.edu/vgdc/bbs/viewtopic.php?p=6310#p6310&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Sat, 29 Jan 2011 18:20:21 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>UCI VGDC Winter Game Jam Over!</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=17</guid><link>https://brianmacintosh.com/blog/comments.php?post=17</link><description>&lt;p&gt;The UCI Video Game Development Club&#039;s Winter Game Jam 2011 ended yesterday. This annual competition within the club requires each team to make a game in one week according to a theme. This year the theme was &quot;pressure&quot;. I was a programmer on one of the four participating teams of about 10 people each.  It was quite cool to see the game come together over the week as the artists submitted the various assets and the code was assembled.  The brainstorming session was also a fun experience involving many great ideas, jumping from genre to genre but usually including beavers with jet packs and bubblegum.&lt;/p&gt;
&lt;p&gt;You can get all four games &lt;a href=&quot;http://www.clubs.uci.edu/vgdc/bbs/viewtopic.php?f=50&amp;amp;t=734&quot;&gt;here&lt;/a&gt; - I worked on &quot;Those Dam Beavers!&quot;.&lt;/p&gt;
&lt;p&gt;P.S. We used FlatRedBall and its editor Glue to make our game - sadly I don&#039;t recommend anyone else repeat the experience, especially if you&#039;re trying to use version control. I do love C# and XNA though.&lt;/p&gt;</description><pubDate>Wed, 19 Jan 2011 03:11:44 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Subscribe!</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=16</guid><link>https://brianmacintosh.com/blog/comments.php?post=16</link><description>&lt;p&gt;Just finished up a subscription system for this blog and for the posting of new projects - get an e-mail whenever I make a new post or, more importantly, upload a new project! Click the green icon above!&lt;/p&gt;
&lt;p&gt;There is also the RSS feed to subscribe to.&lt;/p&gt;</description><pubDate>Sat, 15 Jan 2011 13:07:16 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Port Apollo Completed!</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=10</guid><link>https://brianmacintosh.com/blog/comments.php?post=10</link><description>&lt;p&gt;After a few bug fixes, Port Apollo is done!  I&#039;m looking forward to moving on to a new project. See the the Port Apollo project page to download.&lt;/p&gt;</description><pubDate>Wed, 29 Dec 2010 11:51:47 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Port Apollo Preliminary Release</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=9</guid><link>https://brianmacintosh.com/blog/comments.php?post=9</link><description>&lt;p&gt;I&#039;ve just put up a download for &lt;a href=&quot;https://www.brianmacintosh.com/projects/project.php?proj=4&quot;&gt;Port Apollo&lt;/a&gt;. I&#039;m going to be taking bug reports and maybe some feature requests on this version before I call the project DONE!&lt;/p&gt;</description><pubDate>Mon, 20 Dec 2010 22:19:29 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Port Apollo - Video Posted</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=7</guid><link>https://brianmacintosh.com/blog/comments.php?post=7</link><description>&lt;p&gt;A game of medium proportions I started in August is very near completion, so I&#039;ve put it up here. It&#039;s a bunch of 3D, physics-based fun, and there are explosions! There&#039;s a video on the &lt;a href=&quot;https://www.brianmacintosh.com/projects/project.php?proj=4&quot;&gt;project page&lt;/a&gt;.&lt;/p&gt;</description><pubDate>Mon, 13 Dec 2010 18:18:00 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Online High Scores Set Up</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=5</guid><link>https://brianmacintosh.com/blog/comments.php?post=5</link><description>&lt;p&gt;Today I thought I&#039;d try to use my nice webspace here to host an online scoreboard system for some of my games. I tested it out with &lt;a href=&quot;https://www.brianmacintosh.com/projects/project.php?proj=3&quot;&gt;Unterseeboot!&lt;/a&gt; and it seems to be working great. Do try it out and fill up the scoreboard :).&lt;/p&gt;</description><pubDate>Sun, 12 Dec 2010 14:06:00 -0600</pubDate>
</item>
<item>
<author>webmaster@brianmacintosh.com (Brian MacIntosh)</author><title>Welcome to brianmacintosh.com</title><guid isPermaLink="true">https://brianmacintosh.com/blog/comments.php?post=1</guid><link>https://brianmacintosh.com/blog/comments.php?post=1</link><description>&lt;p&gt;The site still needs a lot of work, obviously. Some of the most immediate tasks:&lt;/p&gt;
&lt;p&gt;- Put a PHP blog here instead of all this text (though if you&#039;re reading this, that&#039;s done!)&lt;/p&gt;
&lt;p&gt;- Prepare more of my games and programs for distribution and upload them for your downloading pleasure&lt;/p&gt;</description><pubDate>Sun, 21 Nov 2010 09:20:00 -0600</pubDate>
</item>
</channel>
</rss>
