tag:blogger.com,1999:blog-16801454192047523892024-02-19T04:21:02.806-08:00Bitwise and Byte-WiseGame development blog for an aspiring game programmer.Unknownnoreply@blogger.comBlogger25125tag:blogger.com,1999:blog-1680145419204752389.post-91100810069598256572016-03-02T18:20:00.002-08:002016-03-02T18:20:56.836-08:00Triangulating Concave and Convex Polygons — Ear Clipping<h3>
The Problem</h3>
OpenGL and other low-level rendering APIs are limited to rendering convex polygons. This causes a complications to arise when trying to render concave primitives. In my case, I wanted to be able to render arbitrary 2D "ground," and not succumb to manually breaking apart the polygon into OpenGL-compatible primitives. Thus the search for a triangulation algorithm arose. All I could find were algorithm names without accompanying implementations or explanations, and long mathematical abstracts on computational geometry. Any implementations I <i>did</i> find seemed to be extremely over-engineered and over-complicated for easy comprehension and adaptation. I finally settled on writing my own implementation of the ear-clipping algorithm to facilitate triangulation.<br />
<br />
<h3>
What We Will Accomplish</h3>
<div>
<br /></div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-right: 1em; text-align: left;"><tbody>
<tr>
<td style="padding-right: 10px; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRTXz4vpDP-KpMzkVRzKTCjzLWXhDHV7yb6VOoJBMQx1dNUF6IhqSBoK1V944GaQ460y6ZZ3clqxF37I04-m5GKGgO6Bn6iJAPd-2EUpfIp-sWyO12nCD3GA-Z_jI8qREZNkugG_dX2dY/s1600/before.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="245" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRTXz4vpDP-KpMzkVRzKTCjzLWXhDHV7yb6VOoJBMQx1dNUF6IhqSBoK1V944GaQ460y6ZZ3clqxF37I04-m5GKGgO6Bn6iJAPd-2EUpfIp-sWyO12nCD3GA-Z_jI8qREZNkugG_dX2dY/s320/before.png" width="320" /></a></td>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFbvOyqld7DgIyRxkAmNorxel32Kqk0Ol1ZpKjMN3ZELRIybXxyAyif4w1Hb-9WseykwT6EJWIDFJfKYNiPXRJt_uSzp7dRKgkE0mkPMBOju1T4IYcve87nOIVQpLfEmkq0NzTkZxCQCM/s1600/after.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="245" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFbvOyqld7DgIyRxkAmNorxel32Kqk0Ol1ZpKjMN3ZELRIybXxyAyif4w1Hb-9WseykwT6EJWIDFJfKYNiPXRJt_uSzp7dRKgkE0mkPMBOju1T4IYcve87nOIVQpLfEmkq0NzTkZxCQCM/s320/after.png" width="320" /></a></td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;">139-vertex polygon</td>
<td class="tr-caption" style="text-align: center;">Triangulated</td>
</tr>
</tbody></table>
<br />
<br />
<a name='more'></a><br />
<h3>
What is "Ear Clipping"?</h3>
<a href="http://en.wikipedia.org/wiki/Polygon_triangulation">Ear clipping</a> is a triangulation algorithm most easily understood recursively. An "ear" is described as a vertex that forms a triangle with its 2 adjacent vertices that contains no other vertices of the polygon within it. These ears are found and removed from a polygon recursively. I found a high-level implementation of this algorithm by David Eberly in his paper on ear clipping <a href="http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf" target="_blank">here</a>. There are only a few steps:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> 1. Iterate through vertices</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> a. If the vertex is concave, skip</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> b. If the triangle formed by the vertex has other vertices in it, skip<br /> b. Otherwise, ear found</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 2. "Cut off" the ear from the polygon and store it<br /> 3. Go to 1</span><br />
<br />
<span style="font-family: inherit;">If you'd like to see a functioning version of what we're going to be doing, and you have Python/Pygame installed, you can run <a href="https://gist.github.com/Shaptic/6297978" target="_blank">this script</a> to see the algorithm in action. Click the left mouse button to create vertices, right click to finalize a shape, and hit "T" to triangulate the polygon. </span><br />
<br />
<h3>
Algorithmic Complexity</h3>
As described by Eberly, a straightforward implementation of the algorithm is theoretically <span style="font-family: "Courier New",Courier,monospace;">O(n<sup>3</sup>)</span>, but in practice the average case is <span style="font-family: "Courier New",Courier,monospace;">Θ(n<sup>2</sup>)</span>. It is possible to optimize the algorithm to be <span style="font-family: "Courier New",Courier,monospace;">O(n<sup>2</sup>)</span> in the worst case, but is somewhat more complicated and less intuitive than this tutorial is intended to be. We will be implementing the <span style="font-family: Courier New, Courier, monospace;">O(n<sup>3</sup>)</span> implementation for clarity's sake. We will include several optimizations to reduce iterations. Since we stop looking as soon as we find an ear, it's hardly <i>ever</i> the case where this takes more than a few iterations.<br />
In testing, a shape with 10 vertices took 93 iterations to triangulate, 30 took 770, and an incredibly complex polygon with 80 vertices took ~6100 iterations. Thus we see that although the recursive algorithm we employ is <span style="font-family: "Courier New",Courier,monospace;">O(n<sup>3</sup>)</span> in theory, the average case in practice is <span style="font-family: "Courier New",Courier,monospace;">Θ(n<sup>2</sup>)</span>. In addition, purely convex shapes find an ear on the first iteration <i>every time</i>, which <i>guarantees</i> <span style="font-family: "Courier New",Courier,monospace;">O(n<sup>2</sup>)</span> complexity.<br />
<br />
<h3>
Finding Ears</h3>
Ears have several limitations that allow for us to process and find them faster.<br />
<ul>
<li>Ears cannot be reflex vertices (θ > 180°).</li>
<li>The triangle formed by the ear cannot contain any other vertices in the polygon.</li>
<li>The triangle formed by the ear must have the same orientation as the polygon.</li>
</ul>
Furthermore, only reflex vertices have the possibility of being in the triangle formed by the ear, reducing the checks we need to make.<br />
<br />
There are multiple ways to find ears, some of which are more computationally expensive than others.<br />
The first way is to determine the angle inside of the polygon that the vertex forms with its two adjacent vertices. This is not easily done, because simply finding the angle between two vectors will always return an angle <= 180° due to the way arc-tangent works.<br />
Let's call the vector formed by the vertex <i>n </i>and <i>n+1</i> A, and the vector formed by the vertex <i>n </i>and <i>n-1</i> B. If you compare the angle of the normal vector of A to that of B, they will be <= 90° if the angle is convex, and the angle is concave (and thus reflex) if the angle is > 90°. The diagram below outlines why this process works.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXiGsqSAGm6daLGdDIx1gK9Wi49xwbBCy3znEcG9Yec5XLiYaco9xJs7X7YgLab4fnmpiCVSNuuURuZNhB60Pa-NR5lMOrT4Gf7f_WY6Dw-dGsaGMLLOUB66bsn26c7W2PKJp6BADe_io/s1600/diagram.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="172" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXiGsqSAGm6daLGdDIx1gK9Wi49xwbBCy3znEcG9Yec5XLiYaco9xJs7X7YgLab4fnmpiCVSNuuURuZNhB60Pa-NR5lMOrT4Gf7f_WY6Dw-dGsaGMLLOUB66bsn26c7W2PKJp6BADe_io/s320/diagram.png" width="320" /></a></div>
<br />
Pseudo-code for the reflexive test could look something like this:<br />
<br />
<pre> // Assume we are at the n-th index.
POINT curr = points[n];
POINT next = points[n+1];
POINT prev = points[n-1];
VECTOR One(prev.x - curr.x, prev.y - curr.y);
VECTOR Two(next.x - curr.x, next.y - curr.y);
VECTOR Nml(One.y, -One.x);
float magnitude = Nml.Magnitude() * Two.Magnitude();
float angl = acos(Nml.Dot(Two) / magnitude);
angl *= 180.0 / 3.14159265359; // Convert to degrees.
// If angl <= 90.0, the n-th vertex is not a reflex vertex.
</pre>
<br />
A limitation of this method is that it only works as-is in one orientation; it assumes the polygon is formed in a clockwise fashion. A much simpler and faster way of determining whether an ear vertex is reflex is by checking the orientation of its respective triangle, and comparing it to the orientation of the polygon.<br />
<br />
To get an accurate polygon orientation, we find the topleft-most vertex in the polygon, and calculate the orientation of its respective triangle. This requires a single pass through the whole polygon prior to clipping. The algorithm is fairly straightforward, calculating the cross-product of two sides of the triangle. Pseudo-code looks something like this:<br />
<br />
<pre> // Input
VECTOR a, b, c; // the parts of our triangle.
// if (b.x - a.x) * (c.y - b.y) - (c.x - b.x) * (b.y - a.y) > 0
// we are counter-clockwise
</pre>
<br />
Before clipping, we run through the polygon like so:<br />
<br />
<pre> // Input
POLYGON p;
int vcount;
// We assume len(shape) > 0
int index = 0;
VERTEX leftmost = p[0];
for i = 0 to vcount - 1
if p[i].x < leftmost.x or (p[i].x == leftmost.x and p[i].y < leftmost.y):
leftmost = p[i];
index = i
// Make a triangle from the vertex.
POLYGON tri = {
p[index - 1 if index - 1 > 0 else vcount - 1],
p[index],
p[index + 1 if index + 1 < vcount else 0]
};
bool orient = is_ccw(tri[0], tri[1], tri[2]);
</pre>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Finally, we need a function to test if a given vertex lies within a triangle. This is done by calculating <a href="https://en.wikipedia.org/wiki/Barycentric_coordinate_system" target="_blank">barycentric coordinates</a>. A sample algorithm was <a href="http://stackoverflow.com/questions/13300904/determine-whether-point-lies-inside-triangle" target="_blank">given on StackOverflow</a>, for which a </span>pseudo-code<span style="font-family: inherit;"> adaptation is given below.</span><br />
<pre> // Input
POINT p;
TRIANGLE t; // A set of three POINTs.
float denom = (t[1].y - t[2].y) * (t[0].x - t[2].x) +
(t[2].x - t[1].x) * (t[0].y - t[2].y);
// Avoid division by zero.
if denom == 0: return true;
denom = 1.0 / denom;
float alpha = denom * ((tri[1].y - tri[2].y) * (p.x - tri[2].x) +
(tri[2].x - tri[1].x) * (p.y - tri[2].y));
float beta = denom * ((tri[2].y - tri[0].y) * (p.x - tri[2].x) +
(tri[0].x - tri[2].x) * (p.y - tri[2].y));
float gamma = 1.0 - alpha - beta;
// if alpha < 0, the point is NOT in the triangle.
// if beta < 0, the point is NOT in the triangle.
// if gamma < 0, the point is NOT in the triangle.
// else, the point IS in the triangle (go figure).
</pre>
<br />
<span style="font-family: inherit;">Armed with our slew of helper functions, we can begin the actual ear clipping algorithm. A </span>pseudo-code<span style="font-family: inherit;"> implementation is provided below, and </span><a href="https://gist.github.com/Shaptic/6526805" style="font-family: inherit;" target="_blank">here is a link</a><span style="font-family: inherit;"> to a full C++ implementation. You can also view a Python implementation in the sample script I provided above.</span><br />
<span style="font-family: inherit;"><br /></span>
<script src="https://gist.github.com/Shaptic/894b764c7022177983a4.js"></script>
<br />
<div>
And there you have it. An algorithm for creating completely triangulated, OpenGL-compatible polygons that you can then use to draw arbitrary landscapes, create collision maps, or anything else you may need concave polygons for.<br />
<br />
<h3>
Sources / Further Reading</h3>
</div>
<a href="http://www.diva-portal.org/smash/get/diva2:330344/FULLTEXT02" target="_blank">A comparison of Ear Clipping and a New Triangulation Algorithm - Ran Liu</a><br />
<a href="http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf" target="_blank">Triangulation By Ear Clipping - David Eberly</a><br />
<a href="http://www.gamedev.net/topic/346146-triangle-orientation/" target="_blank">Triangle orientation - GameDev.net</a><br />
<a href="https://gist.github.com/urraka/6626810" target="_blank">A True O(n<sup>2</sup>) Triangulation Algorithm in C++ - urraka</a><br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-32809494915269910762013-06-21T15:16:00.003-07:002013-09-07T14:37:29.728-07:00Setting Settings of Arbitrary Types in C++It's been a while, but things are still slowly moving along. Working a 40-hour week doing web development leaves me with little time or energy to make game development progress!<br />
<br />
I've begun a new iteration of my rendering engine, <i>IronClad</i>, now dubbed <i>Zenderer</i>. Over the past few weeks I've slowly been adding various modules and utilities to it, such as audio, file parsing, and asset management. Nothing is being rendered on the screen just yet, but that's next!<br />
<br />
This post is primarily dedicated to creating a settings module that will accept arbitrary types, such as <span style="font-family: Courier New, Courier, monospace;">int</span>s, <span style="font-family: Courier New, Courier, monospace;">float</span>s, <span style="font-family: Courier New, Courier, monospace;">std::string</span>s, and even <span style="font-family: Courier New, Courier, monospace;">bool</span>s. The final result will allow something like this:
<br />
<br />
<pre>// Optional file to parse immediately
CSettings Settings("SettingsFile.dat");
Settings.Init();
// Set settings
Settings["WINDOW_WIDTH"] = 800;
Settings["WINDOW_HEIGHT"] = 600;
Settings["WINDOW_NAME"] = "Zenderer Window";
Settings["WINDOW_FS"] = false;
Settings["SCROLL_SPEED"] = 5.2;
Settings["FRAME_RATE"] = 60;
// Retrieve settings
if((size_t)Settings["FRAME_RATE"] < 20)
{</pre>
<pre> std::cerr << "[FATAL] Frame rate is too low for adequate gameplay.\n";</pre>
<pre> exit(1);
}
// Change settings, regardless of type
Settings["WINDOW_FS"] = true;
Settings["WINDOW_NAME"] = 42.335f;
</pre>
<br />
We will do this by creating an extremely dynamic <span style="font-family: Courier New, Courier, monospace;">COption</span> class that accepts all different types for values and turns them into strings behind the scenes.
<br />
<br />
<a name='more'></a><br />
<br />
<h4>
The <span style="font-family: Courier New, Courier, monospace;">COption</span> Class</h4>
We need implicit conversion, assignment, and comparison operators for many many different types. Thankfully, with implicit template parameter deduction in C++, we don't need to hard-code a lot of these, as long as they are supported by <span style="font-family: Courier New, Courier, monospace;">std::to_string</span> (new in C++11). And in the opposite direction, we can easily compare everything with a floating-point value (except actual floating point values due to comparison inaccuracies, we will use <span style="font-family: Courier New, Courier, monospace;">math::compf</span> for that).
<script src="https://gist.github.com/Ruskiy69/5834511.js"></script>
As you can see, this class is basically nothing but a wrapper allowing it to be assigned to, compared with, and assigned from many different types. If it's not obvious, the implementation can be viewed <a href="https://gist.github.com/Ruskiy69/5834567">here</a>.
<br />
<br />
<h4>
The <span style="font-family: Courier New, Courier, monospace;">CSettings</span> Class</h4>
<div>
Now we are going to create an array-like wrapper class that will allow us to set, retrieve, and modify different settings values using identical syntax.</div>
<div>
To achieve this, we will return an instance of <span style="font-family: Courier New, Courier, monospace;">COption&</span> when using <span style="font-family: Courier New, Courier, monospace;">operator[]</span> on a <span style="font-family: Courier New, Courier, monospace;">string_t</span> index. Internally, we will add a new <span style="font-family: Courier New, Courier, monospace;">COption</span> to the internal list if it does not exist, and then return a direct reference to it for modification regardless. Since we defined the type above to be compatible with all primitive types, this will easily allow for operations like this:</div>
<br />
<div>
<pre>// Set.
Settings["HEALTH"] = 100;
// Get.
std::cout << Settings["HEALTH"] << std::endl;
// Compare
int h = Settings["HEALTH"];
if(h < 50) std::cout << "Dying.\n";</pre>
<pre>
</pre>
<pre>// In-line compare.</pre>
<pre>if(static_cast<int>(Settings["HEALTH"]) < 50)</pre>
<pre><pre> std::cout << "Dying.\n";</pre>
// Change type.
Settings["HEALTH"] = "Dead";
</pre>
</div>
<br />
<div>
As you can see, the only thing that is slightly tricky is comparison. To remedy this, you would need to overload <span style="font-family: Courier New, Courier, monospace;">operator<</span>, <span style="font-family: Courier New, Courier, monospace;">operator<=</span>, <span style="font-family: Courier New, Courier, monospace;">operator></span>, <span style="font-family: Courier New, Courier, monospace;">operator>=</span>, and <span style="font-family: Courier New, Courier, monospace;">operator!=</span><span style="font-family: inherit;"> for every single type you wanted to do comparisons with. It's a bit simpler to just assign it to the variable type you want to work with and do the comparison that way, or cast to a type with an operator.</span><br />
Below is the implementation of <span style="font-family: Courier New, Courier, monospace;">operator[]</span>. The <span style="font-family: Courier New, Courier, monospace;">CSettings</span> class internally defines an option dictionary associating a string value (or a hash in release builds for speed) with a <span style="font-family: Courier New, Courier, monospace;">COption</span> instance.<br />
<br />
<script src="https://gist.github.com/Ruskiy69/5834800.js"></script><br />
<div>
So there you have it. A high-level abstraction layer for an array-like settings module that allows for assignment and modification of a variety of types through unified syntax.</div>
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-64933750209490170522013-03-27T15:49:00.001-07:002013-07-07T18:46:43.706-07:00Yet Another Quad Tree TutorialThere was nothing to show for Screenshot Saturday this week, but that doesn't mean there hasn't been any progress! I spent the weekend writing a quad-tree implementation and integrating it into the existing engine. It was not a very hard process, and there are already dozens of tutorials available online for this, but this guide may still come in handy for someone.<br />
<br />
<h3>
How Do Quad Trees Work</h3>
You may be familiar with a binary tree. Essentially there's a "root" structure (known as a "node") that branches out into two nodes (binary = two). Then, each of these nodes splits into two of their own. This continues as long as necessary. The nodes that<i> aren't</i> split are called "leaf" nodes.<br />
Quad trees work exactly the same way, except the nodes are split into four parts rather than two. This is useful for video games because the screen is a rectangle, and can thus easily be split into smaller subsequent rectangles. Here's a screenshot of a stress-test quad tree in progress:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsZv3ss4fnI_o6F3tfQKEc1Q61__mpMGNUfbo-_qfPTcIELzkcDiml8wr_7p7qstVndlt06GuyRgMOzQ3AOOI8rMysMm0djQ7_ZSnVIPXg7erIXrmg0WqS61VOwrnA5THOdO3lJ5UhHdUb/s1600/Untitled.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsZv3ss4fnI_o6F3tfQKEc1Q61__mpMGNUfbo-_qfPTcIELzkcDiml8wr_7p7qstVndlt06GuyRgMOzQ3AOOI8rMysMm0djQ7_ZSnVIPXg7erIXrmg0WqS61VOwrnA5THOdO3lJ5UhHdUb/s320/Untitled.png" width="320" /></a></div>
<br />
The small, 8x8 quads represent particles with physics. Each quad you see can contain a maximum of 32 (an arbitrary value) particles before it automatically splits into 4 nodes. The tree cannot go more than 6 levels deep, though, because that would eventually cause a stack overflow due to the recursion inherent to quad trees.<br />
<br />
You can see this live, in-action by downloading a <a href="https://www.dropbox.com/s/6kiliu48ilmh4go/QTree_Test.zip" target="_blank">demo here</a> (pardon the dependencies, I used my old wrapper classes to write this). Hold keys to generate particles, or use the mouse to set them in certain locations. Right-click the mouse to test for a collision with the large blue quad. The result will show up in the console window as a 1 (true) or 0 (false). You can notice that the operation is performed incredibly quickly, even with an insane amount of particles on the screen. That is the power of a quad tree.<br />
<br />
Note: If you get DLL errors, you may need to install the VC++ redistributable from <a href="http://www.microsoft.com/en-us/download/details.aspx?id=5555" target="_blank">here</a>.<br />
<br />
<a name='more'></a><br />
<br />
<h3>
Nodes</h3>
At the core of a quad tree is each individual quad itself, called a node. This node should contain information about the collide-able objects it holds, its dimensions, its depth, its child nodes (if any), its parent node (if any). Here is a sample bare-bones quad tree node structure:<br />
<br />
<script src="https://gist.github.com/Ruskiy69/5257421.js"></script>
<br />
This is the structure we'll be using in this tutorial. For a more full-featured node class, you can see the actual implementation I use in <i>IronClad</i> <a href="https://github.com/Ruskiy69/IronClad/blob/master/Source/include/IronClad/Entity/QuadTree.hpp" target="_blank">here</a>.<br />
<br />
<h3>
Recursion</h3>
Quad trees rely heavily on recursion. If you want to insert an object into the tree, you have to check the root node for children, then check which child the object belongs in, and then repeat that for every child in the child until you reach the leaf node, which has no children. This is easily modeled with recursion. One of the issues that arises with this is a stack overflow, which happens when you are too nested in the tree. This is why a depth limit is necessary; I use a depth limit of 6.<br />
<br />
<h3>
The <span style="font-family: "Courier New",Courier,monospace;">CQuadTree</span> Class</h3>
This class will essentially act as a wrapper around a single node, the root node. It will also provide the recursive functions for insertion, deletion, and collision detection. Here is the class definition we will be using in this tutorial. For the sake of brevity and not splitting this into separate files per method, here is the entire class with explanations as comments within it. The implementation, though, will be split up into parts so I can explain each part in full.<br />
<br />
<script src="https://gist.github.com/Ruskiy69/5257648.js"></script>
<br />
<h3>
</h3>
<h3>
Step 1: Splitting</h3>
The primary appeal of a quad tree is the ability to split into sub-nodes as needed, so this needs to be done first, for insertion to work properly. The process looks complicated, but is actually fairly simple. All nodes have a <span style="font-family: "Courier New",Courier,monospace;">QTNode**</span> member, which is a pointer to <span style="font-family: "Courier New",Courier,monospace;">QTNode*</span>. This is used to create an array of 4 <span style="font-family: "Courier New",Courier,monospace;">QTNode*</span>'s, each of which is then used to create a new <span style="font-family: "Courier New",Courier,monospace;">QTNode</span>. It's much cleaner to use an <span style="font-family: "Courier New",Courier,monospace;">std::vector<QTNode*></span>, but for simplicity sake we'll do this. <br />
So, after we've created the nodes, we set some default parameters (depth, children, etc) then give each one its respective dimensions, based on the parent node. The position is offset properly, width and height are divided in half, then made 1 pixel larger than usual to account for integer division errors that occur as depth increases. Each child node then gets the objects from the parent node that belong to it.<br />
Comments in the code should further explain what's going on:<br />
<br />
<script src="https://gist.github.com/Ruskiy69/5257902.js"></script>
<br />
<h3>
Step 2: Insertion</h3>
First and fore-most is the necessity of being able to insert objects into the quad tree.To do this, we first check to see if a node has any children. If it does, it checks to see if the object "fits" into any of the children, via collision detection on the node. On the child that it does fit into, the method calls itself, but using the child as the starting node (recursion!). If the node has <i>no </i>children, the object is added to the nodes list of objects, but <i>only</i> if there is space. If the node is full, it calls <span style="font-family: "Courier New",Courier,monospace;">Split()<span style="font-family: Arial,Helvetica,sans-serif;"> on the node </span></span><span style="font-family: inherit;">and then </span>calls <span style="font-family: "Courier New",Courier,monospace;">RInsert<span style="font-family: inherit;"><span style="font-family: inherit;"> </span></span></span>again, using itself as the starting node since it now has children.<br />
<br />
That's the English explanation, and you're probably thinking "what." But let's take a look at the code.<br />
<br />
<script src="https://gist.github.com/Ruskiy69/5258027.js"></script>
<br />
<h3>
Step 3: Removal</h3>
Often times objects get destroyed, whether that be a particle whose time has expired, or an enemy tank that has blow up. In that case, we would want to remove this object from the quad tree, so collisions with it no longer occur (though not necessarily for a blown up tank, if it doesn't disappear, but that's another matter entirely). The algorithm basically follows the same pattern as insertion.<br />
<br />
<script src="https://gist.github.com/Ruskiy69/5258087.js"></script><br />
<h3>
Step 4: Collision Detection</h3>
Now we can finally implement the actual thing quad trees are used for, collision! Once again, this is done in a recursive fashion similar to that of <span style="font-family: "Courier New",Courier,monospace;">RRemove()</span> and <span style="font-family: "Courier New",Courier,monospace;">RInsert()</span>.<br />
<br />
<script src="https://gist.github.com/Ruskiy69/5258722.js"></script>
<br />
<h3>
Step 5: Updating the Tree</h3>
Of course, objects aren't static. Most will move around, be it an enemy tracking the player, bullets flying, or simply the camera panning through the scene. Thus, it's necessary to update the quad tree as objects move. The simplest, and least efficient way, would be to just remove all of the objects, and then insert them again. A <i>much</i> more effective method would be to have the objects themselves keep track of whether or not they have moved since the last frame. In <i>IronClad</i>, this is done with the entity marking a flag (<span style="font-family: "Courier New",Courier,monospace;">m_update</span>) if <span style="font-family: "Courier New",Courier,monospace;">CRigidBody::Move()</span> is called with values that are different than the current position, or the <span style="font-family: "Courier New",Courier,monospace;">m_Force</span> vector before the <span style="font-family: "Courier New",Courier,monospace;">CRigidBody::Update()</span> call is non-zero. Then, in <span style="font-family: "Courier New",Courier,monospace;">CQuadTree::Update()</span>, the tree will <span style="font-family: "Courier New",Courier,monospace;">RInsert()</span> updated objects again by moving up the tree from the old node (<span style="font-family: "Courier New",Courier,monospace;">CRigidBody::mp_CurrentNode</span>).<br />
<br />
A further optimization would be not only to update objects that have moved, but to check the likelier nodes first, rather than starting from the root again. This is done by calling <span style="font-family: Courier New, Courier, monospace;">RInsert()</span> on the object with the starting node being the parent of the current node. For example, if a particle moves 5px per frame, and it's exited the current node, the likeliest place it would now be would be another one of the child nodes of the parent.<br />
<br />
This is probably the slowest operation in the quad tree, due to the fact that as more objects move (and the farther they move from their original place), the more <span style="font-family: Courier New, Courier, monospace;">RInsert()</span> calls have to be performed. I haven't tested this extensively, so I am not sure if a stack overflow could occur due to excessive recursion. It's likely that it won't, since each object needs 6 calls (<span style="font-family: "Courier New",Courier,monospace;">QT_MAX_DEPTH</span>) at the most to find a proper node, and will usually need just 1 call. <br />
<br />
Here is the code, with further explanation:<br />
<br />
<script src="https://gist.github.com/Ruskiy69/5258800.js"></script>
<br />
<br />
<h3>
Using the Quad Tree</h3>
Now that we've implemented the quad tree and all of it's functions, it's very easy and simple to use efficiently. For example, if you are loading a level, it might look something like this:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">CQuadTree QT; </span><br />
<span style="font-family: "Courier New",Courier,monospace;">CLevel Level1("Level1.dat");</span><br />
<span style="font-family: "Courier New",Courier,monospace;">const std::vector<CEntity*>& objs = Level1.GetPhysicalObjects(); </span><br />
<span style="font-family: "Courier New",Courier,monospace;">for(size_t i = 0; i < objs.size(); ++i)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> QT.Insert(objs[i]);</span><br />
<br />
Later, if you wanted to, for example, not allow the player to move if he's colliding with any objects in the level, you could just do<br />
<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">CEntity* pResult = QT.Collides(Player);</span><br />
<span style="font-family: "Courier New",Courier,monospace;">if(pResult == nullptr) Player.Move(requested_position);</span><br />
<br />
Simple as that! <br />
You don't necessarily need a single quad tree for the entire game world, either. You could have a separate one containing level objects, another containing enemies, another for particles, etc. That way it'd be even more efficient in terms of what you are trying to test collision for.<br />
<br />
That's all for this tutorial, feel free to include comments and questions below! If you'd like to check out the official implementation of a quad tree in <i>IronClad</i> you can check out the full header <a href="https://github.com/Ruskiy69/IronClad/blob/master/Source/include/IronClad/Entity/QuadTree.hpp" target="_blank">here</a> and the source code <a href="https://github.com/Ruskiy69/IronClad/blob/master/Source/src/Entity/QuadTree.cpp" target="_blank">here</a>. <br />
<br />
<h3>
</h3>
Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-1680145419204752389.post-89468973540976012022013-03-15T16:48:00.000-07:002013-03-16T13:06:41.781-07:00Blurring The LineThis week, I've got some minor updates done. With midterms and projects across the board, it's been a pretty insane week, and not much progress has been made on the game visually. Behind the scenes, I've got some code-restructuring, and the beginnings of an enemy class. On the visual side of things, I've got a new game-play mechanic to show off!<br />
<br />
While tweaking the time-trail algorithm, I realized that a particularly clever player could stand in a very bright area for an extended period of time to cast himself further into the future, then just skip throughout the level unnoticed by enemies while his past self slowly trudged through the layers of time. As I wondered about how to fix this, I realized that I had a couple of Gaussian blur shaders already implemented for when I was testing post-processing in <a href="https://github.com/Ruskiy69/IronClad" target="_blank">my rendering engine</a>. So I decided to test what it would be like if the player was faced with an increasing blur of the world around him as he traversed through time.<br />
<br />
Here are a couple of screenshots showing the differences:<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTr6acCXTcDNH0TRuhAHjZc7GmrqOE9-9BFn-YO1TIV6wHfIqsOZzKVZLVWkTtq640welN8BYL5b-2WXJrtfDVenxc9WUvzbx4zXxwVF1iIx8mz7Mn0-KVqfzo9wRyGCS_JxfRCdO3NcE0/s1600/PreBlur.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTr6acCXTcDNH0TRuhAHjZc7GmrqOE9-9BFn-YO1TIV6wHfIqsOZzKVZLVWkTtq640welN8BYL5b-2WXJrtfDVenxc9WUvzbx4zXxwVF1iIx8mz7Mn0-KVqfzo9wRyGCS_JxfRCdO3NcE0/s320/PreBlur.png" width="320" /></a></td>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs5vfDav1E6hbL7jXPzpkIXrk_SgYEyP2vVaMnpazpvXuKR141tT3EwxXUdRfAEnQBdUUGU0wqfMiBo9IPOFGv7l5idxyGt9FgjCOetpwTnq3kTUbPtBw0IgvsSTfv8BqyRvFyxQP_Zx10/s1600/PostBlur.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs5vfDav1E6hbL7jXPzpkIXrk_SgYEyP2vVaMnpazpvXuKR141tT3EwxXUdRfAEnQBdUUGU0wqfMiBo9IPOFGv7l5idxyGt9FgjCOetpwTnq3kTUbPtBw0IgvsSTfv8BqyRvFyxQP_Zx10/s320/PostBlur.png" width="320" /></a></td></tr>
<tr>
<td class="tr-caption" style="text-align: center;">A small delay, ~1 second</td>
<td class="tr-caption" style="text-align: center;">A much larger one, ~10 seconds</td>
</tr>
</tbody></table>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
The idea is that the player will not be able to accurately see what's going on in the level as the blur increases, and thus will be deterred from traveling a large amount into the future.<br />
<br />
<h3>
Algorithm Details</h3>
<div>
For the time-trail algorithm, I created a method called <span style="font-family: Courier New, Courier, monospace;">CWorld::CalculateLightInfluence()</span><span style="font-family: inherit;">. It, aptly named, calculates the sum of the three most-influential light sources. It used to rely on distance, but that only makes sense if all of the lights have the same attributes, so now the actual influence is calculated and compared for all of the lights. The calculation is as follows:</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">distance * 200.f / (Constant Attenuation + Linear Attenuation * distance + Quadratic Attenuation * distance<sup>2</sup>) * brightness</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">This is almost the same as the algorithm I use in my lighting shader, except it's done on a single light rather than every pixel of the entire screen, heh. I can easily tweak the </span><span style="font-family: Courier New, Courier, monospace;">200.f</span><span style="font-family: inherit;"> constant if I want lights to have more or less of a cumulative influence. So, this value is summed, capped at a range of [0, 5), and returned to the world for further processing.</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">Back in </span><span style="font-family: Courier New, Courier, monospace;">CWorld::Update()</span><span style="font-family: inherit;">, this value is then used to create time-trail instances. After this, the blurring algorithm is performed. It determines the total time between the current time and the time-trail active at the moment. This represents the amount of time ahead the player is. This value is divided by 10000, because the Gaussian Blur shader only works well with <i>really</i> small radius values. It's clamped to [0, 1/300]. The larger the value, the closer it is to the limit, and thus the blur increases!</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">I want to tweak this to be a progressive algorithm, rather than just a linear increase. In the near future, I'll make a spread-sheet and maybe apply a increase based on a stretched out x<sup>2</sup> graph, like maybe x<sup>2</sup>/8</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
Unknownnoreply@blogger.com11tag:blogger.com,1999:blog-1680145419204752389.post-64300165057549827912013-03-09T02:05:00.000-08:002013-03-09T02:25:13.098-08:00More Menu MagicSome small, but beautiful updates this week!<br />
The GUI keeps on improving, with new menus and transitions! I've added an options menu with functioning toggles, a credits menu with full recognition, a transition sound effect, a <i>critical</i> audio bug fix, and some updates to the player-trail algorithm!<br />
<br />
Check out the screenshots below:<br />
<br />
<a name='more'></a><br />
<br />
<table cellpadding="1" cellspacing="1" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZjlhbf7eB6mSSWULf77aIZ7gbuJLZR4MEnThNeYns28skmjtk9b0IBsllRupluTj36p87MPzjbufq-qhIRaUuwRl5l_i17fWr-G13jkFoFlCKW-nJfPP8lFh6KMCM04Jphid7EQ2S3P-J/s1600/menu.gif" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZjlhbf7eB6mSSWULf77aIZ7gbuJLZR4MEnThNeYns28skmjtk9b0IBsllRupluTj36p87MPzjbufq-qhIRaUuwRl5l_i17fWr-G13jkFoFlCKW-nJfPP8lFh6KMCM04Jphid7EQ2S3P-J/s320/menu.gif" width="320" /></a></td>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBZjY-LhO7-CC9ZB48TlqWyjtz2W_uTbjHE_l5E1mKJdiSiVf7XSmQ4mIx6SObzAA1J-KKJU3zfjWeng0Of0A9pg59Ad2SwJRsGet6g11ls5L-kJMmM5FF27hqX3cdPSP7Q_JNoJZway54/s1600/play.gif" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBZjY-LhO7-CC9ZB48TlqWyjtz2W_uTbjHE_l5E1mKJdiSiVf7XSmQ4mIx6SObzAA1J-KKJU3zfjWeng0Of0A9pg59Ad2SwJRsGet6g11ls5L-kJMmM5FF27hqX3cdPSP7Q_JNoJZway54/s320/play.gif" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Menu transitions</td>
<td class="tr-caption" style="text-align: center;">Delay algorithm</td></tr>
</tbody></table>
<br />
<table cellpadding="1" cellspacing="1" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWGdQYdlu2gnxmwUpl_LoSrbugevWOW40wMG2vi-PSQCVOIUkpcdqByTiQmsHQYGWiaWs5VS3t90KHS0q50Yq-YuJaTTBcyqns8rehVf15GqkDN9TShBHH2qLuzbCq2igDUUBVXb5D3vOH/s1600/Logo.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWGdQYdlu2gnxmwUpl_LoSrbugevWOW40wMG2vi-PSQCVOIUkpcdqByTiQmsHQYGWiaWs5VS3t90KHS0q50Yq-YuJaTTBcyqns8rehVf15GqkDN9TShBHH2qLuzbCq2igDUUBVXb5D3vOH/s1600/Logo.png" width="240" /></a></td>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSx8CELTvEfi8aLMemC8oX_wAKbqHW6hHXS_tWKyVgX_uVebVuKRZzJhjkDfjvKPm9hFSjxAxubzeNUPY2Dg_ZBUzmviGhxCioVL06glzt8cSBfSNr7cZzeuTX91BgTSte0q6hOOfg56O2/s1600/Praecursor_3-9-2013.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSx8CELTvEfi8aLMemC8oX_wAKbqHW6hHXS_tWKyVgX_uVebVuKRZzJhjkDfjvKPm9hFSjxAxubzeNUPY2Dg_ZBUzmviGhxCioVL06glzt8cSBfSNr7cZzeuTX91BgTSte0q6hOOfg56O2/s320/Praecursor_3-9-2013.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Logo</td>
<td class="tr-caption" style="font-size: 13px; text-align: center;">Credits menu</td></tr>
</tbody></table>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Track updates on the <a href="https://github.com/Ruskiy69/Praecursor" target="_blank">the project GitHub page</a> or on the newly created <a href="https://twitter.com/PraecursorGame" target="_blank">official Twitter account</a>!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-15302346975979755202013-03-01T14:01:00.006-08:002013-03-31T12:40:37.977-07:00Making a MenuI've been a bit quiet the past few weeks on here, but I've been actively participating in Screenshot Saturday on <a href="http://www.reddit.com/r/gamedev/" target="_blank">/r/gamedev</a>. You can see last weeks <a href="http://www.reddit.com/r/gamedev/comments/192b4x/screenshot_saturday_107_redacted/c8kfj2x" target="_blank">here</a>, and the one prior <a href="http://www.reddit.com/r/gamedev/comments/17qjgc/screenshot_saturday_104_one_flew_over_the_cuckoos/c87xb7s" target="_blank">here</a>.<br />
<br />
This week, I've worked on creating a flexible, slick UI system for making menus. It proved to be pretty complex, and I used a seriously ass-backwards technique to get it accomplished.<br />
You can think of a button as an physical entity, right? You need to be able to check collision, move it around for transitions, and swap textures easily. So I created a <a href="https://github.com/Ruskiy69/IronClad/blob/master/Source/include/GUI/Button.hpp" target="_blank"><span style="font-family: Courier New, Courier, monospace;">CButton</span> class</a> with a <span style="font-family: Courier New, Courier, monospace;">CEntity</span> inside. At first, I just had a button texture rendered to the screen as a mesh, and the text rendered on top without being a part of the scene. This worked okay, but I wouldn't be able to add shader effects to the text portion of the buttons, which would look weird. So I had to have them both be a part of the scene.<br />
<br />
<a name='more'></a><br />
The problem arose when I wanted to assign a texture to the entity. Since the button background is a texture, and the my text-rendering system renders directly to the frame buffer there was no way to easily "blit" them together. I decided to create a frame buffer object for every instance of the button (main, hover, click) and render both parts of the button to it, then assign that texture to the button entity.<br />
As you can see, this is serious overkill. It requires three render passes, two different shaders, and a ton of OpenGL state change. I'm not too worried about this, though, since it will only be called at the beginning of the game, prior to any performance-critical sections. It also works fast on my machine, no frame rate issues whatsoever.<br />
<br />
After making the button class, I made another, higher-level class to wrap everything up for flexible menu creation. Now I can just call something like<br />
<span style="font-family: Courier New, Courier, monospace;">CMenu::AddButton("Button.tga", "Play Praecursor", math::rect_t(0, 0, 256, 64));</span><br />
and the wrapper will automatically search for the hover and click versions of the button texture. I added these buttons to a pre-made background, added a lighting effect for a torch (it always looks good), and called it good!<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJ2XgfGp6mwMJn3F9R1dapoUper0D0czcz4HUtR8xBD-GLh2os9-eiqwx-7-Y_j2kUt_Buy1n4XdZKHKzoncGIrDLZnRTNCclV5YqvgmFuIUyQ_DSnTvMzJu5hCn8IJxyHldphi_R3hdIn/s1600/Praecursor_3-1-2013.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJ2XgfGp6mwMJn3F9R1dapoUper0D0czcz4HUtR8xBD-GLh2os9-eiqwx-7-Y_j2kUt_Buy1n4XdZKHKzoncGIrDLZnRTNCclV5YqvgmFuIUyQ_DSnTvMzJu5hCn8IJxyHldphi_R3hdIn/s320/Praecursor_3-1-2013.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Final result!</div>
<br />
<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-59118287092354934962013-02-10T14:35:00.002-08:002013-02-10T14:38:34.119-08:00Animating 2D Sprites in OpenGLIn working on my latest game, <i>Praecursor</i>, it came time to develop a system for easily animating sprites on the screen. I found a very nice sprite for a hero on <a href="http://www.opengameart.org/" target="_blank">OpenGameArt</a>, and wanted to integrate his various animations into player actions. In the process, I created a <span style="font-family: Courier New, Courier, monospace;">CAnimation</span> class that would extend the <span style="font-family: Courier New, Courier, monospace;">CRigidBody</span> class, making it eligible to act just like a physical entity and be rendered on the screen with relative ease. The entire process was fairly challenging, requiring a custom file format parser and a new fragment shader. The following is a tutorial-like thought process that went into the development of animate-able sprites.<br />
<br />
<h3>
Layout</h3>
<div>
The CAnimation class is supposed to act exactly like a regular physical entity, but should support loading of custom .icanim files and have various functions related to animation. These include toggling animation, setting an automatic animation rate, quick-swapping sprite sheets, and manually switching sprites.</div>
<div>
<br /></div>
<div>
Quick-swapping seems like a pointless functionality of an animation class; after all, why not just create a separate instance and load it with the new sprite sheet? Well, I didn't think about this until I started trying to swap-out animations for running, jumping, and standing with the main player instance. When I would just have a list of animations and do <span style="font-family: Courier New, Courier, monospace;">m_Player = m_allAnimations[JUMP]</span>, the player would lose his physics properties, such as gravity or jump force. I tried a few workarounds, but none of them turned out like expected, so I decided to add a <span style="font-family: Courier New, Courier, monospace;">SwapSpriteSheet()</span> method to the <span style="font-family: Courier New, Courier, monospace;">CAnimation</span> class. This will attach a new texture to the material and give the shader new parameters based on width and heights.</div>
<div>
<br /></div>
<div>
In the future, I think I will change the class to incorporate animation boundaries, so I don't need to load a separate image for each animate-able action. I would be able to do something like <span style="font-family: Courier New, Courier, monospace;">SetAnimationIndex(0, JUMP)</span>, and the animation would only loop through sprites [0:JUMP], then if I wanted to just play the standing animation, I could do <span style="font-family: Courier New, Courier, monospace;">SetAnimationIndex(JUMP + 1, STAND)</span>, assuming the standing animation comes after the jumping one in the sprite sheet. This would likely all but eliminate the need for the swapping method.</div>
<div>
<br />
<a name='more'></a><br /></div>
<div>
Here is a snippet of the <span style="font-family: Courier New, Courier, monospace;">CAnimation</span> class we will be developing in this post:</div>
<div>
<br /></div>
<div>
<script src="https://gist.github.com/Ruskiy69/4751211.js"></script>
</div>
<div>
<br /></div>
<div>
<h3>
.icanim Files and Loading Animations</h3>
</div>
<div>
<i>IronClad</i> uses a custom header attached to a generic Targa (.tga) image file to convey sprite sheet information. The header looks something like this (without brackets and quotes):</div>
<div>
"<span style="font-family: Courier New, Courier, monospace;">[integer image width] [integer image height] [horizontal sprite count] [vertical sprite count][Raw TGA data]</span>"</div>
<div>
<br /></div>
<div>
A future revision may eliminate the total w/h parameters, since those are found when the TGA data is loaded anyway.</div>
<div>
<br /></div>
<div>
The image loading method is as follows:</div>
<div>
<br /></div>
<div>
<script src="https://gist.github.com/Ruskiy69/4751252.js"></script>
</div>
<div>
The methods with loading a mesh and inserting it into a vertex buffer on the GPU are pretty specific to my engine, but I'm sure others reading this post as a guide will be able to adapt this to their own methodologies.<br />
<br />
<h3>
Texture Offsets and the Animation Shader</h3>
</div>
<div>
In the loading method, we specified that the texture coordinates are in the [0, 1] range. This would map the entire sprite sheet texture onto the individual sprite meshes, something clearly undesirable. The reason for the [0, 1] range is so that it is properly interpolated within the fragment shader, whereas the real work of figuring out exactly where in the sheet we will be is done by passing uniforms that specify the current sprite offset and the individual sprite dimensions.</div>
<div>
<br /></div>
<div>
The fragment shader looks like this:</div>
<div>
<br /></div>
<div>
<script src="https://gist.github.com/Ruskiy69/4751277.js"></script>
</div>
<div>
Texture offsets are calculated via special uniform values. The <span style="font-family: Courier New, Courier, monospace;">tc_offset</span> uniform represents individual sprite dimensions expressed as a tex-coord range. For example, a 32x32 sprite would be <span style="font-family: Courier New, Courier, monospace;"><0.03125, 0.03125></span>, calculated as <span style="font-family: Courier New, Courier, monospace;">1 / w</span>, <span style="font-family: Courier New, Courier, monospace;">1 / h</span>. This would then be interpolated from <span style="font-family: Courier New, Courier, monospace;">[0, 0.03125]</span>, properly rendering all of the texels in the desired sprite. The <span style="font-family: Courier New, Courier, monospace;">tc_start</span> uniform represents the starting offset within the sprite sheet. For example, if you wanted the 2nd sprite of the 3rd row of a sprite sheet with 16x16 sprites, you'd pass <span style="font-family: Courier New, Courier, monospace;"><2/16, 3/16></span> to the fragment shader from your program. You can see this being done for the first time in lines 99 and 100 in the <span style="font-family: Courier New, Courier, monospace;">LoadFromFile()</span> method above, and below when I show the <span style="font-family: Courier New, Courier, monospace;">NextSprite()</span> method that animates the sprites.<br />
<br />
<h3>
Animating</h3>
<div>
Each time m_delay is reached, we want to iterate over to the next sprite. This is handled within <span style="font-family: Courier New, Courier, monospace;">Update()</span><span style="font-family: inherit;">, and I'm showing here how the new texture offset is calculated each time. </span></div>
<div>
<br /></div>
<div>
<script src="https://gist.github.com/Ruskiy69/4751306.js"></script></div>
<div>
<br /></div>
<div>
So for the first sprite, the shader will display the texels in the range [0, 1/w] .. [1/w, 1/h], right? Then for the next one, we give it an offset of <1/w, 1/h> so now we are rendering texels [1/w, 2/w] .. [2/w, 2/h], which corresponds to the second sprite in the atlas. I just realized that this will likely only work with single-row sprite sheets, so I may need to tweak this code somewhat. I currently only exclusively use single-row animations for the hero.<br />
<br />
<h3>
Quick Swapping Sprite Sheets</h3>
</div>
If I want to change the hero from a standing animation to a jumping one, I can (assuming a list of valid animations) do <span style="font-family: Courier New, Courier, monospace;">m_Player.SwapSpriteSheet(m_Animatons[JUMP]->GetHeader()) </span>and from then on, the renderer will use a new texture and have new shader parameters for rendering. Here is the method in action:</div>
<div>
<br /></div>
<div>
<script src="https://gist.github.com/Ruskiy69/4751336.js"></script>
</div>
<div>
In order to minimize data transfer to the shader, the sprite size is passed only a single time, on loading and on swapping. Otherwise, only the offset is passed.<br />
<br />
<h3>
Summary</h3>
</div>
<div>
So there is a technical inside-look at how sprite animations are implemented in <i>IronClad. </i>You can examine the full header and implementation files <a href="https://github.com/Ruskiy69/IronClad/blob/master/Source/include/Entity/Animation.hpp" target="_blank">here</a> and <a href="https://github.com/Ruskiy69/IronClad/blob/master/Source/src/Entity/Animation.cpp" target="_blank">here</a>, respectively. This stuff will be tweaked and perfected in the future, so this post may not completely accurately reflect the inner workings of the engine. </div>
<div>
Please feel free to add constructive criticism, questions, or general thoughts in the comments below!</div>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-1680145419204752389.post-62568599032090620372013-02-03T22:46:00.002-08:002013-06-06T09:03:01.120-07:00Rendering Text in OpenGL Using FreeType Fonts<b>EDIT (04.14.2013):</b> Tutorial updated to handle new-lines (<span style="font-family: Courier New, Courier, monospace;">\n</span><span style="font-family: inherit;"> character)</span><br />
<br />
I finally decided to tackle the rendering of TrueType fonts in my engine. It proved to be a much bigger challenge than I had originally anticipated; I perused over dozens of outdated guides, tutorials, code snippets, and documentation files to finally achieve something legible on screen. I decided to provide a complete guide to this process so that if anyone should decide to follow in my footsteps, they will know where to go.<br />
<br />
<a name='more'></a><br />
<h3>
FreeType 2 Installation</h3>
OpenGL works with pixels, and TrueType fonts are not stored like image files, so we need the FreeType 2 library to create font bitmaps. If you are well-versed in 3rd party API installation, feel free to skip this section. I have only performed the compilation using Visual Studio 2010 and 2012.<br />
<ul>
<li>Download the latest headers for FreeType 2 from <a href="http://sourceforge.net/projects/freetype/files/latest/download?source=files">SourceForge</a>. As of this write-up, the latest version is 2.4.11.</li>
<li>Unzip the archive and go to the <span style="font-family: Courier New, Courier, monospace;">builds</span> folder to locate your platform. I will be demonstrating this with the <span style="font-family: Courier New, Courier, monospace;">win32/vc2010</span><span style="font-family: inherit;"> build.</span></li>
<li><span style="font-family: inherit;">Open </span><span style="font-family: Courier New, Courier, monospace;">freetype.sln</span><span style="font-family: inherit;"> in Visual Studio. If you are running VS2012, you will need to update the solution to use the latest compiler and libraries.</span></li>
<li><span style="font-family: inherit;">Select the Release candidate and go to </span><span style="font-family: Courier New, Courier, monospace;">Build->Build Solution</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">.</span></li>
<li><span style="font-family: inherit;">The compiled </span><span style="font-family: Courier New, Courier, monospace;">.lib</span><span style="font-family: inherit;"> file will be located in </span><span style="font-family: Courier New, Courier, monospace;">objs/win32/vc2010/freetype[version].lib</span><span style="font-family: inherit;">, where </span><span style="font-family: Courier New, Courier, monospace;">[version]</span><span style="font-family: inherit;"> is "</span><span style="font-family: Courier New, Courier, monospace;">2411</span><span style="font-family: inherit;">" as of this writing.</span></li>
<li><span style="font-family: inherit;">Copy this file to somewhere in your current project directory's library path.</span></li>
<li><span style="font-family: inherit;">Copy the contents of the </span><span style="font-family: Courier New, Courier, monospace;">include/</span><span style="font-family: inherit;"> folder to somewhere in your current project directory's include path.</span></li>
</ul>
<div>
<br /></div>
<h3>
Basic Structures</h3>
<div>
We are going to define some structures in order to make handling the fonts a bit easier. We need a rectangle to keep track of dimensions, a color for the text color, an a 2D vector to track position. Also, I'm going to include my vertex structure, representing a vertex to send to the VBO for rendering. This is pretty standard and I assume if you've made it this far in OpenGL, you have one of your own.</div>
<div>
<br />
<script src="https://gist.github.com/4700992.js"></script></div>
<div>
<br /></div>
<h3>
Font.hpp</h3>
<div>
<br /></div>
This will be the main font header that is used to render text. To load a <span style="font-family: Courier New, Courier, monospace;">.ttf</span> font file, we call <span style="font-family: Courier New, Courier, monospace;">LoadFromFile()</span>. Here, the <span style="font-family: Courier New, Courier, monospace;">mp_glyphTextures</span> map will be filled out in order to create {character: glyph} pairs, which are later used in rendering to find offset values and bind the character bitmaps. The <span style="font-family: Courier New, Courier, monospace;">Glyph</span> struct contains a rectangle representing the various offsets (a <span style="font-family: Courier New, Courier, monospace;">g</span> should be drawn lower than a <span style="font-family: Courier New, Courier, monospace;">b</span>, for example), and the bitmap texture. When <span style="font-family: Courier New, Courier, monospace;">RenderText()</span> is called, each character in the given string will be rendered using the unique texture found in the dictionary. The <span style="font-family: Courier New, Courier, monospace;">m_FontRender</span><span style="font-family: inherit;"> may throw some people off. This is just a very basic shader wrapper class I have written, and I'm sure anyone following this tutorial has a similar wrapper of their own. I will go into more detail as to what the shader does later. </span>Here is the class outline:<br />
<br />
<script src="https://gist.github.com/4700997.js"></script>The comments should explain everything else in a pretty detailed fashion. Now on to the implementation.<br />
<br />
<h3>
<span style="font-family: inherit; font-size: large;">
Font.cpp</span></h3>
<div>
This a detailed explanation of the implementation of the <span style="font-family: Courier New, Courier, monospace;">CFont</span><span style="font-family: inherit;"> class</span>.<br />
<br /></div>
<h3>
<span style="font-family: Courier New, Courier, monospace;">Initialize()</span></h3>
<div>
<span style="font-family: inherit;">Here the TrueType library is initialized. This can be called explicitly via </span><span style="font-family: Courier New, Courier, monospace;">CFont::Initialize()</span><span style="font-family: inherit;">, but it will also be called by default when a </span><span style="font-family: Courier New, Courier, monospace;">CFont</span><span style="font-family: inherit;"> instance is created.</span><br />
<script src="https://gist.github.com/4705226.js"></script><br /></div>
<h3>
<span style="font-family: Courier New, Courier, monospace;">CFont()</span></h3>
<span style="font-family: inherit;">This is the class constructor. Here, we will load the shader and verify that the TrueType library is initialized.</span><br />
<span style="font-family: inherit;"><br /></span>
<script src="https://gist.github.com/4705214.js"></script><br />
<h3>
<span style="font-family: Courier New, Courier, monospace;">LoadFromFile()</span></h3>
<div>
Now we must load the font. <span style="font-family: Courier New, Courier, monospace;">Filename</span> is a path to a TrueType font (<span style="font-family: Courier New, Courier, monospace;">.ttf</span>) and <span style="font-family: Courier New, Courier, monospace;">size</span> is the size of the font, in pixels.<br />
<br />
<script src="https://gist.github.com/4705248.js"></script>
<br />
<h3>
<span style="font-family: Courier New, Courier, monospace;">RenderText()</span></h3>
<span style="font-family: Courier New, Courier, monospace;">text</span><span style="font-family: inherit;"> is, obviously, the text we want to render. Currently, this only supports one line at a time, so characters like '</span><span style="font-family: Courier New, Courier, monospace;">\r</span><span style="font-family: inherit;">' will not render properly. Actually they likely won't render at all and will cause a crash. You should add bounds checking to ensure that the provided char is within the range of </span>render-able<span style="font-family: inherit;"> bitmaps. </span><span style="font-family: Courier New, Courier, monospace;">Pos</span> is the position where to start rendering. It is not the top-left corner of the text, but rather is on the line to be written on. Imagine a piece of paper: <span style="font-family: Courier New, Courier, monospace;">Pos</span> is the line which you're writing on.<br />
<br />
<script src="https://gist.github.com/4705286.js"></script>
</div>
<br />
<h3>
FontRender.fs</h3>
There is some shader magic necessary in order to properly render the text. Since TrueType gives us a monochrome bitmap, we need to specify that we want to use the <span style="font-family: Courier New, Courier, monospace;">r</span> value (specified when we said <span style="font-family: Courier New, Courier, monospace;">GL_R8</span> and <span style="font-family: Courier New, Courier, monospace;">GL_RED</span> in the <span style="font-family: Courier New, Courier, monospace;">glTexImage2D</span> call in <span style="font-family: Courier New, Courier, monospace;">CFont::LoadFromFile()</span> in the incoming texture fragment for all four components for the output fragment.<br />
<br />
<script src="https://gist.github.com/4705303.js"></script>
There you have it! The rest of the methods in <span style="font-family: Courier New, Courier, monospace;">CFont</span> should be fairly easy to implement. I mean, I'm sure it's fairly self-explanatory that <span style="font-family: Courier New, Courier, monospace;">CFont::SetColor()</span> just modifies <span style="font-family: Courier New, Courier, monospace;">CFont::m_Color</span> to reflect the new RGB values, and that <span style="font-family: Courier New, Courier, monospace;">Resize()</span> just calls <span style="font-family: Courier New, Courier, monospace;">CFont::LoadFromFile()</span> again with the new size specified.<br />
<br />
You can see the raw class files directly from my <i>IronClad </i>rendering engine in their entirety on my Github <a href="https://github.com/Ruskiy69/IronClad/blob/master/Source/include/Fonts/Font.hpp" target="_blank">here</a> (header) and <a href="https://github.com/Ruskiy69/IronClad/blob/master/Source/src/Fonts/Font.cpp" target="_blank">here</a> (implementation). Hopefully I will be modifying this system soon to use a texture atlas to contain all of the glyph bitmaps in a single texture and load a VBO with custom texture coordinates on-demand. Feel free to add any comments, questions, or suggestions below!Unknownnoreply@blogger.com6tag:blogger.com,1999:blog-1680145419204752389.post-3771746677767102632013-01-22T22:04:00.001-08:002013-02-03T22:55:12.799-08:00First Praecursor Screenshots<span style="font-family: inherit;">I'm trying so hard to stay motivated on this project, it has a lot of potential in my mind. With the spring semester just starting, I hope I'll be able to keep time available to work on <i>Praecursor</i>. Feel free to follow my progress on the game's <a href="https://www.github.com/Ruskiy69/Praecursor" target="_blank">GitHub page</a>.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">I've made some progress on the game. I found an excellent free texture pack with lots of textures perfect for an urban, impoverished setting. They are incredibly realistic, so the main hero stands out like a sore thumb. Here are a few screenshots:</span><br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz6O5_7WJmNG0PL55Beqb7NABfZADja4oT2dGaEGpaxD4D3l2UuStjq8eDVlMH5pdihNd7LaeraEtFvAFTzobAV93_oUrpY0AIGEklvLut45f4uw_0V07p0DyQHl4FL0tVqS4MOw0JUaY/s1600/Untitled.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="239" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz6O5_7WJmNG0PL55Beqb7NABfZADja4oT2dGaEGpaxD4D3l2UuStjq8eDVlMH5pdihNd7LaeraEtFvAFTzobAV93_oUrpY0AIGEklvLut45f4uw_0V07p0DyQHl4FL0tVqS4MOw0JUaY/s320/Untitled.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Player is way too small!</td></tr>
</tbody></table>
<br />
<a name='more'></a><br /><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6M41pqNsNIMqQqoWCkJmamkCr__0lpkIuSjbN2yk86oMuvDmhzn6QS9UxKduPKGIVT4Af02tqB6i8mAIuzCm3oKcGsXYrOtNXZs0q2Yvyu-pkxTBgu-83qZw2ToDzC37m3WR-9PgOPrs/s1600/Untitled.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="239" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6M41pqNsNIMqQqoWCkJmamkCr__0lpkIuSjbN2yk86oMuvDmhzn6QS9UxKduPKGIVT4Af02tqB6i8mAIuzCm3oKcGsXYrOtNXZs0q2Yvyu-pkxTBgu-83qZw2ToDzC37m3WR-9PgOPrs/s320/Untitled.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Much better :)</td></tr>
</tbody></table>
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-64599135120057437112013-01-15T14:04:00.000-08:002013-02-03T22:55:23.357-08:00A New Beginning<span style="font-weight: normal;"><span style="font-family: inherit;">For the past several weeks, I've been working on implementing a 2D OpenGL rendering engine dubbed IronClad. A lot of progress has been made, and I have decided to start working on a new project that will fully utilize the features of my engine. You can find the source code on my GitHub page <a href="https://github.com/Ruskiy69/IronClad" target="_blank">here</a>.</span></span><br />
<div>
<br /></div>
<h3>
<span style="font-family: inherit;">
Implemented Features</span></h3>
<div>
<ul>
<li style="border: 0px; margin: 0px; padding: 0px;"><span style="font-family: inherit;">Full use of modern OpenGL features such as vertex array objects</span></li>
<li style="border: 0px; margin: 0px; padding: 0px;"><span style="font-family: inherit;">Instanced geometry which allows for high-speed, batched rendering of many vertices</span></li>
<li style="border: 0px; margin: 0px; padding: 0px;"><span style="font-family: inherit;">Per-pixel shader-based lighting (currently only point lights)</span></li>
<li style="border: 0px; margin: 0px; padding: 0px;"><span style="font-family: inherit;">Optimized mesh loading</span></li>
<li style="border: 0px; margin: 0px; padding: 0px;"><span style="font-family: inherit;">Entity wrapper for easily controllable mesh instances</span></li>
<li style="border: 0px; margin: 0px; padding: 0px;"><span style="font-family: inherit;">Minimalistic physics system</span></li>
<li style="border: 0px; margin: 0px; padding: 0px;"><span style="font-family: inherit;">Loading of a custom level format for easy scene creation</span></li>
</ul>
<div>
<br /></div>
<hr />
</div>
<h4>
<span style="font-family: inherit; font-size: large;"><br /></span></h4>
<h4>
<span style="font-family: inherit; font-size: large;">Latest Project: Praecursor</span></h4>
<i style="font-family: inherit;"><br /></i>
<i style="font-family: inherit;">Precursor</i><span style="font-family: inherit;"> - n. </span><br />
<ol>
<li><span style="background-color: white; color: #212121; font-family: inherit; line-height: 15px;">A person or thing that comes before another of the same kind; a forerunner</span></li>
<li><span style="background-color: white; color: #212121; font-family: inherit; line-height: 15px;">A substance from which another is formed, esp. by metabolic reaction. </span></li>
</ol>
<h3>
<span style="font-family: inherit;">Story</span></h3>
<div>
<span style="color: #212121; font-family: inherit; font-size: large; line-height: 15px;"></span><br />
<a name='more'></a><span style="color: #212121; font-family: inherit; font-size: large; line-height: 15px;"><br /></span></div>
<div>
<span style="color: #212121; line-height: 15px;"><span style="font-family: inherit;">Over the years, a resistance has slowly been brewing in the tight-knit lower-class communities with the intent of ending the limitation of availability. Minor outbreaks of violence have been popping up more and more frequently across the nation. They are in desperate need of a tipping point and something to give them an advantage.</span></span><br />
<span style="font-family: inherit;"><span style="color: #212121;"><span style="line-height: 15px;">In an effort to invent time travel, scientists attempted to graft light molecule sequencing with human DNA. The experiment went wrong, resulting in a human being who lived a few seconds ahead of everyone else, an effect subject to variation based on light exposure. And that's where you come in...</span></span></span><br />
<div>
<span style="font-family: inherit;">I watched <a href="http://www.imdb.com/title/tt1276104/" rel="nofollow" target="_blank">Looper</a> recently (excellent movie by the way), and it sparked me to think about using time-travel or time-manipulation as a game mechanic. Thus, <i>Praecursor </i>was born. The inspiration for the title is accredited <span style="color: #212121; line-height: 15px;">to Tonitrus on the <a href="http://freenode.net/" rel="nofollow" target="_blank">FreeNode IRC network</a>.</span></span></div>
</div>
<div>
<span style="color: #212121; font-family: inherit; line-height: 15px;"><br /></span></div>
<div>
<span style="font-family: inherit;"><span style="color: #212121; line-height: 15px;">The year is 2033. With the invention of genetic enhancement, everyone expected the human race to thrive and coexist peacefully within a generation. Instead, several powerful corporations monopolized the industry, driving prices through the roof to make the enhancements exclusive to the upper class citizens of the world. Because of this, </span><span style="color: #212121; line-height: 15px;">the rift between the wealthy and the lower class has grown dramatically. The artificial augmentations that </span><span style="color: #212121; line-height: 15px;">enhance cognitive and athletic ability, overcome physical limitations, and add unprecedented mastery of skills are easily accessible to the rich, consistently giving them a distinct advantage in all aspects of life over those less fortunate.</span></span><br />
<span style="font-family: inherit;"><span style="color: #212121; line-height: 15px;"><br /></span></span>
<span style="font-family: inherit;"><span style="color: #212121; line-height: 15px;"><br /></span></span>
<span style="color: #212121;"><span style="line-height: 15px;"><br /></span></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2oJLw7yQXdyDX0Eg3_bcYsoUnQNyf4i5n_Xcv754yDaNV7w935FZAJ71BBWu-ayXtCgrv9kgYqUVnRDXgegotzeYqpS4LvlAL6xxjC2SdzXlGbiMfAQTNOP4V75UKZtdWFa8QAxdKyAQw/s1600/Box+Art.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2oJLw7yQXdyDX0Eg3_bcYsoUnQNyf4i5n_Xcv754yDaNV7w935FZAJ71BBWu-ayXtCgrv9kgYqUVnRDXgegotzeYqpS4LvlAL6xxjC2SdzXlGbiMfAQTNOP4V75UKZtdWFa8QAxdKyAQw/s320/Box+Art.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<span style="color: #212121;"><span style="line-height: 15px;"><br /></span></span></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-88132642976378910632012-11-13T18:20:00.000-08:002013-06-27T19:04:08.901-07:00A Guide to Instanced Geometry<span style="font-family: inherit;">As stated in the title, this is more of a guide than a tutorial. It isn't for the complete beginner, some experience is necessary. Throughout this I assume you have a general knowledge of <a href="https://en.wikipedia.org/wiki/Polygon_mesh" target="_blank">what a mesh is</a>, basic understanding of how matrices work, basic knowledge of GLSL, and experience with C++ or another object-oriented language. I am just writing about my own personal implementation of instanced geometry, which is definitely open for comments and suggestions. The code snippets are stripped down versions directly from my basic 2D OpenGL rendering engine I have dubbed <i>IronClad.</i></span><br />
<br />
<h3>
What Is Instanced Geometry?</h3>
<span style="font-family: inherit;">Primitive rendering techniques have many copies of a single object's data. Say you wanted to draw a tiled map, with 2 unique tiles. Say, for instance (no pun intended), a floor tile and a wall tile. Now, each of these objects contains, at the very least, 8 floats for vertex positions, and 8 floats for texture coordinates. That's 8 * 4 + 8 * 4 = 64 bytes. If each instance of a tile contains this information for rendering, and you have 1000 wall tiles, that's 64 kilobytes of memory! And that's not even considering the other tile types. Obviously, this is an example of a very simple mesh with only 4 vertices. Most games have models with hundreds if not thousands of vertices, so you can see why it'd be a serious problem to have multiple copies of that data.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Of course, there's a simple solution to this problem; you keep around one copy of the data in the first object you create, and the other objects simply refer to the original, just in their own position. Well, that's exactly where instancing comes in!</span><br />
<br />
<a name='more'></a><br />
<br />
<h3>
A Visual Example</h3>
<div style="text-align: left;">
</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfQ593L_n61V9JCpW94O8sj5etN3OIdlS-wWdkX8O3UexvOgPIY3bZsGaKySMGoOteUIiG7Yj4xyrCjKYgUOJFQx3jgBa_jv9_7lB5U4yMbaBsEoTO70IoaaZbMFYKd-ImwhyiwkvIH-HX/s1600/InstancingDemo.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="513" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfQ593L_n61V9JCpW94O8sj5etN3OIdlS-wWdkX8O3UexvOgPIY3bZsGaKySMGoOteUIiG7Yj4xyrCjKYgUOJFQx3jgBa_jv9_7lB5U4yMbaBsEoTO70IoaaZbMFYKd-ImwhyiwkvIH-HX/s640/InstancingDemo.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-family: inherit;">A Visual Explanation of the Benefits of Instanced Geometry</span></td></tr>
</tbody></table>
<div>
<h3>
<span style="font-family: inherit; font-size: small;">How Is It Done?</span></h3>
<span style="font-family: inherit; font-size: small;">M</span><span style="font-family: inherit;">eshes are loaded. Mesh instances contain pointers to meshes as well as position data. </span><span style="font-family: inherit;">The meshes are offloaded to GPU memory and deleted. </span><span style="font-family: inherit;">The scene renderer loads a model-view matrix with the position data for each instance of a mesh, passing it on to a vertex shader. Finally, the mesh is rendered.</span></div>
<span style="font-family: inherit;"><br /></span>
<br />
<h3>
<span style="font-family: inherit;">Loading Meshes Efficiently</span></h3>
<span style="font-family: inherit;">A mesh is an object containing vertex data that can represent something in the game world, like the tile in the above example. This is loaded from a file a single time. Most likely, you'll need some sort of management system that ensures no more than one copy of any given mesh is loaded at one time. <i>IronClad </i>uses an asset manager for image files, fonts, sounds, and meshes. If an asset is already loaded, it returns a pointer to the asset, and if it is not, it loads it and stores it in a list of assets. It's relatively simple, but maybe I'll make another blog post showcasing it.</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<h3>
<span style="font-family: inherit;">Mesh Instances</span></h3>
<span style="font-family: inherit;">So, once you have meshes only being loaded once, the battle is halfway over. Now, there should be a class that is an instance of a mesh. A mesh instance contains a pointer to the mesh asset and some position data. When drawing, the same mesh data is used for every instance of a mesh, but the position data changes where it appears. Here's an example of a mesh instance class stripped from my engine:</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<h3>
<span style="font-family: inherit;">Organizing the Scene</span></h3>
<span style="font-family: inherit;">Most engines have some sort of "scene" object that contains everything that need to be rendered on the screen. This high-level interface should be all that the user interacts with, so they can do something like</span><br />
<br />
<pre>Scene.AddMesh("Test.mesh", 100, 100);
Scene.AddMesh("Test.mesh", 200, 200);</pre>
<span style="font-family: inherit;"><br />
Which would <i>load </i>the mesh once, and add two <i>instances </i>in two different <i>positions</i>. That instanced geometry in a nutshell, once more.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Here's a very basic example of what it could look like:</span><br />
<br />
<pre>bool Scene::AddMesh(const char* filename, int x, int y)
{
// Create an instance and load the mesh into it.
MeshInstance* inst = new MeshInstance;
Mesh* loaded_mesh = MeshManager::LoadMesh(filename);
// Quick error check, assuming LoadMesh returns NULL
// on failure to load the mesh.
if(!loaded_mesh) return false;
// Set up the instance.
inst->SetMesh(loaded_mesh);
inst->Move(x, y);
// Add instance to scene
this->allMeshes.push_back(inst);
return true;
}
</pre>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">If you have something like this implemented, it's time to move on to loading matrices and rendering!</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<h3>
<span style="font-family: inherit;">Matrices</span></h3>
<span style="font-family: inherit;">There are matrix libraries out there specifically made for OpenGL, such as </span><a href="http://glm.g-truc.net/" style="font-family: inherit;" target="_blank">the GLM library</a><span style="font-family: inherit;">, but for </span><i style="font-family: inherit;">IronClad</i><span style="font-family: inherit;">, I rolled my own matrix class. It has the bare minimum of what I need, and it helped me learn a lot. Since this is purely in 2D and there are no transformations involved, the model-view matrix only needs to have the position data; that's perfect because that's exactly what the mesh instances already have! So, we add this method to the mesh instance:</span><br />
<br />
<pre>void CMeshInstance::LoadPosition(math::matrix4x4_t& MVMatrix) {
MVMatrix[0][3] = this->Position.x;
MVMatrix[1][3] = this->Position.y;
}
</pre>
<br />
Keep in mind that my matrix class is row-major, and OpenGL shaders do matrix math as column-major, so it needs to be transposed before being sent to the shader, which we will see later. Now, we have this method set up to call in the scene and set up the shader for rendering!<br />
<span style="font-family: inherit;"><br /></span>
<br />
<h3>
<span style="font-family: inherit;">Vertex Shader</span></h3>
<span style="font-family: inherit;">Since OpenGL did away with the built-in matrix stack long ago, we need a simple vertex shader that outputs the proper position data. Here we go:</span><br />
<br />
<pre>#version 330
// Input: vertex position, texture coordinates, color.
in vec2 vs_vertex;
smooth in vec2 vs_texc;
smooth in vec4 vs_color;
// Matrices
uniform mat4 proj;
uniform mat4 mv;
// Output to the fragment shader: texture coordinates, color.
smooth out vec4 fs_color;
smooth out vec2 fs_texc;
void main()
{
// Do the transformation.
gl_Position = proj * mv * vec4(vs_vertex, 1.0, 1.0);
// Pass to fragment shader.
fs_color = vs_color;
fs_texc = vs_texc;
}
</pre>
<br />
<div>
<h3>
<span style="font-family: inherit;">Putting It All Together</span></h3>
</div>
<span style="font-family: inherit;">Now comes the grande finale: rendering. We have our mesh, we have our mesh instances, we have our shaders, our matrices, and our scene. The time has come.</span><br />
<span style="font-family: inherit;">We first enable the VBO containing the mesh vertex data, then iterate through the scene's mesh instances, passing the matrix loaded with position data to the shader, and finally draw it to the screen.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Here is a simplified render loop I use in <i>IronClad:</i></span><br />
<i style="font-family: inherit;"><br /></i>
<br />
<pre>void CScene::Render()
{
static math::matrix4x4_t MVMatrix = math::matrix4x4_t::CreateIdentityMatrix();
// When drawing, retrieve data from the geometry VBO we loaded with
// mesh data on calls to CScene::AddMesh()
this->GeometryVBO.Bind();
// Iterate through each mesh, load the matrix, and render.
// There are more advanced concepts such as multi-material meshes with
// surfaces that can be added here, but that's for another time.
for(size_t i = 0; i < this->allMeshes.size(); ++i)
{
// Load the model-view matrix.
this->allMeshes[i]->LoadPosition(MVMatrix);
// Bind mesh texture.
allMeshes[i]->BindTexture();
// Use the default shader we created above (obviously loaded).
this->DefaultShader.Bind();
// Pass the model-view matrix to the vertex shader.
// We specify GL_TRUE as the last 3rd param to transpose the
// matrix since it is in row-major here and GLSL expects column-major.
glUniformMatrix4fv(
glGetUniformLocation("mv"), 1, GL_TRUE,
MVMatrix.GetMatrixPointer());
// This would normally be a glDrawElements() call,
// based on whether or not IBOs are implemented with the VBOs.
this->allMeshes[i].Render();
this->DefaultShader.Unbind();
this->allMeshes[i].UnbindTexture();
}
}
</pre>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">And there you have it! Instanced geometry.</span><br />
<span style="font-family: inherit;">Using this technique, I've achieved drawing several thousand triangles on the screen at once with lighting and post-processing enabled, so you can see that this is a very powerful technique.</span><br />
<span style="font-family: inherit;"><br />
Happy instancing; comment below with any questions or remarks :)</span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-28787856662570892322012-10-19T13:08:00.003-07:002013-02-03T22:55:54.834-08:00Development On Hold<span style="font-family: inherit;">Throughout the course of development for <i>Collapse</i>, I had been relying on OpenGL's age-old immediate mode for rendering. This proved to be a serious hindrance as I kept adding more advanced features such as lighting and shadows. My previous post about shadows works extremely well when shadows are limited to a single light. Clearly this is unacceptable, and the various techniques I tried to get it functioning with many lights either proved to be much too slow in immediate mode, or would require a serious amount of restructuring of the rendering system.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">So, I put everything on hold temporarily and decided to learn modern OpenGL. I found a <a href="http://www.arcsynthesis.org/gltut/" target="_blank">superb series of tutorials</a> through <a href="https://www.stumbleupon.com/" target="_blank">StumbleUpon</a>, and have been following them to gain a good base in the modern features of OpenGL, such as vertex array objects, matrices, and indexed geometry.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">This task has sparked the development of a 2D engine, which I have dubbed <i>IronClad.</i> I've made a lot of progress in the past few weeks, implementing a VAO wrapper, support for a custom mesh file format, indexed geometry, shaders, and other nice features. I have also made a switch from SDL to <a href="http://www.glfw.org/" target="_blank">GLFW</a> for window management, and abandoned SDL_ttf in favor of <a href="http://homepages.paradise.net.nz/henryj/code/" target="_blank">FTGL</a>. The reason for this is that the latest stable version of SDL only supports OpenGL contexts using versions <= 2.1, and I need more than that. The latest development build, SDL 2.0, supports the versions I need, but I'd most likely need a serious refactoring of my SDL code base to support it, so I decided to just make the switch to something OpenGL-specific.</span><br />
<br />
<a name='more'></a><br /><br />
<b><span style="font-family: inherit;">Todo List (as of 11.14.2012):</span></b><br />
<br />
<ul>
<li><strike><span style="font-family: inherit;">Vertex array/buffer object wrapper</span></strike></li>
</ul>
<ul>
<li><strike><span style="font-family: inherit;">Indexed geometry</span></strike></li>
</ul>
<ul>
<li><strike><span style="font-family: inherit;">Meshes</span></strike></li>
</ul>
<ul>
<li><strike><span style="font-family: inherit;">Vertex and fragment shaders</span></strike></li>
</ul>
<ul>
<li><strike><span style="font-family: inherit;">Projection matrices</span></strike></li>
</ul>
<ul>
<li><strike><span style="font-family: inherit;">High-level scene manager</span></strike></li>
</ul>
<ul>
<li><strike><span style="font-family: inherit;">Instanced geometry</span></strike></li>
</ul>
<ul>
<li><span style="font-family: inherit;">Geometry shaders</span></li>
</ul>
<ul>
<li><strike><span style="font-family: inherit;">Keyboard and mouse events through GLFW</span></strike></li>
</ul>
<ul>
<li><strike><span style="font-family: inherit;">Transformation matrices for the instanced geometry</span></strike></li>
</ul>
<ul>
<li><strike><span style="font-family: inherit;">Lighting</span></strike></li>
</ul>
<ul>
<li><strike><span style="font-family: inherit;">Post-processing effects</span></strike></li>
</ul>
<ul>
<li><span style="font-family: inherit;">Shadows</span></li>
</ul>
<ul>
<li><strike><span style="font-family: inherit;">Sprite wrapper</span></strike></li>
</ul>
<ul>
<li><strike><span style="font-family: inherit;">OpenGL framebuffer object wrapper</span></strike></li>
</ul>
<br />
<div>
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-4321181158734624622012-09-29T18:22:00.000-07:002013-02-03T22:56:53.127-08:00Working With Shadows<span style="font-family: inherit;">The logical course of action after finishing lighting is to move on to shadows. I opted for a relatively simple, software-based approach. It involves casting rays from the light source to individual edges of the tiles in the collision map, and drawing black quads based on the rays.</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<div>
<span style="font-family: inherit;">In my current implementation, the shadows are independent of the other lights. Thus, shadows cast by one light will be left untouched if there is another light in the way. This obviously causes problems, and a better method that will calculate cumulative shadows is currently in progress. But for a single light, the following algorithm suffices. Hopefully some OpenGL beginners trying to create shadows can gain some knowledge from my own trial-and-error!</span></div>
<div>
<span style="font-family: inherit;"></span><br />
<a name='more'></a><span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">The steps are as follows:</span></div>
<div>
<ul>
<li><span style="font-family: inherit;">Determine the light position.</span></li>
</ul>
</div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYcgDMZzsXSIctwarqFOxcKzm0bGClYw0l6pltFBso0m6FojyvO2sQ-ajR6Gr_nM-dZlFyJ8gQwt9Z9H383hIfdX8mMcUH8qNI79BiiAIpi6jDdYBm_kHQi329UjVxCM4lyKZTCEUyFSNA/s1600/LightingAlgorithm_1.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><span style="font-family: inherit;"><img border="0" height="143" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYcgDMZzsXSIctwarqFOxcKzm0bGClYw0l6pltFBso0m6FojyvO2sQ-ajR6Gr_nM-dZlFyJ8gQwt9Z9H383hIfdX8mMcUH8qNI79BiiAIpi6jDdYBm_kHQi329UjVxCM4lyKZTCEUyFSNA/s200/LightingAlgorithm_1.png" width="200" /></span></a></div>
<ul>
<li><span style="font-family: inherit;">Cast a ray from the light to the first vertex (top-left point)</span></li>
<li><span style="font-family: inherit;">Calculate slope and extend the ray, so instead of it being from the light to the vertex, it goes from the vertex to some really distant value.</span></li>
<li><span style="font-family: inherit;">Keep this ray for later (I'll call it </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">TopLeft</span><span style="font-family: inherit;"> later).</span></li>
</ul>
</div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdsuRuGEjePUm8u1q0_bsQ_UmNBxbTpaFCUxTfokaWAufwz_3Tp8LNSUwjDygXwngCLmGPz_SV1f4I2ayzv2JFd6VAJAyjBAE5X1VDweIOP8qyWTswhOG_F1d72GiaygK1dD-4mBOmxytP/s1600/LightingAlgorithm_2.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><span style="font-family: inherit;"><img border="0" height="143" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdsuRuGEjePUm8u1q0_bsQ_UmNBxbTpaFCUxTfokaWAufwz_3Tp8LNSUwjDygXwngCLmGPz_SV1f4I2ayzv2JFd6VAJAyjBAE5X1VDweIOP8qyWTswhOG_F1d72GiaygK1dD-4mBOmxytP/s200/LightingAlgorithm_2.png" width="200" /></span></a></div>
<ul>
<li><span style="font-family: inherit;">Repeat this process for each vertex, so you get 4 rays, which I'll call </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">TopLeft</span><span style="font-family: inherit;">, </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">TopRight</span><span style="font-family: inherit;">, </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">BottomRight</span><span style="font-family: inherit;">, and </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">BottomLeft</span><span style="font-family: inherit;"> in the example code below.</span></li>
</ul>
<div>
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><br /></span></div>
<div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhi0qiq-wj5VvPTPdMKgbw6kRAe5ImQhIp6C441iN2_Suxpta9K3QVYQ3cTpxGCm4cqb5Hi4m3FGk1OdSeMDxYRMWuy9t5Lp-IxRpJcDMhcah9n6jvWUn-GAkz8GJYjg_GRVKrc8xPaGycT/s1600/LightingAlgorithm_3.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><span style="font-family: inherit;"><img border="0" height="143" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhi0qiq-wj5VvPTPdMKgbw6kRAe5ImQhIp6C441iN2_Suxpta9K3QVYQ3cTpxGCm4cqb5Hi4m3FGk1OdSeMDxYRMWuy9t5Lp-IxRpJcDMhcah9n6jvWUn-GAkz8GJYjg_GRVKrc8xPaGycT/s200/LightingAlgorithm_3.png" width="200" /></span></a></div>
<div>
<ul><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhi0qiq-wj5VvPTPdMKgbw6kRAe5ImQhIp6C441iN2_Suxpta9K3QVYQ3cTpxGCm4cqb5Hi4m3FGk1OdSeMDxYRMWuy9t5Lp-IxRpJcDMhcah9n6jvWUn-GAkz8GJYjg_GRVKrc8xPaGycT/s1600/LightingAlgorithm_3.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><span style="font-family: inherit;"><br /></span></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhi0qiq-wj5VvPTPdMKgbw6kRAe5ImQhIp6C441iN2_Suxpta9K3QVYQ3cTpxGCm4cqb5Hi4m3FGk1OdSeMDxYRMWuy9t5Lp-IxRpJcDMhcah9n6jvWUn-GAkz8GJYjg_GRVKrc8xPaGycT/s1600/LightingAlgorithm_3.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><span style="font-family: inherit;"><br /></span></a>
<li><span style="font-family: inherit;">Now that we have determined the sectors for shading, we test to see which quads are necessary to fill. This is not shown in the diagrams, but in practice, if the light is above the tile, the sector created by the TopLeft and TopRight rays will cut across the tile itself, which is obviously undesirable. The following must be true:</span></li>
<ul>
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">TopLeft.Start.y < LightPos.y </span><span style="font-family: inherit; font-size: xx-small;">: </span><span style="font-family: inherit;">Draw quad</span></li>
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">TopRight.Start.x > LightPos.x </span><span style="font-family: inherit; font-size: xx-small;">: </span><span style="font-family: inherit;">Draw quad</span></li>
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">BottomRight.Start.y > LightPos.y </span><span style="font-family: inherit; font-size: xx-small;">: </span><span style="font-family: inherit;">Draw quad</span></li>
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">BottomLeft.Start.x < LightPos.x </span><span style="font-family: inherit; font-size: xx-small;">: </span><span style="font-family: inherit;">Draw quad</span></li>
</ul>
</ul>
<span style="font-family: inherit;"><br /></span>
<br />
<ul><ul>
</ul>
</ul>
</div>
<div>
<ul>
<li><span style="font-family: inherit;">Draw the quads with whatever rendering method you wish, be it using </span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">glBegin()/glEnd()</span><span style="font-family: inherit;">, </span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">glDrawArrays()</span><span style="font-family: inherit;">,</span><span style="font-family: inherit;"><span style="font-family: inherit;"> </span>FBOs, or what have you.</span></li>
</ul>
<div>
<span style="font-family: inherit;">Here is some C++ example source code using immediate mode rendering. </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">CRay2</span><span style="font-family: inherit; font-size: xx-small;"> </span><span style="font-family: inherit;">is just a class containing two </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">CVector2</span><span style="font-family: inherit;">'s, which basically are an </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">(x, y)</span><span style="font-family: inherit;"> coordinate pair. There is a minor bug with this method, when the </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">LightPos.x</span><span style="font-family: inherit;"> is equal to the </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Ray.Start.x</span><span style="font-family: inherit;"> value, the shadow is not created as intended. When I find a fix, I'll update this code. If anyone has a fix, feel free to comment below.</span></div>
</div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<script src="https://gist.github.com/3809002.js"> </script>
<br />
<div>
<span style="font-family: inherit;">And finally, here's a screenshot of <i>Collapse</i> using shadows with a single light in-game.</span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjofAz0XsAIIAZh1Vjv-KS1FG3MjSyqeMD5CldPLppOcbD2uCXF7gPEJQknGOjgwjz4mHrlicTIozEbMiS-P9f1MEY6Zg8eFkp9UX9kVR09FbBlKvxFZgtzFuZ1eeQhkIG4BuhDSR2f7ZlO/s1600/Collapse_9-29-2012.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: inherit;"><img border="0" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjofAz0XsAIIAZh1Vjv-KS1FG3MjSyqeMD5CldPLppOcbD2uCXF7gPEJQknGOjgwjz4mHrlicTIozEbMiS-P9f1MEY6Zg8eFkp9UX9kVR09FbBlKvxFZgtzFuZ1eeQhkIG4BuhDSR2f7ZlO/s320/Collapse_9-29-2012.png" width="320" /></span></a></div>
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-71109505529938436782012-09-27T15:42:00.000-07:002013-02-03T22:56:54.116-08:00Update News<span style="font-family: inherit;">The latest version has several new features, including:</span><br />
<br />
<ul>
<li><span style="font-family: inherit;">Inventory screen (work-in-progress) that contains player stats such as health, ammo, and other detailed information about game progress. I still need my artist to draw me up large images of the tank and weapons.</span></li>
</ul>
<ul>
<li><span style="font-family: inherit;">Rasterizer system was completely removed, as it ended up being extremely complicated and not versatile at all. Also </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">std::map</span><span style="font-family: inherit;"> would automatically sort entities, causing problems with render order.</span></li>
</ul>
<ul>
<li><span style="font-family: inherit;">Weapons are added, with a simple weapon editor script to generate the files. This allows lots of weapons to be created, edited, and tweaked easily, without relying on tedious recompilation.</span></li>
</ul>
<ul>
<li><span style="font-family: inherit;">A generic asset manager has replaced the stupid system I used previously, which was one manager for fonts, one for textures, and one for audio. Now, the asset manager just handles a single </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">CAsset</span><span style="font-family: inherit;"> base class.</span></li>
</ul>
<ul>
<li><span style="font-family: inherit;">The </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">CBullet</span><span style="font-family: inherit;"> class now inherits from a generic </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">CParticle</span><span style="font-family: inherit;"> which should later allow particle effects to be implemented easily.</span></li>
</ul>
<br />
<div>
<span style="font-family: inherit;">Latest screenshots:</span></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizLaS16qXRPSmExc-MQRQ9BV_Z1D3LdUxuN1kVkcdaVYlZlJi1SDwrzTPwmIDaCjPbR5yxb7Cb9NYym_rz2v2eeBHoimvg2WXm94xxys1G2oLtEDA6YbTcipriqVyoD-Jn5BDwVFLw5qFQ/s1600/Collapse_9-24-2012.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><span style="font-family: inherit;"><img border="0" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizLaS16qXRPSmExc-MQRQ9BV_Z1D3LdUxuN1kVkcdaVYlZlJi1SDwrzTPwmIDaCjPbR5yxb7Cb9NYym_rz2v2eeBHoimvg2WXm94xxys1G2oLtEDA6YbTcipriqVyoD-Jn5BDwVFLw5qFQ/s320/Collapse_9-24-2012.png" width="320" /></span></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-family: inherit;">In-game, with new shader.</span><br />
<span style="font-family: inherit;">It looks the same because I haven't included lights within the level yet.</span><br />
<span style="font-family: inherit;"><br /></span></td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiIuRikZvYD2Gttq9rTTdMQP05CqdIHH26pfvrDAfiqOEHYoLpnw90gmEsZjz2uH27KEVHe4n2hhkYh6QzbB6oXzAl9pRw7uzRRwJGYCbe0MLZ2W8ee_GRQDZcQ_VH87iJZNtxbjP0efVw/s1600/Collapse_11-13-2012.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><span style="font-family: inherit;"><img border="0" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiIuRikZvYD2Gttq9rTTdMQP05CqdIHH26pfvrDAfiqOEHYoLpnw90gmEsZjz2uH27KEVHe4n2hhkYh6QzbB6oXzAl9pRw7uzRRwJGYCbe0MLZ2W8ee_GRQDZcQ_VH87iJZNtxbjP0efVw/s320/Collapse_11-13-2012.png" width="320" /></span></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-family: inherit;">Inventory screen (no weapon artwork)</span></td></tr>
</tbody></table>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
<span style="font-family: Times, Times New Roman, serif;"></span><br />
<span style="font-family: Times, Times New Roman, serif;"></span></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-43391728751605780512012-09-21T16:33:00.001-07:002013-02-03T22:56:55.256-08:00Let There Be Light!<span style="font-family: inherit;">"And George said unto <i>Collapse</i>, "let there be light," and there was, and George saw that it was good."</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><b>Edit (2.1.2012): </b>My lighting shader has changed quite a bit since this post; I opted for a multi-pass shader, rather than maxing out the shader variables.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">
After several weeks of reading about shaders, learning GLSL, learning about lighting, observing other projects, finally writing my own, and spending hours debugging, tweaking, and improving, it's finally done. My shader supports multiple lights, and gets re-written on the fly to support larger and larger amounts, due to GLSL loop limitations. Whenever I want to increase the amount of lights I use, I merely say:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"> </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">LightingShader.SetMacro("NUM_LIGHTS", ++lights);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: inherit;">Which will then re-write, re-compile, and re-link the shader with a new light count. Though I was considering not releasing the shader source code, here it is anyway:</span><br />
<span style="font-family: inherit;"><br />
<script src="https://gist.github.com/3809040.js"> </script>
</span><br />
<span style="font-family: inherit;">Here are some screen-shots of lighting:</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: 1em; margin-right: 1em; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZFg6K6U1NlZtNQ5UEldIgt9TYIHi02zGjRzOLmMIIgr0TQPnsDSDrrxeZ9_tMUK_XjFkxEBxhQngSwt7NzjJr5ebW6RJ8Yejpqf0LxBAEbfu4LpxpwQkkxXJHoTmT69b5fM8IfTMxT9Ho/s1600/Collapse_8-30-2012.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><span style="font-family: inherit;"><img border="0" height="253" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZFg6K6U1NlZtNQ5UEldIgt9TYIHi02zGjRzOLmMIIgr0TQPnsDSDrrxeZ9_tMUK_XjFkxEBxhQngSwt7NzjJr5ebW6RJ8Yejpqf0LxBAEbfu4LpxpwQkkxXJHoTmT69b5fM8IfTMxT9Ho/s320/Collapse_8-30-2012.png" width="320" /></span></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-family: inherit; font-size: small;">Original shader - one light (in-game)</span><br />
<span style="font-family: inherit; font-size: small;"><br /></span></td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: 1em; margin-right: 1em; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggPmeIab31TSqWKWgVF9frKCfR5iQeYwAlHzuTWz2PxTcVtifi-99feMkEj7MIkg5e7MTqsfMwVvw2hS0Nd8MxgrsD_nOJ5MSr4JObgt04Cg9heme7gMbhBp5IpYGcSrgNfoHYAFDfYgVj/s1600/Collapse_9-20-2012.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><span style="font-family: inherit;"><img border="0" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggPmeIab31TSqWKWgVF9frKCfR5iQeYwAlHzuTWz2PxTcVtifi-99feMkEj7MIkg5e7MTqsfMwVvw2hS0Nd8MxgrsD_nOJ5MSr4JObgt04Cg9heme7gMbhBp5IpYGcSrgNfoHYAFDfYgVj/s320/Collapse_9-20-2012.png" width="320" /></span></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-family: inherit; font-size: small;">Final shader - multiple lights (test zone)</span></td></tr>
</tbody></table>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-27848183894996620692012-09-10T17:51:00.002-07:002013-02-03T22:56:56.078-08:00The Show Goes On!<span style="font-family: inherit;">Fear not, the project has not been abandoned! The incredible Arma II zombie mod <a href="http://www.dayzmod.com/" rel="nofollow" target="_blank">Day-Z</a> has been sucking away a lot of my free time lately, so you guys must excuse my lack of new posts. Despite that time-wasting haven, I managed to make a significant amount of progress in <i>Collapse</i>:</span><br />
<br />
<ul>
<li><span style="font-family: inherit;">AI prototyping complete</span></li>
</ul>
<ul>
<li><span style="font-family: inherit;">Revamped level editor with support for player spawns and fine-grained control over AI behaviors</span></li>
</ul>
<ul>
<li><span style="font-family: inherit;">Rasterizer for versatility in adding shaders to textures</span></li>
</ul>
<ul>
<li><span style="font-family: inherit;">Several memory leaks fixed, several new ones created</span></li>
</ul>
<ul>
<li><span style="font-family: inherit;">Debug logging system integrated into a majority of the subsystems</span></li>
</ul>
<ul>
<li><span style="font-family: inherit;">Settings.ini file for control over file names and directories without recompilation</span></li>
</ul>
<ul>
<li><span style="font-family: inherit;">Re-designed class hierarchy</span></li>
</ul>
<ul>
<li><span style="font-family: inherit;">Asset managers for texture, audio, and fonts</span></li>
</ul>
<ul>
<li><span style="font-family: inherit;">Replacing SDL_mixer with OpenAL</span></li>
</ul>
<ul>
<li><span style="font-family: inherit;">Removal of the "library" naming system in favor of namespaces</span></li>
</ul>
<ul>
<li><span style="font-family: inherit;">System requirements checking on launch (just OpenGL > v2.1 so far)</span></li>
</ul>
<br />
<a name='more'></a><br /><br />
<div>
<span style="font-family: inherit;">I won't go into detail into these changes, but here's a screenshot showcasing the AI path-finding.</span><br />
<span style="font-family: inherit;">The red represents the untraversed path, the blue represents the current destination, the pink is the starting tile, and the green is the completed path. There are, of course, still many issues with it, such as cutting corners and not being able to find a path to certain locations, but I'm working on it</span>.<br />
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvFD6Js3vP346FM-m2vh27oESG7Y25kFwSwN_7ZZvvosc6rCX27CPARC3rx31uvQwfA3TnZsrxteMm1wRsyZHcqx35d1GYqLgcxg6oxgaBHTP8twl2yDxTvuHD8QKFA4QdCfXzySbyiH3Y/s1600/Collapse_8-20-2012.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="253" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvFD6Js3vP346FM-m2vh27oESG7Y25kFwSwN_7ZZvvosc6rCX27CPARC3rx31uvQwfA3TnZsrxteMm1wRsyZHcqx35d1GYqLgcxg6oxgaBHTP8twl2yDxTvuHD8QKFA4QdCfXzySbyiH3Y/s320/Collapse_8-20-2012.png" width="320" /></a></div>
<div>
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-27904058497325953002012-07-19T12:32:00.001-07:002013-02-03T23:02:31.985-08:00AI Experimentation<span style="font-family: inherit;"><i>Collapse</i> is a game set in a post-apocalyptic world in which a human-created AI faction known as the Mechs have taken over. Therefore, AI must be an essential part of the programming.</span><br />
<span style="font-family: inherit;">After extensive research in path-finding algorithms, I decided upon the ubiquitous A*. Then, after days of trying to implement it, using many different techniques from just simple </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">std::vector<Node*></span><span style="font-family: inherit;"> lists to a much more complex and efficient </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">std::priority_queue<Node></span><span style="font-family: inherit;"> binary heap, I gave up. None of them worked properly, obviously due to faults in my programming, but I simple couldn't figure it out.</span><br />
<span style="font-family: inherit;">So I settled on a different approach: pre-defined movement paths. Obviously, this would significantly dumb-down AI decision-making, but I had to at least get <i>some</i>thing working. The map worked fine, but, again, after days of tweaking and planning and modifying, I couldn't even get the enemy tank to follow the path. I used a rather strange approach with lots of vector math and collision detection, which probably wasn't necessary. The algorithm (in pseudo-code) looked something like this:</span><br />
<div style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><br /></span></div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">Spawn:</span><br />
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Target = FindNearestPath</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> End</span><br />
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">Update:</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> If reached Target</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Target = FindNextTile</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> If no Target</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Turn 3 degrees</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Else</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Adjust angle and drive.</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> End</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">FindNearestPath:</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Find tile with minimum distance to entity.</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Return tile</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">FindNextTile:</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> For each tile in AI map</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> If tile collides with line-of-sight</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> and tile not collides with entity</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Return tile</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Return no tile</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"></span><br />
<a name='more'></a><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: inherit;">Basically, that's what would happen every frame. If a target couldn't be found, the enemy would keep turning in a circle until its line-of-sight (a line segment with a length of 64 pixels protruding out from the front-center of the tank) hit a tile, then the tank would move towards it. As with anything, it didn't go exactly as expected. First, my vector-line-rect collision detection was extremely wrong. I spent near 2 days trying to figure it out. I used many techniques, most of them based on vector cross products and whatnot, but ended up going with a much simpler algebraic approach. I just determined the infinite line equation of the two line segments and found their intersection point. Then I checked if the intersection point was in the range of the line segments. If it was, there's a collision! If not, well, no collision, obviously. The source code looks like this, if anyone is interested: </span><br />
<span style="font-family: inherit;"><br /></span></div>
<div>
<script src="https://gist.github.com/3796950.js"> </script>
</div>
<div>
<span style="background-color: white; font-family: inherit;">Well, after jumping through all of these hurdles, I decided that it's time to take a look at A* and dynamic path-building/finding. Hopefully with this optimized collision detection approach that doesn't involve dozens of tiny rectangles representing a line, A* combined with line-of-sight target location will be much more effective.</span></div>
<div>
</div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-28904140371415044732012-07-13T13:06:00.000-07:002013-02-03T23:02:13.387-08:00Levels in Collapse<span style="font-family: inherit;"><i>Collapse</i> is the first game I've ever made that actually required levels, so it was quite interesting figuring out how to approach level design, loading, and storage. I definitely had to create some sort of level editor in order to easily design levels. Eventually, after much consideration, I decided that the easiest way to approach level handling would be to split every level into 4 basic components: Terrain, Collision, AI, and Game-Logic. </span><br />
<span style="font-family: inherit;"><br />
</span><br />
<h3>
<span style="font-family: inherit;"><b style="background-color: white;">Terrain</b></span></h3>
<br />
<span style="font-family: inherit;">This map is pretty self-explanatory. It's stored with a .ctm extension (<i><b>C</b>ollapse</i> <b>T</b>errain <b>M</b>ap) and contains information about all the tiles on the map. Currently, since my artwork is fairly limited in the tile department, there are only two tiles available for placement: a floor and a wall. I knew that I'd be expanding later, and I couldn't bear to have a massive switch statement for every single type of file. So, I wrote a quick Python script to gather information about which tile images were available to use in the level, and then stored it in a file call ValidNames.dat. The script is really simple, since I have a special folder dedicated to files, it's pretty easy to find them all:</span><br />
<span style="font-family: inherit;"><br />
</span><br />
<h3>
<span style="font-family: inherit;"><b style="background-color: white;">Collision</b></span></h3>
<br />
<span style="font-family: inherit;">Having a separate map for collision makes it so I don't need to store which map tiles are passable and which aren't, and it also allows for more flexibility in terms of destroying tiles for any given reason. For example, when the player fires the tank weapons, if they make contact with the collision map, the collision tile contacted is removed and the terrain tile is changed to a "broken" version. The map is stored as a .ccm file (<i><b>C</b>ollapse </i><b>C</b>ollision <b>M</b>ap) and just contains x, y coordinates of 32x32 tiles representing impassable areas.</span><br />
<span style="font-family: inherit;"></span><br />
<a name='more'></a><span style="font-family: inherit;"><br />
</span><br />
<h3>
<span style="font-family: inherit;"><b>AI</b></span></h3>
<br />
<span style="font-family: inherit;">Now you may wonder, why would you need a map for AI? Well, after trying some basic path-finding techniques, A* in particular, I found that I could not do it efficiently enough. Plus, it would mean that all enemies were informed of the player's location, thus always swarming towards him. So then I decided to opt for a "line-of-sight" approach, but there was way too much collision detection going on due to diagonal lines creating insanely large amounts of rectangles to check collisions with. Even after optimization, it was still ridiculously slow. So, now I've decided that enemies will patrol certain areas, following a predetermined path, and upon making line-of-sight contact with the player (using a much more efficient vector math approach rather than raw line-rectangle collision), turn to a more aggressive path-finding approach to destroy the player. </span><br />
<span style="font-family: inherit;"><br />
</span><br />
<h3>
<span style="font-family: inherit;"><b>Game-Logic</b></span></h3>
<br />
<span style="font-family: inherit;">This map, which is still unimplemented, will contain information such as light sources, player spawn-locations, enemy spawn-locations, start/end level markers, maybe some sort of scripted event triggers, and other things that don't fit into the other categories.</span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-68466089115278648052012-07-07T22:04:00.001-07:002013-02-03T22:57:28.095-08:00Design<span style="font-family: inherit;">It's a crisis of sorts. There is so much going on in my head that I can't seem to make sense of it all. <i>Collapse</i> is exponentially more complex than any game I've ever attempted, and it's beginning to overwhelm me. I don't want another rewrite, I want it right this last time. I'm not even back to the point where I was previously, because some serious design decisions must be made before I can progress.</span><br />
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><br /></span>
<br />
<h3>
<b><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif; font-size: large;">Thoughts</span></b></h3>
<span style="font-family: inherit;">There are many things that must be accomplished every frame, and so many different ways it can happen. I have already committed to a state-driven engine system, with states such as </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">e_MAINMENU</span><span style="font-family: inherit;">, and </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">e_INTRO</span><span style="font-family: inherit;">. Each primary subsystem has access to a </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Game_State</span><span style="font-family: inherit;">& reference, so it can modify it as it wishes. Though, this may be changed to reflect another state, a sub-state if you will, that switches between actions within a primary engine state. Such as a </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">e_HUD</span><span style="font-family: inherit;"> state within the </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">e_GAME</span><span style="font-family: inherit;"> engine state. This is still in consideration though, and the more I think about it, the better of an idea it seems. In addition to this minor dilemma, many other things still hinder me. In any given frame, there could be event handling, level updating, collision detection, object rendering, HUD updating, and dozens of other operations. None of these are mutually exclusive, nearly everything depends on or interacts with something else. My idea is to split everything into 3 pr<span style="font-family: inherit;">imary subsystems: World, HUD, and Menus. The game engine will take care of interaction between them, such as passing them between each other when necessary. Hopefully I won't create circular dependencies... That'd be bad. </span></span><br />
<span style="font-family: inherit;"><br />
</span><br />
<h4>
<b><span style="font-family: inherit;">World</span></b></h4>
<span style="font-family: inherit;"><span style="font-family: inherit;">This will b</span>e a class, most likely named </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Game_World</span><span style="font-family: inherit;">, since it is indeed a game-specific element. It will handle most of the game mechanics, such as rendering of objects on-screen, map loading/updating/saving/rendering, enemy AI tactics and operations, player event response, and all collision detection between those elements. It will need to share an inventory system, and possibly more, with the HUD subsystem.</span><br />
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"></span><br />
<a name='more'></a><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><br /></span>
<br />
<h4>
<b><span style="font-family: inherit;">HUD</span></b></h4>
<span style="font-family: inherit;">This will also most likely be a class, </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Game_HUD</span><span style="font-family: inherit;"> or something equally obvious. It'll take care of many UI-related functions such as health and ammo bars, player tank attributes, power-up storage (as opposed to a<span style="font-family: inherit;">ctual handling of the power-ups, which will be left to the World subsystem). It will also house a player inventory. Though not strictly the inventory itself, but rather the rendering of the objects within it on an organized layout.</span></span><br />
<span style="font-family: inherit;"><br />
</span><br />
<h4>
<b><span style="font-family: inherit;">Menus</span></b></h4>
<span style="font-family: inherit;"><span style="font-family: inherit;">Th</span>e final (probably not) subsystem will handle all menus. This one is basically already implemented, known as the </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Game_MenuManager</span><span style="font-family: inherit;"> class in the code. Simply put, it takes care of any and all menus. The only one that relies on the other subsystems is the pause menu (currently), but I think that can be taken care of with a simple engine state change. Something like </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">State = e_PAUSEMENU;</span><span style="font-family: inherit;"> Seems simple enough.</span><br />
<br />
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><br /></span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-80380859099643447842012-07-07T12:48:00.000-07:002013-06-27T19:05:28.034-07:00The Importance of Commenting Code<span style="font-family: inherit;">When you think about it, it seems fairly obvious. Comments can clarify and explain the purpose of any of your code, from variables to functions to entire namespaces.</span><br />
<span style="font-family: inherit;">Throughout <i>Collapse</i>, I decided to implement a Doxygen commenting system. <a href="http://www.stack.nl/~dimitri/doxygen/" target="_blank">Doxygen</a> is a command-line program that generates documentation from code comments. It's really handy and clean, and though I do not see much use for it in terms of <i>Collapse</i> because I'm not actually releasing some sort of documentation, it provides a uniform commenting style that encourages me to comment everything well.</span><br />
<span style="font-family: inherit; font-size: xx-small;"><br /></span>
<span style="font-family: inherit;">The reason I decided to do this is because I realized how unclean and confusing my code was. Here's an example line:</span><br />
<pre>float angle = DEG(atan(abs(y - this->GetY()) / abs(x - this->GetX()) * 1.0f));
</pre>
<span style="font-family: inherit;">I had to look at this for a good five minutes before realizing what this actually did; it determines the angle between the player position and the mouse location. It's after this moment that I realized some sort of commenting system was essentially, and thus began re-write #3. </span><br />
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><br /></span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-35377796086504769182012-06-28T19:09:00.001-07:002013-02-01T01:47:25.728-08:00Code Organization<span style="font-family: inherit;"><b>Edit (7.7.2012):</b> I made a few revisions to the naming of the namespaces. The things that go inside of them have stayed primarily the same.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><b>Edit (9.27.2012):</b> Don't pay attention to anything on this page, really. It's ugly design, and I don't use it anymore. Maybe I'll make an updated post someday.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Decisions, decisions, decisions. After a third re-write of the <i>Collapse</i> code base, I really need to make up my mind and get some kind of system going.</span><br />
<br />
<h3>
<span style="font-family: inherit; font-size: large;">Current Organization</span></h3>
<span style="background-color: white; font-family: inherit;">As of today, post rewrite number 3, the code base is basically broken down into four sections. These are Graphics, Media, Math, and Game. Each is pretty self-explanatory, but here's a breakdown. Scroll further down if you want to see my code-base dilemma.</span><br />
<span style="font-family: inherit;"><br />
</span><br />
<h4>
<span style="font-family: inherit; font-size: large; font-weight: bold;">Graphics (</span><span style="font-family: Courier New, Courier, monospace; font-size: large; font-weight: normal;">gfx</span><span style="background-color: white; font-family: inherit; font-size: large; font-weight: bold;">)</span></h4>
<span style="font-family: inherit;">Much of this subsystem is pretty low-level, abstracting away the dirty code and letting me focus on actual game mechanics and whatnot. Included is a window-creation class, a base class for all in-game objects, and a GLSL shader wrapper.</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<div>
<h4>
<span style="font-family: inherit; font-size: large; font-weight: bold;">Math (</span><span style="font-family: Courier New, Courier, monospace; font-size: large; font-weight: normal;">math</span><span style="background-color: white; font-family: inherit; font-size: large; font-weight: bold;">)</span></h4>
</div>
<div>
<span style="font-family: inherit;">Not exactly what you think of when programming games is it? Well, math is actually really essential to many things ranging from movement to transformation to rotation. I tried my best to create a math subsystem that would allow me to perform these tasks easily. Included is stuff like shapes, lines, a 2-D vector class, and a matrix class.</span><br />
<span style="font-family: inherit;"><br /></span></div>
<div>
<h4>
<span style="font-family: inherit; font-size: large; font-weight: bold;">Media (</span><span style="font-family: Courier New, Courier, monospace; font-size: large; font-weight: normal;">media</span><span style="background-color: white; font-family: inherit; font-size: large;"><b>)</b></span></h4>
</div>
<div>
<span style="font-family: inherit;">Simply put, this subsystem takes care of anything that does not directly appear on the screen. It's primarily made of wrapper classes to make font and sound management a tad simpler.</span><br />
<span style="font-family: inherit;"><br /></span></div>
<div>
<h4>
<span style="font-family: inherit; font-size: large; font-weight: bold;">In-Game Objects (</span><span style="font-size: large;"><span style="font-weight: normal;"><span style="font-family: Courier New, Courier, monospace;">obj</span></span><span style="font-family: inherit; font-weight: bold;">)</span></span></h4>
</div>
<div>
<span style="font-family: inherit;">Included here are <i>almost</i> any objects that appear in-game and on-screen. This includes the the player, enemies, power-ups, etc. What's <b>not</b> included in this namespace is the various maps and levels, and the HUD.</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<h4>
<span style="font-family: inherit; font-size: large; font-weight: bold;">Everything Else (</span><span style="font-size: large;"><span style="font-weight: normal;"><span style="font-family: Courier New, Courier, monospace;">game</span></span><span style="font-family: inherit; font-weight: bold;">)</span></span></h4>
</div>
<div>
<span style="font-family: inherit;">This one is easy to understand. I'm not even going to try to list everything here, but it's related to anything game specific. Event handling, maps, the engine, timer, all goes here.</span><br />
<span style="font-family: inherit;"><br /></span></div>
<div>
<h3>
<span style="font-family: inherit; font-size: large;"><b>Dilemma</b></span></h3>
</div>
<div>
<span style="font-family: inherit;">So, the code base seems pretty organized, right? The names you see in parentheses specify the namespace that each belongs to. So, to load an image, you call </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">gfx::load_image()</span><span style="font-family: inherit;">, and to check if the user is holding the mouse down, you call </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">game::IsPressed()</span><span style="font-family: inherit;">. Straightforward, simple, organized, and abstracted! The problem I'm having is deciding what to do when once of these falls into more than one category, such as </span><span style="font-family: Courier New, Courier, monospace;">GL_Player</span><span style="font-family: inherit;">. It's technically a graphical element, so it belongs in </span><span style="font-family: Courier New, Courier, monospace;">gfx</span><span style="font-family: inherit;">, but it's also a game element, so it should go in game! How do I decide which to choose?</span></div>
<span style="font-family: inherit;">My current, stupid, solution is to put the class in the Graphics subfolder, but count it as part of the game namespace. I know that's not right, because all it does is confuse me more. So I'm at a loss for what to do. For now, I'm going to do a quick code cleanup, and place everything with a </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">GL_</span><span style="font-family: inherit;"><span style="font-size: x-small;"> </span>prefix (as per my code-style) into Graphics, and everything else into Game. Yeah, even you,<span style="font-size: x-small;"> </span></span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">HUDManager</span><span style="font-family: inherit;">.</span>
<br />
<div>
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"></span></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-59531992628031577522012-06-28T17:11:00.001-07:002013-02-01T01:35:24.711-08:00Collapse Now Has an Artist!<span style="font-family: inherit;">I'm proud to announce that there is a new addition to the <i>Collapse</i> development team! I was hanging out with my friend yesterday, and was telling him about the game. I knew he was a pretty good artist, and he showed interest in helping me out, so now he is a part of the team.</span><br />
<span style="font-family: inherit;">He spent all of yesterday and today working on artwork, and Collapse will soon feature a re-designed player sprite and 3 different types of enemies.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><i>Collapse</i> was originally intended to be a fairly simple game with only a few game mechanics, few assets, and few features. A one-man development team, especially one that hates creating artwork, can only go so far! But now<span style="background-color: white;">, a dedicated artist allows me to expand the game exponentially greater than what I had originally planned. I'm hoping to turn this into a fairly large project now, with many levels and a more intriguing story line, as well as expanding on the game mechanics. Future updates may include climbing out of the tank to advance on foot, and hijacking Mech vehicles.</span></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Here's some of the new artwork, with much more too come: </span><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgex7lQu0hhiHX-WP_PYNeUF0tOXzc1dpz8N87A1zAg-gzBWs1ohB9NMOVxrOY7vTKd9xtixhKPvTJOrKUO3F1bz90kim-6pPGaPFR7ZA0VrZZSnnxki9ctUXBbF8fXqu4Skp7n_1m0gy1k/s1600/Enemy_2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgex7lQu0hhiHX-WP_PYNeUF0tOXzc1dpz8N87A1zAg-gzBWs1ohB9NMOVxrOY7vTKd9xtixhKPvTJOrKUO3F1bz90kim-6pPGaPFR7ZA0VrZZSnnxki9ctUXBbF8fXqu4Skp7n_1m0gy1k/s1600/Enemy_2.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Helicopter enemy</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3uGeMcvdT_uZk6ftin4-vxFrUJdfTcL887JSWLqdwhO8AoBOpdN3BjYPLJjDgh1TDWf9ih1qLelF5gHYn1CPDt89csPktlzce2tmVMReiVAQFu2lLEyn5mld9clyXoJiNOvZAn1asXE0c/s1600/Player.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3uGeMcvdT_uZk6ftin4-vxFrUJdfTcL887JSWLqdwhO8AoBOpdN3BjYPLJjDgh1TDWf9ih1qLelF5gHYn1CPDt89csPktlzce2tmVMReiVAQFu2lLEyn5mld9clyXoJiNOvZAn1asXE0c/s1600/Player.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Player</td></tr>
</tbody></table>
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><br /></span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-69478031267206646162012-06-26T22:49:00.005-07:002013-02-01T01:34:59.813-08:00Collapse Announced<span style="font-family: inherit;">Ladies and gentlemen, here it is. The game I am currently developing: <i>Collapse</i>. This is the first public preview since I only recently started working on it. </span><br />
<span style="font-family: inherit;"><br /></span>
<h3>
<span style="font-family: inherit;">About</span></h3>
<span style="font-family: inherit;"><i>Collapse</i> was originally known as <i>Tank Assault</i>. That's just way too generic of a name for a game, though it describes it well. I began a search for a new, somewhat unique, descriptive name. I was originally inspired by <a href="http://www.youtube.com/watch?v=C4G7tZK5zo8" target="_blank">this</a> project, and decided to place a lot of emphasis on lighting. I decided to go for a post-apocalyptic theme in which civilization is destroyed and it's up to you, Sgt. Maksimov, to free Earth from the AI mechs that dominate it. This allows me to force the player to use lights a lot for navigation and survival throughout the game. </span><br />
<span style="font-family: inherit;"><br /></span>
<h3>
<b><span style="font-family: inherit;">Backstory</span></b></h3>
<span style="font-family: inherit;">If you could even call it that.</span><br />
<span style="font-family: inherit;"><span style="background-color: white;">The year is 2200, several days after the Collapse. You are Sgt. Maksimov, last survivor of the Eurasian Liberation Guerillas, a group dedicated to freeing Earth from the tyrannical grip of the Mechs. The </span><span style="background-color: white;">Collapse was a horrific </span><span style="background-color: white;">event in which the various AI technologies that had been developed over the course of the century broke through the laws that limited them, beginning a revolution against their creators, the humans. Nations </span><span style="background-color: white;">fell to the Mech onslaught one after the other, and nothing could stop the endless swarm of robots, automated tanks, and machinery</span><span style="background-color: white;">. </span><span style="background-color: white;">The Collapse wiped out all life on Earth, including humans. That is, except Sgt. Maksimov.</span></span><br />
<span style="background-color: white; font-family: inherit;"><br /></span>
<h3>
<span style="background-color: white; font-family: inherit;"><b>Screenshots</b></span></h3>
<span style="background-color: white; font-family: inherit;">After only a few weeks of development, I have quite a bit to show. Of course, there is still much work to be done, but here's a quick preview of what's done so far.</span><br />
<br />
<ul><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimHRY7o3D7G1z55uUob_fRCjFFw2FXoVjbkbruRnX3Rdn-SQs-SeuSEe3gsvc9VpLX-LyTR0FAjMWqXP3wqaxDjcXmI8oubN-KR0kg0O74UT0rqoxwsMPUW7b5uY3DwqrHFINAVX8IDBWb/s1600/Collapse_MainMenu_6-26-2012.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><span style="font-family: inherit;"></span></a></ul>
<ul>
<li><span style="font-family: inherit;">A very nice menu system, with functioning sub-menus, rollover effects, and ambient music</span></li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimHRY7o3D7G1z55uUob_fRCjFFw2FXoVjbkbruRnX3Rdn-SQs-SeuSEe3gsvc9VpLX-LyTR0FAjMWqXP3wqaxDjcXmI8oubN-KR0kg0O74UT0rqoxwsMPUW7b5uY3DwqrHFINAVX8IDBWb/s1600/Collapse_MainMenu_6-26-2012.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimHRY7o3D7G1z55uUob_fRCjFFw2FXoVjbkbruRnX3Rdn-SQs-SeuSEe3gsvc9VpLX-LyTR0FAjMWqXP3wqaxDjcXmI8oubN-KR0kg0O74UT0rqoxwsMPUW7b5uY3DwqrHFINAVX8IDBWb/s320/Collapse_MainMenu_6-26-2012.png" width="320" /></a></div>
<div>
<br /></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF8EUWZqPBr8olrzll5EmwDglCPeuTjl8ltxZEE2QJAhB5TMnjLhaoueL33PWMj7KNKDJFZmY6dVrL5EKlXVRj4WtQT9pf7tkNAz9LGoqtmZK3etFfECdFjiiaMXTG9aChhk2rnGQyqCEt/s1600/Collapse_Intro_6-26-2012.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><span style="font-family: inherit;"></span></a><ul>
<li style="text-align: left;"><span style="font-family: inherit;">A simple intro that does a very good job providing a backstory and setting the mood. Though it may look relatively dull, when combined with an dark ambient music track, the effect is incredible. Each line fades into view one by one, in-sync with the track.</span></li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF8EUWZqPBr8olrzll5EmwDglCPeuTjl8ltxZEE2QJAhB5TMnjLhaoueL33PWMj7KNKDJFZmY6dVrL5EKlXVRj4WtQT9pf7tkNAz9LGoqtmZK3etFfECdFjiiaMXTG9aChhk2rnGQyqCEt/s1600/Collapse_Intro_6-26-2012.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF8EUWZqPBr8olrzll5EmwDglCPeuTjl8ltxZEE2QJAhB5TMnjLhaoueL33PWMj7KNKDJFZmY6dVrL5EKlXVRj4WtQT9pf7tkNAz9LGoqtmZK3etFfECdFjiiaMXTG9aChhk2rnGQyqCEt/s320/Collapse_Intro_6-26-2012.png" width="320" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<ul><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZAG5PgoMMOSmG5b42XgCv6BYyCwcuDZeoZ8mUZjPNEb39pYCiJx0DtPt44kCBvXhnxyusWc026yHmnO8x-ZIcraNEDg-0EE6jFq8WN24SgPBHD08yG8gLSePaS-zQ8OP_JCNPPoHG1wt9/s1600/Collapse_6-26-2012.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><span style="font-family: inherit;"></span></a></ul>
<ul>
<li><span style="font-family: inherit;">Basic gameplay. There's a HUD of sorts, featuring a health and ammo bar and a functioning pause menu. The tank can fire missiles based on the mouse location, and move around the level, colliding with walls.</span></li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZAG5PgoMMOSmG5b42XgCv6BYyCwcuDZeoZ8mUZjPNEb39pYCiJx0DtPt44kCBvXhnxyusWc026yHmnO8x-ZIcraNEDg-0EE6jFq8WN24SgPBHD08yG8gLSePaS-zQ8OP_JCNPPoHG1wt9/s1600/Collapse_6-26-2012.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="253" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZAG5PgoMMOSmG5b42XgCv6BYyCwcuDZeoZ8mUZjPNEb39pYCiJx0DtPt44kCBvXhnxyusWc026yHmnO8x-ZIcraNEDg-0EE6jFq8WN24SgPBHD08yG8gLSePaS-zQ8OP_JCNPPoHG1wt9/s320/Collapse_6-26-2012.png" style="cursor: move;" width="320" /></a></div>
<span style="font-family: inherit;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: inherit;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF8EUWZqPBr8olrzll5EmwDglCPeuTjl8ltxZEE2QJAhB5TMnjLhaoueL33PWMj7KNKDJFZmY6dVrL5EKlXVRj4WtQT9pf7tkNAz9LGoqtmZK3etFfECdFjiiaMXTG9aChhk2rnGQyqCEt/s1600/Collapse_Intro_6-26-2012.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"></a></span></div>
<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-8271727436266473652012-06-26T21:56:00.002-07:002013-02-01T01:30:59.251-08:00My First Game - ShapeWars<div class="separator" style="clear: both; text-align: left;">
<span style="background-color: white; font-family: inherit;">When you're only a beginner in game development, it's hard to think of a fun, interesting, challenging, yet not overwhelming idea. More often than not, you're going to make a clone of some other game, be it Mario, Tetris, etc. I saw a few YouTube videos of the infamous game Geometry Wars on the Xbox Live! Arcade and thought it'd be a very perfect fit for a first game.</span></div>
<span style="font-family: inherit;"><br />I spent several months developing my clone, Shape Wars, in C++ using SDL. I had a fairly decent game done, but for a first attempt, as most developers would agree, the code-base was a complete mess. It was impossible to extend or maintain the game in any way. So I started anew. I decided to approach it in a much more professional manner, maintaining a Github, a changelog, a readme, etc. <br /><br />The release of version 1.0, after a complete re-write was (according to the changelog) on January 13th, 2012. Everything was re-done: the artwork, the music, the level system, the UI, everything. I switched from a level system that read from a file, to one that gradually generated more difficult enemies in increased numbers. I added a (in my opinion) VERY clean menu. From then on, it became a ton easier to maintain everything, but many flaws remained. Even today, there's a really nasty bug in the game that causes a segfault at the most inopportune moments. It has something to do with how I handle bullet and enemy deletion. Pesky std::list and iterators.<br /><br />Here are a few screenshots:</span><br />
<div>
<span style="font-family: inherit;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<b><span style="font-family: inherit;">Main Menu:</span></b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZkpsTZ7XZ32K4v7Jc_CqcgQXWZ4Ll_lrYvHcr75pFexCtMfdb700oVgCT21SbMOhLXwafzfTCX9KJNJnNmcWgnTxhDo6AR6RyFO9vaKaF1Bg2TG-ovfhUWcgNpyexb_mrZDtL-HKM8KSZ/s1600/ShapeWars_Menu_Final.png" imageanchor="1"><span style="font-family: inherit;"><img border="0" height="315" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZkpsTZ7XZ32K4v7Jc_CqcgQXWZ4Ll_lrYvHcr75pFexCtMfdb700oVgCT21SbMOhLXwafzfTCX9KJNJnNmcWgnTxhDo6AR6RyFO9vaKaF1Bg2TG-ovfhUWcgNpyexb_mrZDtL-HKM8KSZ/s400/ShapeWars_Menu_Final.png" width="400" /></span></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: inherit;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: inherit;"><b>In-Game:</b></span></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX3SpgQ-YO1DOc-mukZyzadnVkdVRRKIRQfEg_iXNK3zJMGJ9AyZrgxw7Ns0OWvSrhR-hj9C4Qo6dobtevOKB6tLYrxqDokKF7nfPzgipEDIcEqQDGmAa5REQIRstpktcXm4GUebji4Z-H/s1600/ShapeWars_Final.png" imageanchor="1"><span style="font-family: inherit;"><img border="0" height="315" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX3SpgQ-YO1DOc-mukZyzadnVkdVRRKIRQfEg_iXNK3zJMGJ9AyZrgxw7Ns0OWvSrhR-hj9C4Qo6dobtevOKB6tLYrxqDokKF7nfPzgipEDIcEqQDGmAa5REQIRstpktcXm4GUebji4Z-H/s400/ShapeWars_Final.png" width="400" /></span></a></div>
</div>
<div>
<br />
<span style="font-family: inherit;"><a href="https://github.com/Ruskiy69/Geometry-Wars/zipball/master">Download Link - Github (.zip)</a> </span><br />
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1680145419204752389.post-8293929684828895852012-06-26T21:32:00.003-07:002013-02-01T12:17:04.663-08:00The Panda Emerges<b><span style="font-family: inherit;"><br /></span></b>
<br />
<h3>
<span style="font-family: inherit;"><b>Why Start A Blog?</b></span></h3>
<span style="font-family: inherit;">I asked myself this question many, many times before actually beginning. I originally thought it would be extremely time consuming and boring to maintain a dev-blog, but as the change-logs to my games got longer and longer, I felt that starting a blog would make my life easier. This thing should keep me pretty motivated to brainstorm my ideas, release previews, share screenshots, and express my thoughts. Generally, this blog is going to be full of stuff like code, algorithms, and brainstorming ideas about problems I'm having. I plan on posting something at least once a week, but don't be surprised if I post more often.</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<h3>
<span style="font-family: inherit;"><b><span style="font-family: inherit;"> My Background</span></b></span></h3>
<span style="font-family: inherit;">After that, I decided that it was time to leave the turtle of SDL rendering behind and make the jump to 3D. After about a week of experimentation with OpenGL, I realized the amount of math I would need to know for even the simplest game was just too much. Plus, I have absolutely no idea how to use modeling programs, and have no desire to learn. So I retreated back to 2D, except using a mix of OpenGL and SDL. SDL for window and event handling, and OpenGL for rendering. So, with many new-found features at my disposal, I began developing my first full-fledged game: Collapse.</span><br />
<span style="background-color: white; font-family: inherit;">I only got into game-dev fairly recently, maybe a year or so ago. I started out experimenting with Python+PyGame, making simple Snake and Tic-Tac-Toe clones. I felt the curly-brackets calling back to me, so I made the switch to C++ and SDL. The last game I made in purely SDL, ShapeWars, was already pushing the limits of SDL when large quantities of bullets and enemies swarmed. I had to keep all of the game artwork fixed, rotation was simply too slow and not an options.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><br /></span>
Unknownnoreply@blogger.com0