Blueprints. Completely restructured articles section. Y'know, nothin' big. Yawn.
This commit is contained in:
parent
4b3e5d24e9
commit
7d63ddcb48
27
articles/__init__.py
Normal file
27
articles/__init__.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import os
|
||||||
|
from flask import Blueprint, render_template, abort
|
||||||
|
from jinja2.exceptions import TemplatesNotFound
|
||||||
|
|
||||||
|
folder = "articles"
|
||||||
|
bloop = Blueprint("articles", __name__, template_folder="")
|
||||||
|
|
||||||
|
@bloop.route("/")
|
||||||
|
def main_page():
|
||||||
|
return render_template("project_list.html")
|
||||||
|
|
||||||
|
@bloop.route("/<page_name>/")
|
||||||
|
def render_article(page_name):
|
||||||
|
# Arguably, the various options for how to render (templates, articles, flat html) could be stuck into various subdirectories.
|
||||||
|
# Ultimately I don't want to do this because it's supposed to be lightweight - I should be able to chuck this __init__.py file into
|
||||||
|
# any folder and start generating stuff correctly. But whatever!
|
||||||
|
|
||||||
|
# Let's find some test filenames!
|
||||||
|
file_name = os.path.join(folder, page_name.replace("-", "_"))
|
||||||
|
|
||||||
|
# Is there a template by that name? This list is in the priority order for rendering.
|
||||||
|
extensions = [".template.html", ".article.html", ".html", ""]
|
||||||
|
|
||||||
|
try:
|
||||||
|
return render_template([ file_name + suffix for suffix in extensions ])
|
||||||
|
except TemplatesNotFound as e:
|
||||||
|
abort(404)
|
16
articles/article.template.html
Normal file
16
articles/article.template.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
{% block head %}
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>How should this website be laid out?</title>
|
||||||
|
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||||
|
<link href="/static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||||
|
<link href="/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% block body -%}
|
||||||
|
{%- endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
293
articles/auriga.article.html
Normal file
293
articles/auriga.article.html
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
<style type="text/css">
|
||||||
|
#server-choices colgroup { width: 20%; }
|
||||||
|
#server-choices tr { height: 3em; }
|
||||||
|
#server-choices tr>td { text-align: center; }
|
||||||
|
#server-choices tr>td:first-child {
|
||||||
|
text-align: left;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<article>
|
||||||
|
<h1>Shit, I better make this server work.</h1>
|
||||||
|
<h3>On the layout of folders and files!</h3>
|
||||||
|
<p>Basically I'm not sure how I should lay out this website. The current organization looks something like this:</p>
|
||||||
|
<ul class="file-tree">
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">server/</span> (server root)
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">pages/</span> (articles with nice links)
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span> (accessed as <span class="url">http://example.com/auriga/</span>)</li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">language_for_games.html</span> (<span class="url">http://example.com/language-for-games/</span>)</li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span> (<span class="url">http://example.com/tamari/</span>)
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">static/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-eye-open"></i> <span class="filename">stylesheet.css</span> (global stying)</li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">favicon.ico</span></li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">banner.png</span></li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">tamari/</span> (files for an article)
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">figure_1.png</span></li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">figure_2.png</span></li>
|
||||||
|
<li><i class="icon-signal"></i> <span class="filename">experiment_data.csv</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>This has a number of problems. First and foremost, barely any thought has gone into naming of folders and files - which is because not much thought has gone into their placement and hierarchy.</p>
|
||||||
|
<p>The server is written using <a href="http://flask.pocoo.org">Flask</a>, and this is the rundown on how it works when a user goes to <span class="url">http://example.com/some-path/</span>:</p>
|
||||||
|
<ol>
|
||||||
|
<li>If the path requested is the root of the website, render <span class="filename">main_page.html</span>.</li>
|
||||||
|
<li>If the path requested begins with <span class="url">static/</span>, render a file from the static content directory.</li>
|
||||||
|
<li>Else, convert the path (<span class="url">some-path</span>) into the filename (<span class="filename">pages/some_path.html</span>) assuming it's an article. If it exists, render it.</li>
|
||||||
|
<li>If there's no article by that name, display the miscellaneous articles page. Or 404. The current behavior isn't very high on my priorities.</li>
|
||||||
|
</ol>
|
||||||
|
<p>There are a bunch of problems with this system - it's kind of brittle, file paths have the meaningless-to-the-user <span class="url">static/</span> at the beginning, and it means that when I include a resource in <span class="url">http://example.com/tamari/</span> (the file <span class="filename">pages/tamari.html</span>) I have to use a path like <span class="url">../static/tamari/figure_1.png</span> - when I should be able to reference files related to the Tamari article by a closely-related URL: <span class="url">./figure_1.png</span>.</p>
|
||||||
|
<p>All this points to the idea of having my articles be in folders, so it would look something like this:</p>
|
||||||
|
<ul class="file-tree">
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">server/</span> (server root)
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">articles/</span> (articles with nice links)
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">auriga/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">language-for-games/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">language_for_games.html</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">tamari/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span></li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">figure_1.png</span></li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">figure_2.png</span></li>
|
||||||
|
<li><i class="icon-signal"></i> <span class="filename">experiment_data.csv</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">static/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-eye-open"></i> <span class="filename">stylesheet.css</span> (global stying)</li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">favicon.ico</span></li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">banner.png</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>And hell, at this point having the filenames match the folders (<span class="filename">auriga/auriga.html</span>) is just a pain, so we could name the main page in each folder <span class="filename">index.html</span>, and suddenly this looks very standard. So why don't I do this?</p>
|
||||||
|
<p>Well... I don't know. But something always bothered me about the <span class="filename">index.html</span> standard. Maybe it's just that my article about Tamari lattices <em>isn't</em> an index, so I don't think it should be called one. That's certainly part of it. Also, some of my articles and pages are going to be very short - in theory I'd like them to be able to be tiny snippets, which could be included on other pages. It'd be annoying to have a subfolder for every single article I write! But... maybe not <em>too</em> annoying. I'll have to think about that.</p>
|
||||||
|
<hr>
|
||||||
|
<h3>But what are we <em>doing</em>?</h3>
|
||||||
|
<p>What would my ideal web framework be? Well, something like Flask, really. I like flask because this is easy:</p>
|
||||||
|
<pre>
|
||||||
|
<code class="language-python">@app.route("<span class="url">/some-convoluted/url/<options>/with-stuff/</span>")
|
||||||
|
def render_shoofle_page(options=None):
|
||||||
|
if options == "bananas":
|
||||||
|
return render_page("<span class="filename">bananas.html</span>")
|
||||||
|
else:
|
||||||
|
return render_page("<span class="filename">some_other_template.html</span>", options=options)</code></pre>
|
||||||
|
<p>And, lo and behold, I can go to <span class="url">example.com/some-convoluted/url/bananas/with-stuff/</span> and see the right generated page! I like having that capacity at my fingertips. In particular, it makes it easy to respond to various other kinds of requests. That's what I really like about Flask - I feel like I can do <em>everything</em> a webserver can do, but it all takes the same very small amount of work. This compares to, say, PHP, where it's easy to make pages... But more complicated behavior, especially anything involving dynamic URL paths, involves jumping through hoops.<span class="sidenote span4">It might seem like an overblown complaint, but the integrity of my mental models is important to me - and in PHP, I don't understand what gets sent to the requestor. If I make a Flask route returning JSON, I know it's exactly what a script wants. With PHP, I would <em>hope</em> that it wouldn't have weird headers or content type or additional markup.</span> Plus, you have to work with PHP, which I would wish on no one.</p>
|
||||||
|
<p>I don't like Flask because I need to specify all the behaviors, and I'm worried that I'll get it wrong (thus, this article).</p>
|
||||||
|
<p>My ideal world solution would be something that lets me pass requests for subpaths to other python modules:<p>
|
||||||
|
<ul class="file-tree">
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">server/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-file"></i> <span class="filename">server.py</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">articles/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-file"></i> <span class="filename">articles.py</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">language-for-games.html</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">games/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-file"></i> <span class="filename">games.py</span></li>
|
||||||
|
<li><i class="icon-signal"></i> <span class="filename">scores.csv</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">play_the_game.html</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">game.js</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>Aaaand how it works would be simple:</p>
|
||||||
|
<ol>
|
||||||
|
<li>A request comes in to <span class="url">http://example.com/tamari/</span>, and it is handled by <span class="filename">server.py</span>.</li>
|
||||||
|
<li><span class="filename">server.py</span> says "Okay, I don't have any specific handlers that do anything with this URL, but I think <span class="filename">articles/articles.py</span> does!" and sends the request to <span class="filename">articles.py</span>.</li>
|
||||||
|
<li><span class="filename">articles.py</span> receives a request for <span class="url">/tamari/</span> and has a rule for handling that, and so it renders the appropriate HTML file.</li>
|
||||||
|
</ol>
|
||||||
|
<p>The basic idea is that requests can be routed to other python modules. If those modules can be reloaded easily (or automatically!), this would mean I could write complicated URL handling in subdirectories of my website - without having to touch any of the code that handles anything else. It means I can modularize - and that's <em>awesome</em>.</p>
|
||||||
|
<ol>
|
||||||
|
<li>An HTTP GET request comes in to <span class="url">http://example.com/games/points</span>, and <span class="filename">server.py</span> takes it.</li>
|
||||||
|
<li><span class="filename">server.py</span> doesn't know what to do with it, but it knows that requests for URLs starting with <span class="url">/games</span> should be handled by <span class="filename">games/games.py</span>.</li>
|
||||||
|
<li><span class="filename">games.py</span> receives an HTTP GET request for <span class="url">/games/points</span>, and so it can respond to this with a JSON object that tells the requestor how many points they got.</li>
|
||||||
|
</ol>
|
||||||
|
<p>This is the main point of the tiered handlers system - that I can write handlers for all kinds of requests, without having to interact with other parts of my website.</p>
|
||||||
|
<p>Basically, I want to combine the simple directory structure of PHP websites with the principles of Flask I really like - separating content from server logic, keeping things simple, and having control.</p>
|
||||||
|
<p>Here's how I imagine this would work:</p>
|
||||||
|
<pre>
|
||||||
|
<code>from flask import Flask, render_template, redirect
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
def main_page(): return render_template("<span class="filename">main.html</span>")
|
||||||
|
app.add_url_rule("<span class="url">/</span>", main_page)
|
||||||
|
|
||||||
|
import games
|
||||||
|
app.add_module_url_rule("<span class="url">/games/<path:rest></span>", games)</code></pre>
|
||||||
|
<p>As usual, don't think too hard about the syntax I just proposed. The point is to distribute URL routing logic throughout multiple files, so that my entire website isn't controlled by one brutalistic overlord <span class="filename">server.py</span> file that decrees the entire path of every request. I want things split up, dammit!</p>
|
||||||
|
<hr>
|
||||||
|
<p>Now I'm reading up on the Flask docs, and it turns out that it already has the capacity for this. Unfortunately, it's complicated and I'm <em>whiiiny</em>.</p>
|
||||||
|
<p>It seems that Flask provides the developer with three options:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Package Organization: Essentially, break up your server code, like configuration and URL route assignment, into separate files. This doesn't actually solve any of my issues - most of what this does (as far as I can tell) is separate the server initialization logic from the routing and response logic. Plus, it makes it easier to use your application in something else. More on this soon.</li>
|
||||||
|
<li>Blueprints: Very close to what I want. I could define a Blueprint object in <span class="filename">articles.py</span>. This Blueprint object would register all the routes and endpoints that I want to register - and then, when the server starts, it gets all of those from the blueprint. This means we can <em>actually</em> factor views out. I'm really not sure, though, what this affords that the organizing your application as a package doesn't.</li>
|
||||||
|
<li>Application Dispatching: The most powerful of the three! This is a slightly lower-level solution, wherein you actually run multiple applications concurrently, and dispatch requests to them. This is kind of overkill, but at least it's nice to know that it's possible - things like the <span class="url">async_app</span> example from previous could really make sense, if the app is large enough in scope. Application dispatching means you can just pull in another application and route things to it on the WSGI layer. Or something.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Okay, but... how do they score up? I have some requirements:</p>
|
||||||
|
<dl>
|
||||||
|
<dt>Organization</dt>
|
||||||
|
<dd>I want to define the behavior for <span class="url">example.com/articles/tamari/</span> in the same place as <span class="url">example.com/articles/language-for-games/</span> is defined, but in a different file from where <span class="url">example.com/games/hunt-the-wumpus</span> is defined.</dd>
|
||||||
|
<dt>Simplicity</dt>
|
||||||
|
<dd>Defining a URL route and endpoint for each subfolder of my application shouldn't be much more complicated than defining behaviors in a flat system. Ideally, registering all the behaviors for the <span class="url">articles/</span> subpath is no more complicated than <code>app.route("<span class="url">/articles/</span>", articles_handler)</code></dd>
|
||||||
|
<dt>Ease of Extension</dt>
|
||||||
|
<dd>I'm writing a family of pages. They're starting to get a little too complicated. It should be really easy to go from that situation to having a nicely-delineated subsection of my website.</dd>
|
||||||
|
<dt>Do I <em>Need</em> to Restart the Server?</dt>
|
||||||
|
<dd>I hate restarting the server. Maybe this is a little thing, but gah! I want the server to detect changes automatically! This shouldn't be that hard. Of course, this is a much thornier topic when it comes to subpages that might store their own state... So it might be out the window unless I want to get my hands <em>way</em> more dirty.</dd>
|
||||||
|
</dl>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row-fluid">
|
||||||
|
<table id="server-choices" class="span8 offset2">
|
||||||
|
<caption><h4>How do they fare up?</h4></caption>
|
||||||
|
<col><colgroup span=4></colgroup>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
|
||||||
|
<th>Organization</th>
|
||||||
|
<th>Simplicity</th>
|
||||||
|
<th>Ease of Extension</th>
|
||||||
|
<th>No Restart Required?</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Current</td>
|
||||||
|
|
||||||
|
<td class="label-warning"><i class="icon-question-sign"></i></td>
|
||||||
|
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||||
|
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||||
|
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Organize as a Package</td>
|
||||||
|
|
||||||
|
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||||
|
<td class="label-warning"><i class="icon-question-sign"></i></td>
|
||||||
|
<td class="label-warning"><i class="icon-question-sign"></i></td>
|
||||||
|
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Blueprints</td>
|
||||||
|
|
||||||
|
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||||
|
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||||
|
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||||
|
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Application Dispatch</td>
|
||||||
|
|
||||||
|
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||||
|
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||||
|
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||||
|
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div></div>
|
||||||
|
<p>In light of this chart, it seems like Blueprints are the clear option. Also, "organize as package" is really vague. What they suggested didn't sound very helpful - but making python packages (finally learning how to use <span class="filename">__init__.py</span> files!) will probably get used in the solution I'm thinking I'll use, which looks something like this:</p>
|
||||||
|
<ul class="file-tree">
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">server/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-file"></i> <span class="filename">server.py</span></li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">articles/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-file"></i> <span class="filename">article_routing_blueprint.py</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">language-for-games.html</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span></li>
|
||||||
|
<li><i class="icon-folder-close"></i> <span class="filename">tamari_files</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">games/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-file"></i> <span class="filename">games_blueprint.py</span></li>
|
||||||
|
<li><i class="icon-signal"></i> <span class="filename">scores.csv</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">play_the_game.html</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">game.js</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">static/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">favicon.ico</span></li>
|
||||||
|
<li><i class="icon-eye-open"></i> <span class="filename">stylesheet.css</span></li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">lol_a_cat.jpg</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>If there's static content that is globally important, with simple routing rules, it can - of course - be stored in the server root's <span class="filename">static/</span> directory. Static file handlers don't take much configuration, so this can go in the root.</p>
|
||||||
|
<p>All the files related to articles are contained in the <span class="filename">articles/</span> directory, or subdirectories. <span class="filename">article_routing_blueprint.py</span> contains a blueprint definition that tells the server how to route calls that result in the rendering of the various articles I've written.</p>
|
||||||
|
<p>All files related to the little javascript games I've made, on the other hand, go in the <span class="filename">games/</span> directory. State for this application is managed by <span class="filename">games_blueprint.py</span>, which is sort of like a very tiny application. I think it's possible to keep track of state, if you remember to keep variables global... This is tricksy, but should be doable - and if it gets larger, it should almost certainly be developed as a separate application entirely. At that point, I should figure out how to include multiple applications in one website!</p>
|
||||||
|
<p>I want to finish this bit by writing down some code for the base <span class="filename">server.py</span> logic:</p>
|
||||||
|
<pre>
|
||||||
|
<code class="language-python">from flask import Flask
|
||||||
|
|
||||||
|
# app configuration and initialization
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.debug = True
|
||||||
|
|
||||||
|
# content in <span class="filename">articles/</span>
|
||||||
|
import articles
|
||||||
|
app.register_blueprint(articles.blueprint)
|
||||||
|
|
||||||
|
# content in <span class="filename">games/</span>
|
||||||
|
import games
|
||||||
|
app.register_blueprint(games.blueprint, url_prefix="<span class="url">/games</span>")</code></pre>
|
||||||
|
<hr>
|
||||||
|
<h3>Okay, one last thing.</h3>
|
||||||
|
<p>This has been a lot about how to get some basic extensible functionality working. <i class="that-guy">But wait</i>, someone cries in the distance! <i class="that-guy">Why are we going to such lengths to do all this in the first place, when you're just serving static HTML files? Isn't this way more work than you need?</i><span class="sidenote span4">In case you're reading this article long after I've finished these changes (I hope so, 'cause I should get to work on this immediately), at this point all the articles were static HTML files. That voice speaks the truth.</span></p>
|
||||||
|
<p>Thanks for asking. The answer is that I want to change how this site is structured, and the articles are the specific thing I want to change. See, as it is, each article has basically the same header at the top, and basically the same footer at the bottom, and... Well, they're just all enclosed in the same stuff, and so when I change the styling of the website - or, horror of horrors, try to add a sidebar across the hwole site - I have to change all of them! And, as I think we've been over before, I'm <em>lazy</em>.</p>
|
||||||
|
<p>Conveniently, as I've been obsessively reading discussions of standards-compliant HTML5 and document formats and such lately, this laziness messes with my indomitable enthusiasm for conceptually pleasing solutions. Here's what I've got:</p>
|
||||||
|
<ul>
|
||||||
|
<li><b>Articles</b> on my site are blocks of text, consisting of my rambling on some topic. Something I've written down. They can have some amount of associated content, but for the most part they're just text. So, I'm going to reduce them down to their bare minimum of unique content - in many cases, just an <code language="html"><article></code> tag containing what I wrote!</li>
|
||||||
|
<li>But sometimes I want to have multiple articles display in one page! Sometimes my articles are single paragraphs. Sometimes they can be grouped into related, uh, groups! What do we do then? The answer is <strong>templates</strong>. Flask uses <a href="http://jinja.pocoo.org/">Jinja2</a>, a perfectly nice templating engine - and why not use it?</li>
|
||||||
|
<li>If I want to display the articles contained in <span class="filename">articles/parkour_is_awesome.html</span>, <span class="filename">articles/exercise.html</span>, and <span class="filename">articles/how_is_body.html</span>), then I just make a new page, a Jinja2 template, which contains this:
|
||||||
|
<pre>
|
||||||
|
<code class="language-jinja2"><!-- {% raw %} -->{% include "<span class="filename">articles/parkour_is_awesome.html</span>" %}
|
||||||
|
{% include "<span class="filename">articles/exercise.html</span>" %}
|
||||||
|
{% include "<span class="filename">articles/how_is_body.html</span>" %}<!-- {% endraw %} --></code></pre>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>And ta-da! We now have a page which has those three articles in a row.</p>
|
||||||
|
<p>This, of course, also means we have a neat format for how to display things in general. Someone requested access to a URL! Find the file it points to. If it's an HTML fragment, then point the <b>general page template</b> to that file, and render. The general page template is just a template that adds the header, footer, sidebar, universal styling, and so on, as required, for universality.</p>
|
||||||
|
<p>So if you go to <span class="url">example.com/tamari/</span>, the server says "Okay, you want to look at the article in the HTML fragment file <span class="filename">articles/tamari.html</span>." It renders the general page template around that article, and returns that to the user.</p>
|
||||||
|
<p>Because I like having the option to look at these things many ways, I'm probably also going to allow for a user to do <code class="language-bash">python articles.py --generate [path]</code>, which will simply spit out the the rendered results of going to <code class="language-bash">[path]</code>. I guess that <em>might</em> just be indistinguishable from using <code class="language-bash">wget</code>, but hey. It can't hurt to give more functionality!</p>
|
||||||
|
<p>It remains to be seen precisely how many pages on this site will use the general page template. I don't want to rely on it too much, but, man, is there <em>any</em> reason not to? Basically, it means that I don't have to worry about writing the headers of anything on my website. I guess I'll need to be able to throw it off when I'm making subpages that are intended to be stylistically distinct from the rest of my site.</p>
|
||||||
|
</article>
|
9
articles/auriga.template.html
Normal file
9
articles/auriga.template.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "articles/article.template.html" %}
|
||||||
|
|
||||||
|
{% block title -%}
|
||||||
|
How should this website be laid out?
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{% block body -%}
|
||||||
|
{%- include "articles/auriga.article.html" -%}
|
||||||
|
{%- endblock %}
|
24
articles/distributed_speakers.article.html
Normal file
24
articles/distributed_speakers.article.html
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<article>
|
||||||
|
<h1>Distributed Speakers</h1>
|
||||||
|
<h4>(project idea)</h4>
|
||||||
|
<div class="important">
|
||||||
|
<p>So you want to have a rally. You want to hold a sports competition for your large neighborhood. Maybe you want to broadcast announcements across your company picnic. Maybe you want to throw an impromptu dance party!</p>
|
||||||
|
<p>The common line between all of these scenarios is this: you need a sound system, but you do not have one.</p>
|
||||||
|
</div>
|
||||||
|
<p>I first conceived of this while thinking about the specific issue of a dance party. Here's my solution:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Everyone downloads this free app.</li>
|
||||||
|
<li>Everyone directs the app to the streaming media source of choice - a web radio station or something.</li>
|
||||||
|
<li>Each phone in the network listens to the audio it hears, and synchronizes what it's playing to the surroundings.</li>
|
||||||
|
</ul>
|
||||||
|
<p>I liked this idea because I have friends I like dancing with, but we rarely have a sound system set up and in place for dancing in public spaces. But anywhere you need to communicate something to a large number of people but you don't have a sound system, this app would be useful.</p>
|
||||||
|
<h3>Let's talk about issues.</h3>
|
||||||
|
<p class="important">How do you sync up a bunch of audio sources together on the fly, with limited communication between them?</p>
|
||||||
|
<p>That's the biggest problem, but there are smaller issues - well, they're really just the obstacles we'd need to face:</p>
|
||||||
|
<ul>
|
||||||
|
<li>How do we make this accept a wide variety of stream types - web radio, youtube, soundcloud, etc.?</li>
|
||||||
|
<li>How do you do ad hoc networking between mobile devices?</li>
|
||||||
|
<li>How do we tie this in with youtube playlists, which people will frequently want to play music from?</li>
|
||||||
|
<li>Is this even possible, when considering the speed-of-sound delay? How far apart can sources be, such that they're perceived as one sound rather than two?</li>
|
||||||
|
</ul>
|
||||||
|
</article>
|
9
articles/distributed_speakers.template.html
Normal file
9
articles/distributed_speakers.template.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "articles/article.template.html" %}
|
||||||
|
|
||||||
|
{% block title -%}
|
||||||
|
Impromptu Soundsystems would be a good name for a band.
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{% block body -%}
|
||||||
|
{%- include "articles/distributed_speakers.article.html" -%}
|
||||||
|
{%- endblock %}
|
36
articles/easy_peasy_state_machinesy.article.html
Normal file
36
articles/easy_peasy_state_machinesy.article.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h1>Easy Peasy State Machinesy</h1>
|
||||||
|
</header>
|
||||||
|
<p>Why do I always have to actually use boolean flags (manually setting and unsetting them) to track the states of my entities?</p>
|
||||||
|
<pre>
|
||||||
|
<code>player.shielding = new Toggle()
|
||||||
|
keyboard.on('w pressed', player.shielding.next)</code></pre>
|
||||||
|
<p>I'm just throwing this syntax together off the top of my head. The syntax isn't important - what's important is that I should be able to describe this and have it happen.</p>
|
||||||
|
<pre>
|
||||||
|
<code>strobelight.color = new Sequence(['red', 'green', 'blue'])
|
||||||
|
strobelight.update = function(dt) {
|
||||||
|
strobelight.color.next()
|
||||||
|
strobelight.draw()
|
||||||
|
}</code></pre>
|
||||||
|
<p>Seriously, don't worry about this syntax - it's ugly and I just threw it together. The point is the kinds of things I should be able to do. This is all totally feasible.</p>
|
||||||
|
<pre>
|
||||||
|
<code>goomba.ai = new StateMachine(['sleep', 'suspicious', 'alert'])
|
||||||
|
goomba.ai['sleep'].transitions_to['suspicious'].on(goomba.near(player))
|
||||||
|
// the state 'sleep' should transition to 'suspicious' on the event goomba.near(player)
|
||||||
|
goomba.ai['sleep'].update = goomba.draw_snores
|
||||||
|
|
||||||
|
goomba.ai['suspicious'].transitions_to['alert'].on(goomba.sees(player))
|
||||||
|
goomba.ai['suspicious'].update = goomba.search_for_player
|
||||||
|
|
||||||
|
// shit we forgot to make a state for just patrolling
|
||||||
|
goomba.ai.add_state('patrol')
|
||||||
|
goomba.ai['patrol'].transitions_to['sleep'].after(5 seconds)
|
||||||
|
goomba.ai['patrol'].update = goomba.wander
|
||||||
|
|
||||||
|
// oh hey, she should occasionally wake up to patrol!
|
||||||
|
goomba.ai['sleep'].transitions_to['patrol'].after(5-10 seconds)</code></pre>
|
||||||
|
<p>So y'know. State machines are powerful. In order to really use them, you need a robust event system, or else they're a huge pain - it's still possible, you just... need to code it to check the conditions on each update loop. That could get expensive!</p>
|
||||||
|
<p>For the example of checking <code>goomba.near(player)</code> - which has an optional argument for the distance - that function checks if there's already a collision detection object attached to <code>goomba</code> for setting off proximity events. If there is, it returns the event handle, which can be used for binding behaviors to the firing of that event. If a proximity collider of the right size <em>doesn't</em> exist, then it creates one, and returns the event handle.</p>
|
||||||
|
<p></p>
|
||||||
|
</article>
|
294
articles/game_log.article.html
Normal file
294
articles/game_log.article.html
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
<style type="text/css">
|
||||||
|
.accolades { display: inline-block; }
|
||||||
|
.thoughts { font-size: smaller; font-style: italic; }
|
||||||
|
#games-log p { margin: 0; }
|
||||||
|
.difficulty, .achievement {
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.max {
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.hard {
|
||||||
|
background-color: rgb(255,70,70);
|
||||||
|
}
|
||||||
|
.normal {
|
||||||
|
background-color: rgb(200,200,200);
|
||||||
|
}
|
||||||
|
.easy {
|
||||||
|
background-color: rgb(70,255,70);
|
||||||
|
}
|
||||||
|
.bad {
|
||||||
|
background-color: yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<article id="games-log">
|
||||||
|
<h1>Games I've Played</h1>
|
||||||
|
<section>
|
||||||
|
<h2>Mostly Shooters and Stuff</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Mass Effect 3 Multiplayer</li>
|
||||||
|
<li>Halo: Combat Evolved
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty max">Legendary solo</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">I really liked Halo: CE. It was a strong game, and I've had a soft spot for the Halo story - I don't think it's particularly deep or told with finesse, but it's <em>fun</em>!</p>
|
||||||
|
</li>
|
||||||
|
<li>Halo 2
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty hard">Heroic co-op</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">I've been telling myself I'm going to beat Halo 2 on legendary by myself since the day I beat Halo: CE on legendary. I feel the overwhelming urge to be able to say I've beaten the whole trilogy on the hardest difficulty! On the other hand, it's really goddamn hard.</p>
|
||||||
|
</li>
|
||||||
|
<li>Halo 3
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty max">Legendary co-op</span>
|
||||||
|
<span class="difficulty max">Legendary solo</span>
|
||||||
|
<span class="achievement max">All Skulls found</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Halo 3: ODST
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty hard">Heroic co-op</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Halo: Reach
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty hard">Heroic co-op</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Gears of War
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty max">Insane co-op</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Gears of War 2
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty hard">Hardcore co-op</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Gears of War 3
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty hard">Hardcore co-op</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Half-Life</li>
|
||||||
|
<li>Half-Life: Blue Shift</li>
|
||||||
|
<li>Half-Life: Opposing Force</li>
|
||||||
|
<li>Half-Life 2 (and Episode 1) (and Episode 2)</li>
|
||||||
|
<li>Portal</li>
|
||||||
|
<li>Portal 2 (and co-op)</li>
|
||||||
|
<li>Army of Two</li>
|
||||||
|
<li>Army of Two: 40th Day</li>
|
||||||
|
<li>Operation Flashpoint: Dragon Rising
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="achievement bad">Gave up after like 30 minutes</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">This game was terrible.</p>
|
||||||
|
</li>
|
||||||
|
<li>Resistance: Fall of Man
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty hard">Hard? co-op</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Resistance 3
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty hard">Hard co-op</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">These games weren't very deep, but they had decent shooting and good weapons. Resistance 2 didn't have co-op, so I didn't play it - I just watched my friend do it.</p>
|
||||||
|
</li>
|
||||||
|
<li>Killzone 3
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty hard">Veteran? co-op</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">This game offered alternate color modes for colorblindness, which is awesome. Shame the dialogue and plot was so literally laughable.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>Resident Evil 5
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty hard">Veteran? co-op</span>
|
||||||
|
<span class="achievement max">Broke one level</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">My pal and I played this over one break, and we couldn't take it seriously. Once we beat it, we spent our hard-earned points on getting infinite ammo for a few weapons - and decided we'd try to unlock infinite ammo for every weapon. We didn't end up doing that, but we did get so practiced at going through one level - which drops the most money for the time you spend in it by <em>far</em> - that we beat the max difficulty time trial by <em>half</em>. The magnum in that game is ridiculously overpowered.</p>
|
||||||
|
</li>
|
||||||
|
<li>F.3.A.R.
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty hard">Fearless? co-op</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">As far as I can tell, these people have no idea what the phrase "survival horror" even means.</p>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>Not Shooters</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Pokemon: Red
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="achievement normal">Beat the Elite Four</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Pokemon: Silver</li>
|
||||||
|
<li>Pokemon: Diamond
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="achievement normal">Beat the Elite Four</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Prince of Persia: Sands of Time</li>
|
||||||
|
<li>Prince of Persia (2008)</li>
|
||||||
|
<li>Super Smash Brothers: Melee
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="achievement hard">Every SP challenge</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Super Smash Brothers: Brawl
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="achievement max">Every achievement</span>
|
||||||
|
<span class="achievement bad">except one sticker</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Mario Kart: Double Dash
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="achievement max">Time Trial Staff Ghosts</span>
|
||||||
|
<span class="achievement max">Every Cup on Mirror</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Mario Kart: Wii
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="achievement max">Gold Medals on Everything</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Okami
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="achievement normal">All brush techniques</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Legend of Zelda: Link's Awakening
|
||||||
|
<p class="thoughts">I think this might be my #1 pick for best Zelda game.</p>
|
||||||
|
</li>
|
||||||
|
<li>Legend of Zelda: Ocarina of Time</li>
|
||||||
|
<li>Legend of Zelda: Twilight Princess</li>
|
||||||
|
<li>Super Mario 64</li>
|
||||||
|
<li>Super Mario Sunshine</li>
|
||||||
|
<li>Final Fantasy</li>
|
||||||
|
<li>Final Fantasy 6
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="achievement bad">Halfway</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Final Fantasy 7
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="achievement bad">Halfway</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Final Fantasy 8
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="achievement bad">Halfway</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">I feel like including Final Fantasy games that I haven't finished is still reasonable because not finishing a Final Fantasy game involves a similar time commitment as finishing many other games.</p>
|
||||||
|
</li>
|
||||||
|
<li>No More Heroes
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty normal">Mild</span>
|
||||||
|
<span class="achievement normal">All Beam Katanas</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>No More Heroes 2: Desperate Struggle
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty normal">Mild</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Guitar Hero
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty max">Expert</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Rock Band
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty max">Expert Guitar</span>
|
||||||
|
<span class="difficulty normal">Medium Drums</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>Super Metroid</li>
|
||||||
|
<li>Metroid: Fusion</li>
|
||||||
|
<li>Metroid: Zero Mission</li>
|
||||||
|
<li>Metroid Prime</li>
|
||||||
|
<li>Metroid Prime 3: Corruption</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>More Indie</h2>
|
||||||
|
<ul>
|
||||||
|
<li>World of Goo</li>
|
||||||
|
<li>Cave Story</li>
|
||||||
|
<li>Gish</li>
|
||||||
|
<li>Kerbal Space Program
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="achievement normal">Low Kerbin Orbit</span>
|
||||||
|
<span class="achievement normal">Round-trip Mun Mission</span>
|
||||||
|
<span class="achievement hard">Minmus Mission</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>Extremely Memorable</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Shadow of the Colossus
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty max">Hard</span>
|
||||||
|
<span class="achievement hard">Time Trials (Normal)</span>
|
||||||
|
<span class="achievement max">Climbed the temple</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">I love this game so much I'm not even going to write about it. My thoughts would take up too much space.</p>
|
||||||
|
</li>
|
||||||
|
<li>Ico
|
||||||
|
<p class="thoughts">Ico was very pretty, and had some of the same quality that Shadow of the Colossus had, but it didn't tie together nearly so well.</p>
|
||||||
|
</li>
|
||||||
|
<li>Mirror's Edge
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty normal">Easy</span>
|
||||||
|
<span class="achievement hard">Test of Faith (Pacifist)</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">This game has the best platforming I've had the pleasure of experiencing - and I'm a sucker for good platforming.</p>
|
||||||
|
</li>
|
||||||
|
<li>El Shaddai
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty normal">Normal</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">I loved this game from an aesthetic point of view, but I kept waiting for the story to get interesting. I'm still waiting.</p>
|
||||||
|
</li>
|
||||||
|
<li>Zeno Clash
|
||||||
|
<p class="thoughts">The aesthetic really makes this game stand out.</p>
|
||||||
|
</li>
|
||||||
|
<li>Iji
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty normal">Normal</span>
|
||||||
|
<span class="achievement normal">Somewhat Pacifist</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">Iji remains one of my favorite games of all time, for its excellent pseudo-morality system - one of the best I've seen.</p>
|
||||||
|
</li>
|
||||||
|
<li>Valkyrie Chronicles
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty normal">Normal</span>
|
||||||
|
<span class="achievement normal">No deaths</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">Valkyrie Chronicles had such a cool gameplay and storytelling style that I have to include it.</p>
|
||||||
|
</li>
|
||||||
|
<li>No More Heroes
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty normal">Mild</span>
|
||||||
|
<span class="achievement normal">All Beam Katanas</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">It's hard to describe this game. It was fascinating.</p>
|
||||||
|
</li>
|
||||||
|
<li>Elite Beat Agents
|
||||||
|
<div class="accolades">
|
||||||
|
<span class="difficulty hard">Sweatin'!</span>
|
||||||
|
<span class="difficulty max">Hard ROCK!</span>
|
||||||
|
</div>
|
||||||
|
<p class="thoughts">Probably my favorite rhythm game.</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</article>
|
9
articles/game_log.template.html
Normal file
9
articles/game_log.template.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "articles/article.template.html" %}
|
||||||
|
|
||||||
|
{% block title -%}
|
||||||
|
I occasionally play some videogames.
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{% block body -%}
|
||||||
|
{%- include "articles/game_log.article.html" -%}
|
||||||
|
{%- endblock %}
|
15
articles/language_for_games.template.html
Normal file
15
articles/language_for_games.template.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{% extends "articles/article.template.html" %}
|
||||||
|
|
||||||
|
{% block title -%}
|
||||||
|
Features for a game-focused programming language or library
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{% block body -%}
|
||||||
|
<p>I like making games but sometimes I spend a lot of time doing stuff that is just annoying. What if a language or environment were designed to make those things easy?</p>
|
||||||
|
<hr>
|
||||||
|
{%- include "articles/snorlax_evaluation.article.html" -%}
|
||||||
|
<hr>
|
||||||
|
{%- include "articles/time_integration.article.html" -%}
|
||||||
|
<hr>
|
||||||
|
{%- include "articles/easy_peasy_state_machinesy.article.html" -%}
|
||||||
|
{%- endblock %}
|
30
articles/mindjail_engine.article.html
Normal file
30
articles/mindjail_engine.article.html
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<article>
|
||||||
|
<h1 class="title">Mindjail Engine!</h1>
|
||||||
|
<p>This is doubtlessly my most ambitious project. It's a little 2D game engine in python that I've been working on for a while now. It's got some basic physics (not accurate, but they feel right, and that's what counts) and it can zip along pretty respectably! I first started this project in my second year of college, but I soon abandoned it because (surprise of surprises!) I had a lot of classes to work on. When I finally picked it back up towards the start of 2013, I had grown a lot as a programmer and a human being, and there were changes to make. I still love this project, but the primary goal I had here was to never set a deadline for myself. The idea was that I should never say when this project will be done - because it's always in progress. I'm never fully committing myself to a flawed approach, and, although there's a bunch of ugly code here, I'm never afraid to go back and change how I did something.</p>
|
||||||
|
<h3>Tell me all about collision detection, it is my favorite subject!</h3>
|
||||||
|
<p>I was good at my data structures and algorithms class, and they're concepts I'm deeply familiar with. It's interesting, though, that nothing ever gave me such a good sense for how algorithmic complexities compare until I was doing real-time collision detection. It doesn't help that my chosen language was python - a decision that helped many things in this project, but not speed. <span class="sidenote">People will happily claim that python is too slow to ever make a real game with, but it's just not true. Computers are fast. I'm convinced that python is perfectly capable.</span> There've been a lot of data structures I used for this, and the source is somewhere - <span class="todo">I'm going to put those online at some point.</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>When I started out, of course, I did the brute force N^2 test, because I just wanted to get objects moving around on the screen. This rapidly bottomed out once I got more than probably 30 objects on the screen. I don't remember, it was a long time ago! I knew from the start that I was going to have to do something better, so I did.</li>
|
||||||
|
<li>The next step was to roll something more advanced of my own. It had problems, but I'm still proud of how well it worked - I called it a sorted search list. The idea was that the list of objects in the world would be simultaneously kept sorted by each object's maximum and minimum extents on the x- or y-axes. When you're searching for a collision, then, you can cut down how many checks you do by searching upwards and downwards through the list until you find an object which is too far away to intersect - at which point no further objects could possibly be touching you. <span class="todo">I should make a picture.</span> Anyway, this system worked alright - if I remember correctly, I got up to around 50 objects on screen before it started slowing down a lot. I kept this around as a supporting data structure, but I didn't realize the massive flaws in it - in order to be certain about objects Foo and Bar not colliding, you need to run the check for Foo against Bar as well as Bar against Foo. Anyway.</li>
|
||||||
|
<li>
|
||||||
|
<p>After that I finally decided to ask the great oracle Google for help. Why didn't I use the knowledge of others before that? Well, they never really covered collision detection-specific data structures in my classes... I found out about a thing called a quadtree, and I was hooked. The idea is to recursively divide space into quadrants - objects northeast of center, northwest of center, and so on. This is the structure I spent the most time on, because I was dead-set on making it work. It was just so <em>cool!</em></p>
|
||||||
|
<p>Well. That was silly of me. There are a lot of problems. Suppose Foo is in the northwest corner, but Bar overlaps between northwest and northeast! There's no simple solution, and mine was to have a secondary data structure, which stored objects which couldn't fit into any of the corners.</p>
|
||||||
|
<p>At this point, I realized a structure-agnostic speedup I could use: Be mindful of whether objects move or not. If two objects never move, you never need to see if they collide. With this, the system got up to probably 80 objects on screen, with most of them stationary. Point being, it was a lot faster. I needed more, though! There was a huge problem:</p>
|
||||||
|
<p>The quadtree wasn't balancing. Balancing a regular tree data structure is one thing, but quadtrees have two dimensions to balance at once, which makes it infinitely more difficult... And I couldn't find a tutorial on it, nor figure it out on my own. All the tutorials either dealt with worlds that had a size limit for objects, or discrete-position finite-world grid systems. I didn't want to do either of those! So I started panicking.</p>
|
||||||
|
</li>
|
||||||
|
<li>The next solution was to try variations on quadtrees. I tried a bunch - changing what supporting data structure I used, switching from a strict quadtree - at each level dividing in quadrants - to a <a href="http://wikipedia.org/wiki/K-d_tree">k-D tree</a>: At each level, it divides the world in half, and switches the lines along which it divides the world each level. They're a little more flexible in a few ways, and in theory easier to balance (because you don't need to balance two dimensions at the same time so much). Unfortunately, there's a dearth of information about using them for collision detection, because everyone uses them for graphics and not much else. <span class="sidenote">At this point, I was running out of steam for recursive data structures, but I briefly considered extending my k-D tree to be the most general kind of <a href="https://en.wikipedia.org/wiki/Binary_space_partitioning">binary space partitioning tree</a>, wherein you don't just cycle your dividing axis through a set of options, but rather you divide along a completely new axis - not necessarily perpendicular! - at each level. This is used for raytracing a lot, but implementing it for these purposes would have been a pain. It would have just meant more balancing and trying to make the trees smart, which I didn't want to get too heavily into.</span> I gave up on this soon after, partly because...</li>
|
||||||
|
<li>I realized that my secondary data structure didn't work right. You needed to double-check every collision in order to be sure you had gotten all of them, and besides, sorting along one axis had little effect when you were frequently checking collisions which are grouped along the axis it doesn't sort on. I was basically back to square one. That's when I finally gave up on the tree - I would have needed to make it too smart in filling itself, I would have needed to balance it, I would have needed to have a good secondary data structure, and... It wasn't worth it. But then I found the light.</li>
|
||||||
|
<li>
|
||||||
|
<p>Spatial Hashing was something I'd heard of before, but mostly in the context of grid-based systems, finite worlds, and size-limited systems. I didn't want <em>any</em> of that. The typical spatial hashing scheme goes like this: You have a 2D array of lists. Each list corresponds to one grid space in your world, and so you only need to check against objects in adjacent squares. Here was my problem: Static arrays means you need to have a set size for your world, I don't like strict gridding, and I wanted to account for the fact that I might have large objects! But there's a solution, and, as it <em>always</em> seems to be in the world of data structures for practical everyday purposes, it's hash tables.</p>
|
||||||
|
<p>Here's how my system works: The Spatial Hash Grid is a dict. The keys are (x,y) tuples which index into the infinite space of grid squares. The items are a secondary collision-detection data structure, which contain the objects. To find the key for an object, you just have to integer divide its coordinates. Since it just uses python's built-in dicts, it's hashing the tuples - so you never need to pre-specify the size of your world! The thorniest thing to get around was storing large objects. I tried throwing items into all the grid squares they touch, but it was too slow. The solution I ended up using is to make multiple tiers.</p>
|
||||||
|
<p>When you put an object in the grid, it checks its size (by looking at the min/max x/y coordinates, which shape objects contain). If it's small enough to fit in this grid - that it will only ever occupy one square and its neighbors - then it goes in the dict we're looking at. Otherwise, the grid makes a new grid - with twice the grid size! Larger objects get shoved up the ladder, and when you're checking for collisions, you traverse up the ladder until you hit the end. This is reasonably fast so long as you don't have unreasonably many objects on different size scales.</p>
|
||||||
|
<p>And it works! I haven't done extensive testing, but it goes up to 150 - 40 moving around, and the rest stationary - with 60FPS. I've gotten some slowdown after that (only from adding more moving objects) but it's certainly fast enough for my purposes - and some of the speed loss is from unoptimized rendering - and it should be the case that a sparsely populated world will have nearly no slowdown from additional objects being chucked in.</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>So I'm using Spatial Hashing, and there're ways for it to be sped up, but collision detection works pretty well for now - certainly well enough to focus on other things.</p>
|
||||||
|
<h3>Yes, but what about... anything else?</h3>
|
||||||
|
<p>Well, this project is about the engine, so I'm not prepared to go into the actual game I want to make with it, but there's certainly graphics and windowing to talk about. The graphics are, for the moment, all coded up with vertex lists that it generates when it runs, and they're far from optimized or anything. This is good because I learned a lot about OpenGL. This is bad because pretty much all of what I learned is now obsolete, since the computer I've been developing for doesn't... have support... for shaders. Whoops. I want to get more experience with shaders, but I don't have a computer that's good for it right now. Also, that will be more meaningful when I have a better model-<engine pipeline for actually putting content into the engine.</p>
|
||||||
|
<p>Windowing is, for the moment, done through pyglet, which is a lightweight framework for windowing and opengl bindings. I like it okay, but it's not capable of doing much - I'd have to write my own GUI, which would be suboptimal (although not too hard) given that I could just get a framework to do it for me. What I'm trying to do now is switch to using PyQt, having tried wxPython briefly and found it very hard to work with. I'm still working through reimplementing secondary things that pyglet was doing for me, such as keyboard and mouse handling and clock/fps management. That's what the gui branch is for, on github.</p>
|
||||||
|
<h3>I guess links would be nice?</h3>
|
||||||
|
<p>Oh, yes! Right. <a href="http://github.com/shoofle/mindjailengine/">The repository</a> is up on github, and it should work for you if you fork it. You'll need to pip install pyglet, or fork their latest dev version if you're on a mac - there's some kind of unresolved problem with OSX or something. That's one of the reasons I want to switch to a different framework - better portability.</p>
|
||||||
|
</article>
|
9
articles/mindjail_engine.template.html
Normal file
9
articles/mindjail_engine.template.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "articles/article.template.html" %}
|
||||||
|
|
||||||
|
{% block title -%}
|
||||||
|
The Mindjail Engine!
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{% block body -%}
|
||||||
|
{%- include "articles/mindjail_engine.article.html" -%}
|
||||||
|
{%- endblock %}
|
@ -3,8 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Projects, by Shoofle</title>
|
<title>Projects, by Shoofle</title>
|
||||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
<link href="/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<article class="project">
|
<article class="project">
|
32
articles/oauth.article.html
Normal file
32
articles/oauth.article.html
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<article>
|
||||||
|
<h1>OAuth Adventures</h1>
|
||||||
|
<h4>(how does it work?)</h4>
|
||||||
|
<p>I recently had some exciting adventures involving trying to make a bot that posted to Tumblr. I eventually got it working (well, so far, just the posting part, but that's the one I didn't understand!)) but decided that I should write down what I learned about OAuth - and specifically, how to use it to write robots that post on their own.</p>
|
||||||
|
<p>The problem is that all the many guides to using OAuth are specifically geared towards the expected use case - I want my app to access users' data on other services like twitter! That's not what I want. I want my bot to be able to periodically run and access some tumblr accounts. This seems like it shouldn't be too hard, but I don't want to code in the password to this account! So what do I do?</p>
|
||||||
|
<p>So let's go through this backwards.</p>
|
||||||
|
<p>It's doable, very doable if you're using a library like oauth2, and extremely doable if you're using <a href="https://github.com/tumblr/pytumblr">tumblr's python api!</a> Either way, you're going to end up making requests to the <a href="http://www.tumblr.com/docs/en/api/v2">tumblr web api</a> using open authentication, and you're going to need a token to do it.</p>
|
||||||
|
<p>You need an Access Token.</p>
|
||||||
|
<p>An access token is keyed to your application, and it's been verified by Tumblr that a user has verified that you can use it. Think of it as the key to your user's content, which your user hands over to the application.</p>
|
||||||
|
<p>Of course, in your case, you're not going to care much about the exact mechanics of acquiring the access token, beyond the first time. You use the access token to sign your requests. How to do that is something I'm sure there are other tutorials for - if you're using oauth2, you simply need to specify it as the token for your client object:</p>
|
||||||
|
<pre><code>import oauth2 as oauth
|
||||||
|
client = oauth.Client(consumer, access_token)</pre></code>
|
||||||
|
<p><code>consumer</code> here refers to a key/secret pair, which you're given when you register your application. It lets tumblr know (through the oauth protocol) which application this is.</p>
|
||||||
|
<p>The <code>access_token</code> is <em>also</em> a key/secret pair, but you get it when the user logs in through oauth. The key and the secret are two strings of random-looking stuff, which is cryptographic magic.</p>
|
||||||
|
<p>If you're trying to figure out (as I was) how to get your python script to access user-restricted tumblr data, but you don't want to code the password to your account directly into the script, then the access token is exactly what you're looking for. I stuck it in a file that I don't share with anyone, from which my script imports the keys. Now I could share my script, but no one would have my keys - and even if they did, I could revoke its access to my account at any time.</p>
|
||||||
|
<p>If I'm using oauth2, then it works as above, and you use the <code>client</code> object to make your requests. If you're using tumblrpy, then you simply provide the consumer token's key and secret, as well as the access token's key and secret, to the library when you are initializing your client object. It's very easy!</p>
|
||||||
|
<h4>Okay but how do you do it?</h4>
|
||||||
|
<p>I can tell you're a smart cookie! That's a very good question. It's easy to use the access token, but how do you actually <em>acquire</em> it? As far as I can tell, the answer is to do the standard three-legged authentication process, but only do it once.</p>
|
||||||
|
<p>I just brought up the interactive python console and started typing in code as though I were trying to code a three-legged authentication workflow (this is the one you hear about when you google for oauth tutorials). Here are the steps of that process, in case you forgot:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Acquire a consumer key and secret when you register your application.</li>
|
||||||
|
<li>Initialize an <code>oauth.Consumer</code> object with the consumer key and secret.</li>
|
||||||
|
<li>Initialize an <code>oauth.Client</code> object with your <code>oauth.Consumer</code> object.</li>
|
||||||
|
<li>Using that client, make a request to the request token url (for tumblr, it's <a href="http://tumblr.com/oauth/request_token">http://tumblr.com/oauth/request_token</a>). The response will contain a request token - a key and secret pair. This is used to acquire your access token!</li>
|
||||||
|
<li>Produce a URL to which to direct the user you want to get credentials for. This looks something like this: <code>http://tumblr.com/oauth/authorize?oauth_token=[your request token's key goes here]</code>.</li>
|
||||||
|
<li>When a user (such as yourself!) goes there, they will be prompted for what to do, and then when they grant authorization, they'll be redirected somewhere with a "verifier" in the URL arguments. If you were making a standard three-legged application, this would redirect you back to your website, which would then store and use the verifier. You just need to redirect yourself to somewhere and copy/paste the verifier out of your URL bar. The callback URL is set in the tumblr settings for the application.</li>
|
||||||
|
<li>Now you can use <code>token.set_verifier([some verifier])</code> to set your request token as being verified as good.</li>
|
||||||
|
<li>Your request token has been verified, so now you simply make a request (using that token, so <code>client = oauth.Client(consumer, request_token)</code>) to the access token URL - for example, <a href="http://tumblr.com/oauth/access_token">http://tumblr.com/oauth/access_token</a>. The response to <em>this</em> will finally contain... Drumroll!</li>
|
||||||
|
</ul>
|
||||||
|
<h4>The access token!</h4>
|
||||||
|
<p>So that's how it's done.</p>
|
||||||
|
</article>
|
9
articles/oauth.template.html
Normal file
9
articles/oauth.template.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "articles/article.template.html" %}
|
||||||
|
|
||||||
|
{% block title -%}
|
||||||
|
I have used OAuth, and lived to tell the tale.
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{% block body -%}
|
||||||
|
{%- include "articles/oauth.article.html" -%}
|
||||||
|
{%- endblock %}
|
21
articles/play_for_x.article.html
Normal file
21
articles/play_for_x.article.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<article>
|
||||||
|
<h1 class="title">Play for X!</h1>
|
||||||
|
<p>This is a running project I'm working on. Check it out on <a href="http://li60-203.members.linode.com:7777/">another port on this very server</a>, with the caveat that it's not exactly the belle of the ball at the moment. Lately I've not been focusing on the styling and design so much as I've been focusing on...</p>
|
||||||
|
<p>The functionality! The super short version is this:</p>
|
||||||
|
<blockquote>
|
||||||
|
<p>Instead of rolling dice to see if you hit a monster, why not play a minigame instead?</p>
|
||||||
|
</blockquote>
|
||||||
|
<p>Tabletop roleplaying games (my experience is mostly with D&D 3.5, but I've also been playing <a href="http://www.dungeon-world.com/">Dungeon World</a> and someday I want to run or be in a <a href="http://www.mimgames.com/window/">The Window</a> game) have the well-agreed on standard that you use dice to generate random numbers to check whether you succeed on chance-based tasks. This introduces instability into the game, which makes things tense and interesting and prevents the game from playing the same way every time!</p>
|
||||||
|
<p>But the only input the player actually has on how well they do, then, is the gameplay choices which apply various bonuses to their rolls. And that's kinda sucky! Because now that we all have computers, why not do something more interesting: </p>
|
||||||
|
<blockquote>
|
||||||
|
<p>When your character faces a skill-based task, you have to face one as well.</p>
|
||||||
|
</blockquote>
|
||||||
|
<h3>So what <em>is</em> Play for X anyway?</h3>
|
||||||
|
<p>It's a chatroom, plus a bunch of tiny javascript games. You and your friends all log into a room together, and you start playing your game over the voice chat system of your choice. When you (as the DM) decree that a player needs to make a skill check, you simply choose a minigame or microtask from the list, and drag it onto their name. It immediately pops up on their screen, and when they've completed it, their score is posted into the chatroom, and you can make a decision based on how well they did!</p>
|
||||||
|
<p>It's not finished yet. How the various parts of the system talk to each other has changed a bit as I've worked on this - the chat functionality works through websockets, and the games are slated to communicate their results to the client's browser by postMessage passing. This is partially implemented in...</p>
|
||||||
|
<p>The code! The source is available at <a href="http://github.com/shoofle/play-for-x/">the github project play-for-x</a>, and you're entirely welcome to inspect, criticize, suggest, fork, whatever, as you like. I'd be interested in hearing if you do something with it! Some parts are pretty messy, but the games themselves are fun to make.</p>
|
||||||
|
<h3>Can I check it out?</h3>
|
||||||
|
<p>Sure! If you want to just try the games, you should direct your eyeballs or eyeball-equivalents at <a href="http://li60-203.members.linode.com:7777/games/">this lil' website</a>, which lets you try out the minigames I've made, play with their configurations, and so on. It uses a <a href="http://jsoneditoronline.org">nifty json editor widget</a> that someone made.</p>
|
||||||
|
<hr>
|
||||||
|
<p>One of my favorite things about working on this project is that it really strips out all the cruft that usually comes with working on game projects - I don't need to worry about the engine, I don't need to worry about rendering engines, I don't need to make lots of textures. I explicitly set a goal of never writing a large game for this project. With that requirement in place, I'm totally free to experiment a <em>lot</em>, and just throw together little javascript games in a few hours. Indeed, most of the games you'll see here took me half an afternoon to write! Experimenting with different forms of gameplay, and exploring exactly that side of the craft, is one of my greatest interests.</p>
|
||||||
|
</article>
|
9
articles/play_for_x.template.html
Normal file
9
articles/play_for_x.template.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "articles/article.template.html" %}
|
||||||
|
|
||||||
|
{% block title -%}
|
||||||
|
Play For X
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{% block body -%}
|
||||||
|
{%- include "articles/play_for_x.article.html" -%}
|
||||||
|
{%- endblock %}
|
4
articles/shoof_shoof_revolution.article.html
Normal file
4
articles/shoof_shoof_revolution.article.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<article>
|
||||||
|
<h2 class="title">Shoof Shoof Revolution!</h2>
|
||||||
|
<p>As part of <a href="/play-for-x/">Play for X</a>, I made a javascript-powered clone of DDR, using SVG. I like working with SVG and javascript - I can directly manipulate drawing rules and maintain an incredibly tight feedback loop as I develop. In this case, though, I was so proud of what I made that I kept trying to make it better. It's far from finished and I've set it aside as I work on other projects, but, in theory, this project was to make a simple javascript clone of DDR - but using the web audio API, I was going to make it so you could load in a file, entirely locally, and it would do automatic beat detection and generate an actual track for your song. Unfortunately, audio processing and beat detection is less than easy and simple when you're using javascript. <a href="http://github.com/shoofle/shoof-shoof-revolution">It's a cool project, and I'm interested in returning to it sometime.</a></p>
|
||||||
|
</article>
|
9
articles/shoof_shoof_revolution.template.html
Normal file
9
articles/shoof_shoof_revolution.template.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "articles/article.template.html" %}
|
||||||
|
|
||||||
|
{% block title -%}
|
||||||
|
Javascript DDR Clone
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{% block body -%}
|
||||||
|
{%- include "articles/shoof_shoof_revolution.article.html" -%}
|
||||||
|
{%- endblock %}
|
64
articles/snorlax_evaluation.article.html
Normal file
64
articles/snorlax_evaluation.article.html
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h1>Snorlax Evaluation</h1>
|
||||||
|
<p>(define-by-reference, or: lazy evaluation taken to extremes)</p>
|
||||||
|
</header>
|
||||||
|
<p>Okay, so I've got a <code>Bomb</code> entity in my game. It's already got the behavior for flying toward its <code>destination</code>. What if I want to make a <code>SmartBomb</code> that tracks a target even if they move? I might do it something like this:</p>
|
||||||
|
<pre><code>SmartBomb.on_update = function (timestep) {
|
||||||
|
// other update behaviors go in this function as well
|
||||||
|
this.destination = target.position
|
||||||
|
}</code></pre>
|
||||||
|
<p>I have to explicitly tell my engine to execute this every frame. I think in terms of this kind of thing already, because I'm a math and physics person. Why can't I define relationships like this more simply? What if, in fact, this was the default way we referred to values? <span class="sidenote span4">It's worth noting that what I've thought of here is essentially just <a href="https://en.wikipedia.org/wiki/Functional_reactive_programming">functional reactive programming</a>. You can go read wikipedia if you want.</span></p>
|
||||||
|
<pre><code>SmartBomb.destination = target.position</code></pre>
|
||||||
|
<p>Any time something fetches the value of <code>SmartBomb.destination</code> it'll fetch the value of <code>target.position</code>. Writing it this way, instead of explicitly specifying which variables need to be kept up-to-date with other variables (and when they need to be updated!), means it's easier to give variables interesting dependencies on other values - like this <code>shield</code> which should float a certain distance between the <code>player</code> and the <code>enemy</code>:</p>
|
||||||
|
<pre><code>shield.position = player.position + shield.distance * unit_vector(enemy.position - player.position)</code></pre>
|
||||||
|
<p>If and when you <em>do</em> need to store something's value at a specific time, you can do that if you want - for example, this code when a bomb explodes:</p>
|
||||||
|
<pre><code>explosion_location = current_value(bomb.position)
|
||||||
|
// or maybe the syntax is like this:
|
||||||
|
explosion_location = bomb.position.current_value</code></pre>
|
||||||
|
<p>So far, everything's time-independent. For example, the <code>shield</code> object's <code>position</code> depends only on the positions of other objects.</p>
|
||||||
|
<p>Why not include time-dependence? A <code>bullet</code> has a <code>position</code> and a <code>velocity</code>, and these are related in a way that doesn't change at any point during gameplay. Why not codify that relationship in a similar way?</p>
|
||||||
|
<pre><code>bullet.position = bullet.position + time_step * bullet.velocity
|
||||||
|
// or maybe
|
||||||
|
bullet.position = bullet.position + bullet.position.time_since_last_calculation * bullet.velocity</code></pre>
|
||||||
|
<p>Okay, if this seems like impossible magic, I'm sorry. Let's walk through it:</p>
|
||||||
|
<ol>
|
||||||
|
<li>The global loop asks for <code>bullet.position</code> in order to know where it should be drawn.</li>
|
||||||
|
<li><code>bullet.position</code> looks at its cached value and sees that it's out of date.</li>
|
||||||
|
<li><code>bullet.position</code> subtracts timestamps to find the time step between now and whenever it last got calculated, and remembers this as <code>time_step</code></li>
|
||||||
|
<li>The time-dependence expression is now evaluated, using the last calculated value for <code>bullet.position</code>, and fetching <code>bullet.velocity</code> as normal.</li>
|
||||||
|
</ol>
|
||||||
|
<p>Hell, why not remember the entire history of a variable's values?<span class="sidenote span4">Performance.</span> When I fetch the last calculated value for <code>bullet.position</code>, why not go ahead and make that a graph-crawling reference-calculation just like everything else?<span class="sidenote span4">Reactive time-dependence is something to think about for an interesting mechanic, if nothing else - keeping track of dependencies on history means you could change a value at any point throughout the game's history and see how it changes things... Just like <a href="http://achrongame.com">Achron</a>! And the flaws that make it seem infeasible here wouldn't be a problem in, say, a turn-based time game.</span></p>
|
||||||
|
<p>Performance is a legitimate worry at that point. If you include the full-on time-dependence, then depending on implementation you might end up following a reference back through every frame the game's been through. This approach would obviously fall apart because every value in your world is going to be at least O(t) to calculate, which sucks - there should be <em>no</em> time-dependent complexity - but there are solutions:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Careful design can ensure that your objects aren't too densely interlinked.</li>
|
||||||
|
<li>If you know you can do things more efficiently in some strenuous case, you can always hard-code it to extract current values and explicitly pass them around whenever you want.</li>
|
||||||
|
<li>Variables should carry metadata about when they last changed, and when their predecessors and descendents in the graph have changed - so that, in calculating the <code>shield</code>'s <code>position</code>, you don't re-fetch the <code>enemy.position</code>, if you know it hasn't changed.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Besides which, we have fast computers, and without running into hard algorithmic complexity problems (collision detection, I'm lookin' at you!) it's not <em>that</em> easy to overload a modern gaming machine. And hey, maybe having declarative time-dependent values is a pipe dream - I don't care. The core idea is still awesome.</p>
|
||||||
|
<p>Here's an example (with more attention paid to data types) of how I'd come up with a vector that always points to a set offset from the position of <code>bullet</code>.</p>
|
||||||
|
<pre><code>bullet.position = Wrapper(v(1,2))
|
||||||
|
offset = v(3,4)
|
||||||
|
endpoint = bullet.position + offset
|
||||||
|
print endpoint</code>
|
||||||
|
<samp>--> WrapperSum(bullet.position, offset)</samp>
|
||||||
|
<code>print endpoint.current_value</code>
|
||||||
|
<samp>--> v(4,6)</samp>
|
||||||
|
<code>bullet.position.current_value = v(-10,0)
|
||||||
|
print endpoint.current_value</code>
|
||||||
|
<samp>--> v(-7,4)</samp></pre>
|
||||||
|
<p>Once I've started thinking and talking about this, I start wondering how much we need imperative game loops at all, for anything other than those troublesome time dependencies and feedback loops. I wonder...</p>
|
||||||
|
<pre><code>print bullet.contacts</code>
|
||||||
|
<samp>--> Wrapper(List<Contacts>)</samp>
|
||||||
|
<code>contact_acceleration = sum(contact.force_to_resolve for contact in bullet.contacts)
|
||||||
|
bullet.acceleration = contact_acceleration</code></pre>
|
||||||
|
<p>Assuming that force due to contacts is the only thing present in the world, then the bullet now feels enough acceleration to resolve all the conflicts. I mean, assuming contacts are simple to work with, and they always are. Right? Right?</p>
|
||||||
|
<p>I'm thinking about this a lot because this kind of referencing is very natural for things like defining interlinks between components in my game engine - I've got conflicting interests:</p>
|
||||||
|
<ul>
|
||||||
|
<li>I want to keep my vectors and properties lightweight, so that a <code>bullet</code>'s position should just be a vector, with which I should be able to do math as freely and easily as integers.</li>
|
||||||
|
<li>But I also want to ensure that the <code>collision component</code>'s position is the same as the <code>bullet</code>'s position! I'd like to do <code>collision_comp.position = bullet.position</code></li>
|
||||||
|
<li>And then I run into the problem that since I want my vectors as primitive as possible, if I change <code>bullet.position</code> then it's not going to change <code>collision_comp.position</code> because pass-by-value is the dominant paradigm.</li>
|
||||||
|
</ul>
|
||||||
|
<p>The solution I've been working with is wrap together <em>sets</em> of related data (as <i>components</i>). The <code>player</code> object has a <code>PositionComponent</code> and a <code>CollisionComponent</code>, and the <code>CollisionComponent</code> stores a reference to the <code>player</code>'s <code>PositionComponent</code> so that it can access it at any time. Actually holding those references constant means that there would be problems if the <code>player.position_component</code> suddenly changed to a different object - but that should never happen. I'm satisfied with this for the reasons I implemented it in the first place, but it doesn't get me the dynamic interlinking I'd like from something more like functional reactive programming.</p>
|
||||||
|
<p>So I don't know. I would love to have the <em>capacity</em> for functional reactive programming in my game engines, at the least! It's so useful for making bulletproof dynamic interactive systems.</p>
|
||||||
|
</article>
|
49
articles/spinning.article.html
Normal file
49
articles/spinning.article.html
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<article>
|
||||||
|
<h1>Spinning!</h1>
|
||||||
|
<p>I like to spin. If you youtube "fire spinning", you'll find out what I mean. I haven't yet actually spun fire, but I've been spinning my glowsticks and non-fire props for several years now, and I'm pretty dang good, if I say so myself! I started spinning at the University of Virginia (props to my Brown College spinners, and the short-lived poi club!) but now, living in Somerville, Massachusetts, I spin twice a week at the Medford Spinjam (at Tufts!) and the Boston Spinjam (at MIT). Check out their facebook pages to see when and where they meet, if you want to see me (and a bunch of others!) spinning our hearts out.</p>
|
||||||
|
<section class="prop" id="staff">
|
||||||
|
<h2 class="title">Poi!</h2>
|
||||||
|
<p>Poi was the first prop I learned. Once I managed to do a three-beat weave, I zoned out until my partner poked me that they were tired, and I realized that I was completely pooped, as I'd just spun for three hours without even thinking about it. That was in 2011, and I've been spinning poi off-and-on (and other props!) since then.</p>
|
||||||
|
<p>I like poi becasue it's relaxing. I can get into it and just spin for hours, and let the prop guide my movements. Gets boring, though!</p>
|
||||||
|
<p>Here's a list of the tricks I can do. If you don't spin a lot, feel free to ignore this. If you do, I apologize for the ones I have kooky names for.</p>
|
||||||
|
<ul class="tricks">
|
||||||
|
<li>In-plane spinning</li>
|
||||||
|
<li>Turns</li>
|
||||||
|
<li>Butterfly</li>
|
||||||
|
<li>Thread the Needle (forward only)</li>
|
||||||
|
<li>Pac-Man Twist</li>
|
||||||
|
<li>3-beat Weave</li>
|
||||||
|
<li>Weave extensions</li>
|
||||||
|
<li>Wrap-beat weave</li>
|
||||||
|
<li>5-beat Weave (forward only)</li>
|
||||||
|
<li>Reels</li>
|
||||||
|
<li>Chasing the Moon, Chasing the Sun, Moon Chasing Sun</li>
|
||||||
|
<li>Chasing where the Sun Don't Shine (same time only)</li>
|
||||||
|
<li>Windmills</li>
|
||||||
|
<li>Air Wraps</li>
|
||||||
|
<li>All manner of bicep wraps and leg wraps</li>
|
||||||
|
<li>Spiral wraps</li>
|
||||||
|
</ul>
|
||||||
|
<p>I spin a pair of flowlights with crystal cases. I've got the Sol coloration, and I love them dearly (although they have a tendency to turn off at the wrong times). I'm hoping to get a pair of Spectrum flowlights, or possibly build my own. I also have a pair of tailed poi I need to fix - they're so fun to spin!</p>
|
||||||
|
<p>Someday I'd like to build a pair of accelerometer-powered glowpoi - they could change color depending on the acceleration they're feeling. When you're spinning in a circle, that's directly dependent on speed - it could make for really nifty effects!</p>
|
||||||
|
</section>
|
||||||
|
<section class="prop" id="staff">
|
||||||
|
<h2 class="title">Staff!</h2>
|
||||||
|
<p>Since the end of 2012 I've also been very into spinning staff. I use a full-length staff that I made myself for super cheap - it's heavy as a car, but it's balanced alright. I spin a mix of traditional and contact staff, because what else would I do?</p>
|
||||||
|
<p>I like spinning staff because it's <em>fun</em>. Poi is relaxing, meditative; staff is, to me, much more energetic. I feel like I'm getting to play with this giant whirling toy, whereas with poi I feel like I'm guided by the inertia of the props.</p>
|
||||||
|
<p>Here's a (partial) list of tricks I can do:</p>
|
||||||
|
<ul class="tricks">
|
||||||
|
<li>Rotors</li>
|
||||||
|
<li>Weaves up to 5 beats (I think)</li>
|
||||||
|
<li>Half-Steves (right-to-left consistently, shakier on left-to-right)</li>
|
||||||
|
<li>Halos</li>
|
||||||
|
<li>Angel Rolls (only right-to-left)</li>
|
||||||
|
<li>Shoulder-Neck-Shoulder</li>
|
||||||
|
<li>Neck wraps, shoulder wraps</li>
|
||||||
|
<li>Fishtails (forward only, right hand only)</li>
|
||||||
|
<li>Rainbow Stalls</li>
|
||||||
|
<li>Conveyor Belts</li>
|
||||||
|
</ul>
|
||||||
|
<p>I'd like to learn to spin a dragon staff someday.</p>
|
||||||
|
</section>
|
||||||
|
</article>
|
9
articles/spinning.template.html
Normal file
9
articles/spinning.template.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "articles/article.template.html" %}
|
||||||
|
|
||||||
|
{% block title -%}
|
||||||
|
I spin things around!
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{% block body -%}
|
||||||
|
{%- include "articles/spinning.article.html" -%}
|
||||||
|
{%- endblock %}
|
66
articles/tamari.article.html
Normal file
66
articles/tamari.article.html
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<article class="project">
|
||||||
|
<h1>Tamari Lattices!</h1>
|
||||||
|
<p>Tamari lattices are graphs (in the mathematical sense - a set of nodes with connections between them) describing a particular set of operations. I like them because they're pretty!</p>
|
||||||
|
<figure>
|
||||||
|
<img src="/static/tamari/tamari_3.png" alt="The (trivial) Tamari lattice for a three-element tree.">
|
||||||
|
<figcaption>A (trivial) Tamari lattice, generated by the associations of three elements. <a class="source" href="/static/tamari/tamari_3.dot">Source file.</a></figcaption>
|
||||||
|
</figure>
|
||||||
|
<p>Oh - oh dear. How'd that get there? Okay, that's not a very good example.</p>
|
||||||
|
<p>There are many ways to generate and think of a Tamari lattice. The way I prefer to think of it is this: Consider some binary operation - you take two elements to produce a new one. You want to combine several of these elements. So long as you have three or more elements, there are multiple ways to combine them.</p>
|
||||||
|
<p>The game we play is this: You're allowed to step from one way of combining the elements to another, but only by <i class="keyword">left-association</i>: turning <code>(a, (b, c))</code> into <code>((a, b), c)</code>.</p>
|
||||||
|
<p>The only remaining rule is that if you can step from one combination to another, the second one has to appear below the first one when you draw it.</p>
|
||||||
|
<figure>
|
||||||
|
<img src="/static/tamari/tamari_4.png" alt="A Tamari lattice for a four-element tree.">
|
||||||
|
<figcaption>As above, but generated by a four-element tree. <a class="source" href="/static/tamari/tamari_4.dot">Source file.</a></figcaption>
|
||||||
|
</figure>
|
||||||
|
<p>You can also think about it in terms of <a href="http://wikipedia.org/wiki/Tree_rotation">tree rotations</a> - but remember that that's a different tree than the one we're building as the Tamari lattice. Tree rotations are just another way to think of left-association and right-association.</p>
|
||||||
|
<p>If you look at <a href="http://wikipedia.org/wiki/Tamari_lattice">the wikipedia article on Tamari lattices</a>, you'll see a very pretty image:</p>
|
||||||
|
<img src="http://upload.wikimedia.org/wikipedia/commons/4/46/Tamari_lattice.svg">
|
||||||
|
<p>There are a lot of ways to reorganize a Tamari lattice, and it takes some artistic work to make one that really looks good. You can even visualize the same graph as <a href="http://en.wikipedia.org/wiki/Associahedron">a 3D shape called an "associahedron"</a>, but I like it in the simple gridded lattice form above. It reminds me how much beauty there can be in regularity - you can see the grid, but it doesn't look constrained by it. I might get a tattoo of the five-element Tamari lattice someday.</p>
|
||||||
|
<figure>
|
||||||
|
<img src="/static/tamari/tamari_5.png" alt="Tamari lattice for a five-element tree.">
|
||||||
|
<figcaption>Also the five-element lattice! Compare to the <a href="http://wikipedia.org/wiki/Tamari_lattice">example above, on wikipedia.</a>. <a class="source" href="/static/tamari/tamari_5.dot">Source file.</a></figcaption>
|
||||||
|
</figure>
|
||||||
|
<p>All these graphs with the ovals and the curvy lines were generated by yours truly! I made some python that would take a string representation of an association of a number of elements and convert it into an easily-manipulated memory representation. Then, a few tree rotations spit out all the possible results of left-associating on it, and it was relatively simple to print out a <code>.dot</code> file, parseable by <a href="http://www.graphviz.org/">graphviz</a>, that described the graph. It even labeled the nodes!</p>
|
||||||
|
<p><code>dot</code> happily converted them into the <code>png</code> files you're looking at. Of course, they don't have the human touch, so they're not organized into beautiful grid lines and 45° angles - but it can be fun to try to mentally reorganize them into a nicer shape. If you want, you can download the <code>.dot</code> source files for any of these, and play around with them in a graph-editing program (such as <a href="https://github.com/jrfonseca/xdot.py">XDot</a>)</p>
|
||||||
|
<figure>
|
||||||
|
<img src="/static/tamari/tamari_6.png" alt="Tamari lattice for a six-element tree.">
|
||||||
|
<figcaption>It's starting to get out of hand, I think.<a class="source" href="/static/tamari/tamari_6.dot">Source file.</a></figcaption>
|
||||||
|
</figure>
|
||||||
|
<p>Unfortunately, at a certain point I think it's going to get difficult to make these pretty. It turns out there are a lot of ways to associate a larger number of elements! Starting with a six-element tree or string, there are 42 elements (above). With seven, there are 132! Wowie!</p>
|
||||||
|
<figure>
|
||||||
|
<img src="/static/tamari/tamari_7.png" alt="Tamari lattice for a seven-element tree.">
|
||||||
|
<figcaption>Oh dear. <a class="source" href="/static/tamari/tamari_7.dot">Source file.</a></figcaption>
|
||||||
|
</figure>
|
||||||
|
<p>My server was chugging along trying to generate <code>tamari_8.dot</code> but I started getting messages from linode about going over my CPU quotas, so I canceled it - after it ran for an hour or so, without finishing. I think the seven-element one is messy-looking enough!</p>
|
||||||
|
<p>You can look at the <a class="source" href="/static/tamari/tamari.py">python script</a> I used to make this, but it's not particularly pretty - I was bored one day and decided I was going to figure out how to generate these... It's not exactly meant to be extensible. It's got a basic binary tree node class I threw together for working the association rules and a handful of (really ugly) helper functions. I just went through and rewrote it a bit to be nicer - the final output loop may please you if you enjoy <code>set</code>s and list comprehensions:</p>
|
||||||
|
<pre>
|
||||||
|
<code class="language-python">current_generation = set()
|
||||||
|
next_generation = {RootOfAllEvil}
|
||||||
|
edges = set()
|
||||||
|
labels = set()
|
||||||
|
|
||||||
|
while next_generation: # While there are trees to examine.
|
||||||
|
# Move to look at the next generation.
|
||||||
|
current_generation = next_generation
|
||||||
|
|
||||||
|
# Clear out the next gen to fill it with the children of this generation.
|
||||||
|
next_generation = set()
|
||||||
|
|
||||||
|
# Ensure there are labels for this generation.
|
||||||
|
labels = labels | set(label_from_node(parent) for parent in current_generation)
|
||||||
|
|
||||||
|
for parent in current_generation:
|
||||||
|
children = generate_children(parent)
|
||||||
|
|
||||||
|
labels = labels | set(label_from_node(child) for child in children)
|
||||||
|
edges = edges | set(str(parent) + " -> " + str(child) + ";" for child in children)
|
||||||
|
next_generation = next_generation | children
|
||||||
|
|
||||||
|
# Output a dot-formatted stream!
|
||||||
|
args.output.write(u"digraph tamari {\n")
|
||||||
|
args.output.write(u"\n".join(labels) + "\n")
|
||||||
|
args.output.write(u"\n".join(edges))
|
||||||
|
args.output.write(u"\n}\n")</code></pre>
|
||||||
|
<p>The full script can be used by running <code class="language-bash">python tamari.py --length 4 | dot -Tpng > output.png</code> to produce a graph. <code>tamari.py</code> will print out to a specified file if you also include a filename: <code class="language-bash">python tamari.py --length 5 output.dot</code></p>
|
||||||
|
</article>
|
9
articles/tamari.template.html
Normal file
9
articles/tamari.template.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{% extends "articles/article.template.html" %}
|
||||||
|
|
||||||
|
{% block title -%}
|
||||||
|
Tamari Lattices: very pretty.
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{% block body -%}
|
||||||
|
{%- include "articles/tamari.article.html" -%}
|
||||||
|
{%- endblock %}
|
35
articles/time_integration.article.html
Normal file
35
articles/time_integration.article.html
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h1>Time Integration</h1>
|
||||||
|
</header>
|
||||||
|
<p>I find myself writing cooldowns and countdowns all the time. Bullets can only fire so fast, bombs explode after five seconds, enemies spawn every 10-15 seconds. Every time I do it, I write the same boilerplate in the initialization:</p>
|
||||||
|
<pre><code>goomba.cooldown_max = 5 // 5 seconds to cool down
|
||||||
|
goomba.cooldown_timer = goomba.cooldown_max</code></pre>
|
||||||
|
<p>and the same boilerplate in the update function:</p>
|
||||||
|
<pre><code>if goomba.cooldown_timer > 0:
|
||||||
|
goomba.cooldown_timer -= time_step
|
||||||
|
if goomba.cooldown_timer < 0:
|
||||||
|
// insert end behavior here</code></pre>
|
||||||
|
<p>and somewhere, I activate this behavior (in response to a keypress, or proximit, or contact):</p>
|
||||||
|
<pre><code>goomba.cooldown_timer = goomba.cooldown_max</code></pre>
|
||||||
|
<p>I do this kind of thing so often that I feel like it should be one of the basic functionalities offered when I'm trying to describe game entity behavior.</p>
|
||||||
|
<pre><code>// initialization
|
||||||
|
goomba.shot_timer = new CooldownTimer(length=5s, on_end=function() {...})
|
||||||
|
// update functionality should be taken care of automatically, but if not:
|
||||||
|
goomba.shot_timer.step(time_step)
|
||||||
|
// activating the timer:
|
||||||
|
goomba.shot_timer.start()</code></pre>
|
||||||
|
<p>Now, wasn't that easy?</p>
|
||||||
|
<p>Of course, that's a pretty simple case! There are obvious extensions, though:</p>
|
||||||
|
<pre><code>goomba.blink_timer = new EndlessTimer()
|
||||||
|
goomba.blink_timer.interval = 5s
|
||||||
|
goomba.blink_timer.at_progress(0%, goomba.change_color) // change color at the start of each interval
|
||||||
|
goomba.blink_timer.at_progress(50%, goomba.take_step) // take a step once every interval halfway through</code></pre>
|
||||||
|
<p>And now making timed behavior for our goomba is easy! We can even speed up the goomba easily: <code>goomba.blink_timer.interval = 3s</code></p>
|
||||||
|
<p>Ideally, you don't need to even specify when to <code>step</code> your timers - that should be taken care of automatically. Of course, that means we'd want to <em>register</em> these timers instead of simply declaring them as a member - but maybe that's a matter of a grander architectural problem.</p>
|
||||||
|
<p>Although! If we <em>do</em> let the developer take care of stepping the timers, then we can also use it for things that <em>aren't</em> time-dependent:</p>
|
||||||
|
<pre><code>player.limit_bar = new Meter(length=100) // general verison of the CooldownTimer
|
||||||
|
player.on('hit by enemy', player.limit_bar.step)
|
||||||
|
player.limit_bar.at_progress(100%, player.limit_break)</code></pre>
|
||||||
|
<p>And now we've got a way for limit breaks to engage. Assuming there's a pre-existing event system and everything is architected carefully, it's now incredibly easy to fill meters in response to events.</p>
|
||||||
|
</article>
|
@ -1,305 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>How should this website be laid out?</title>
|
|
||||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
|
||||||
<link href="../static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
|
||||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<style type="text/css">
|
|
||||||
#server-choices colgroup { width: 20%; }
|
|
||||||
#server-choices tr { height: 3em; }
|
|
||||||
#server-choices tr>td { text-align: center; }
|
|
||||||
#server-choices tr>td:first-child {
|
|
||||||
text-align: left;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<article class="project">
|
|
||||||
<h1>Shit, I better make this server work.</h1>
|
|
||||||
<h3>On the layout of folders and files!</h3>
|
|
||||||
<p>Basically I'm not sure how I should lay out this website. The current organization looks something like this:</p>
|
|
||||||
<ul class="file-tree">
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">server/</span> (server root)
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">pages/</span> (articles with nice links)
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span> (accessed as <span class="url">http://example.com/auriga/</span>)</li>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">language_for_games.html</span> (<span class="url">http://example.com/language-for-games/</span>)</li>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span> (<span class="url">http://example.com/tamari/</span>)
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">static/</span>
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-eye-open"></i> <span class="filename">stylesheet.css</span> (global stying)</li>
|
|
||||||
<li><i class="icon-picture"></i> <span class="filename">favicon.ico</span></li>
|
|
||||||
<li><i class="icon-picture"></i> <span class="filename">banner.png</span></li>
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">tamari/</span> (files for an article)
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-picture"></i> <span class="filename">figure_1.png</span></li>
|
|
||||||
<li><i class="icon-picture"></i> <span class="filename">figure_2.png</span></li>
|
|
||||||
<li><i class="icon-signal"></i> <span class="filename">experiment_data.csv</span></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>This has a number of problems. First and foremost, barely any thought has gone into naming of folders and files - which is because not much thought has gone into their placement and hierarchy.</p>
|
|
||||||
<p>The server is written using <a href="http://flask.pocoo.org">Flask</a>, and this is the rundown on how it works when a user goes to <span class="url">http://example.com/some-path/</span>:</p>
|
|
||||||
<ol>
|
|
||||||
<li>If the path requested is the root of the website, render <span class="filename">main_page.html</span>.</li>
|
|
||||||
<li>If the path requested begins with <span class="url">static/</span>, render a file from the static content directory.</li>
|
|
||||||
<li>Else, convert the path (<span class="url">some-path</span>) into the filename (<span class="filename">pages/some_path.html</span>) assuming it's an article. If it exists, render it.</li>
|
|
||||||
<li>If there's no article by that name, display the miscellaneous articles page. Or 404. The current behavior isn't very high on my priorities.</li>
|
|
||||||
</ol>
|
|
||||||
<p>There are a bunch of problems with this system - it's kind of brittle, file paths have the meaningless-to-the-user <span class="url">static/</span> at the beginning, and it means that when I include a resource in <span class="url">http://example.com/tamari/</span> (the file <span class="filename">pages/tamari.html</span>) I have to use a path like <span class="url">../static/tamari/figure_1.png</span> - when I should be able to reference files related to the Tamari article by a closely-related URL: <span class="url">./figure_1.png</span>.</p>
|
|
||||||
<p>All this points to the idea of having my articles be in folders, so it would look something like this:</p>
|
|
||||||
<ul class="file-tree">
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">server/</span> (server root)
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">articles/</span> (articles with nice links)
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">auriga/</span>
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">language-for-games/</span>
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">language_for_games.html</span></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">tamari/</span>
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span></li>
|
|
||||||
<li><i class="icon-picture"></i> <span class="filename">figure_1.png</span></li>
|
|
||||||
<li><i class="icon-picture"></i> <span class="filename">figure_2.png</span></li>
|
|
||||||
<li><i class="icon-signal"></i> <span class="filename">experiment_data.csv</span></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">static/</span>
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-eye-open"></i> <span class="filename">stylesheet.css</span> (global stying)</li>
|
|
||||||
<li><i class="icon-picture"></i> <span class="filename">favicon.ico</span></li>
|
|
||||||
<li><i class="icon-picture"></i> <span class="filename">banner.png</span></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>And hell, at this point having the filenames match the folders (<span class="filename">auriga/auriga.html</span>) is just a pain, so we could name the main page in each folder <span class="filename">index.html</span>, and suddenly this looks very standard. So why don't I do this?</p>
|
|
||||||
<p>Well... I don't know. But something always bothered me about the <span class="filename">index.html</span> standard. Maybe it's just that my article about Tamari lattices <em>isn't</em> an index, so I don't think it should be called one. That's certainly part of it. Also, some of my articles and pages are going to be very short - in theory I'd like them to be able to be tiny snippets, which could be included on other pages. It'd be annoying to have a subfolder for every single article I write! But... maybe not <em>too</em> annoying. I'll have to think about that.</p>
|
|
||||||
<hr>
|
|
||||||
<h3>But what are we <em>doing</em>?</h3>
|
|
||||||
<p>What would my ideal web framework be? Well, something like Flask, really. I like flask because this is easy:</p>
|
|
||||||
<pre>
|
|
||||||
<code class="language-python">@app.route("<span class="url">/some-convoluted/url/<options>/with-stuff/</span>")
|
|
||||||
def render_shoofle_page(options=None):
|
|
||||||
if options == "bananas":
|
|
||||||
return render_page("<span class="filename">bananas.html</span>")
|
|
||||||
else:
|
|
||||||
return render_page("<span class="filename">some_other_template.html</span>", options=options)</code></pre>
|
|
||||||
<p>And, lo and behold, I can go to <span class="url">example.com/some-convoluted/url/bananas/with-stuff/</span> and see the right generated page! I like having that capacity at my fingertips. In particular, it makes it easy to respond to various other kinds of requests. That's what I really like about Flask - I feel like I can do <em>everything</em> a webserver can do, but it all takes the same very small amount of work. This compares to, say, PHP, where it's easy to make pages... But more complicated behavior, especially anything involving dynamic URL paths, involves jumping through hoops.<span class="sidenote span4">It might seem like an overblown complaint, but the integrity of my mental models is important to me - and in PHP, I don't understand what gets sent to the requestor. If I make a Flask route returning JSON, I know it's exactly what a script wants. With PHP, I would <em>hope</em> that it wouldn't have weird headers or content type or additional markup.</span> Plus, you have to work with PHP, which I would wish on no one.</p>
|
|
||||||
<p>I don't like Flask because I need to specify all the behaviors, and I'm worried that I'll get it wrong (thus, this article).</p>
|
|
||||||
<p>My ideal world solution would be something that lets me pass requests for subpaths to other python modules:<p>
|
|
||||||
<ul class="file-tree">
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">server/</span>
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-file"></i> <span class="filename">server.py</span></li>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">articles/</span>
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-file"></i> <span class="filename">articles.py</span></li>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span></li>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">language-for-games.html</span></li>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">games/</span>
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-file"></i> <span class="filename">games.py</span></li>
|
|
||||||
<li><i class="icon-signal"></i> <span class="filename">scores.csv</span></li>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">play_the_game.html</span></li>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">game.js</span></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>Aaaand how it works would be simple:</p>
|
|
||||||
<ol>
|
|
||||||
<li>A request comes in to <span class="url">http://example.com/tamari/</span>, and it is handled by <span class="filename">server.py</span>.</li>
|
|
||||||
<li><span class="filename">server.py</span> says "Okay, I don't have any specific handlers that do anything with this URL, but I think <span class="filename">articles/articles.py</span> does!" and sends the request to <span class="filename">articles.py</span>.</li>
|
|
||||||
<li><span class="filename">articles.py</span> receives a request for <span class="url">/tamari/</span> and has a rule for handling that, and so it renders the appropriate HTML file.</li>
|
|
||||||
</ol>
|
|
||||||
<p>The basic idea is that requests can be routed to other python modules. If those modules can be reloaded easily (or automatically!), this would mean I could write complicated URL handling in subdirectories of my website - without having to touch any of the code that handles anything else. It means I can modularize - and that's <em>awesome</em>.</p>
|
|
||||||
<ol>
|
|
||||||
<li>An HTTP GET request comes in to <span class="url">http://example.com/games/points</span>, and <span class="filename">server.py</span> takes it.</li>
|
|
||||||
<li><span class="filename">server.py</span> doesn't know what to do with it, but it knows that requests for URLs starting with <span class="url">/games</span> should be handled by <span class="filename">games/games.py</span>.</li>
|
|
||||||
<li><span class="filename">games.py</span> receives an HTTP GET request for <span class="url">/games/points</span>, and so it can respond to this with a JSON object that tells the requestor how many points they got.</li>
|
|
||||||
</ol>
|
|
||||||
<p>This is the main point of the tiered handlers system - that I can write handlers for all kinds of requests, without having to interact with other parts of my website.</p>
|
|
||||||
<p>Basically, I want to combine the simple directory structure of PHP websites with the principles of Flask I really like - separating content from server logic, keeping things simple, and having control.</p>
|
|
||||||
<p>Here's how I imagine this would work:</p>
|
|
||||||
<pre>
|
|
||||||
<code>from flask import Flask, render_template, redirect
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
|
|
||||||
def main_page(): return render_template("<span class="filename">main.html</span>")
|
|
||||||
app.add_url_rule("<span class="url">/</span>", main_page)
|
|
||||||
|
|
||||||
import games
|
|
||||||
app.add_module_url_rule("<span class="url">/games/<path:rest></span>", games)</code></pre>
|
|
||||||
<p>As usual, don't think too hard about the syntax I just proposed. The point is to distribute URL routing logic throughout multiple files, so that my entire website isn't controlled by one brutalistic overlord <span class="filename">server.py</span> file that decrees the entire path of every request. I want things split up, dammit!</p>
|
|
||||||
<hr>
|
|
||||||
<p>Now I'm reading up on the Flask docs, and it turns out that it already has the capacity for this. Unfortunately, it's complicated and I'm <em>whiiiny</em>.</p>
|
|
||||||
<p>It seems that Flask provides the developer with three options:</p>
|
|
||||||
<ul>
|
|
||||||
<li>Package Organization: Essentially, break up your server code, like configuration and URL route assignment, into separate files. This doesn't actually solve any of my issues - most of what this does (as far as I can tell) is separate the server initialization logic from the routing and response logic. Plus, it makes it easier to use your application in something else. More on this soon.</li>
|
|
||||||
<li>Blueprints: Very close to what I want. I could define a Blueprint object in <span class="filename">articles.py</span>. This Blueprint object would register all the routes and endpoints that I want to register - and then, when the server starts, it gets all of those from the blueprint. This means we can <em>actually</em> factor views out. I'm really not sure, though, what this affords that the organizing your application as a package doesn't.</li>
|
|
||||||
<li>Application Dispatching: The most powerful of the three! This is a slightly lower-level solution, wherein you actually run multiple applications concurrently, and dispatch requests to them. This is kind of overkill, but at least it's nice to know that it's possible - things like the <span class="url">async_app</span> example from previous could really make sense, if the app is large enough in scope. Application dispatching means you can just pull in another application and route things to it on the WSGI layer. Or something.</li>
|
|
||||||
</ul>
|
|
||||||
<p>Okay, but... how do they score up? I have some requirements:</p>
|
|
||||||
<dl>
|
|
||||||
<dt>Organization</dt>
|
|
||||||
<dd>I want to define the behavior for <span class="url">example.com/articles/tamari/</span> in the same place as <span class="url">example.com/articles/language-for-games/</span> is defined, but in a different file from where <span class="url">example.com/games/hunt-the-wumpus</span> is defined.</dd>
|
|
||||||
<dt>Simplicity</dt>
|
|
||||||
<dd>Defining a URL route and endpoint for each subfolder of my application shouldn't be much more complicated than defining behaviors in a flat system. Ideally, registering all the behaviors for the <span class="url">articles/</span> subpath is no more complicated than <code>app.route("<span class="url">/articles/</span>", articles_handler)</code></dd>
|
|
||||||
<dt>Ease of Extension</dt>
|
|
||||||
<dd>I'm writing a family of pages. They're starting to get a little too complicated. It should be really easy to go from that situation to having a nicely-delineated subsection of my website.</dd>
|
|
||||||
<dt>Do I <em>Need</em> to Restart the Server?</dt>
|
|
||||||
<dd>I hate restarting the server. Maybe this is a little thing, but gah! I want the server to detect changes automatically! This shouldn't be that hard. Of course, this is a much thornier topic when it comes to subpages that might store their own state... So it might be out the window unless I want to get my hands <em>way</em> more dirty.</dd>
|
|
||||||
</dl>
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row-fluid">
|
|
||||||
<table id="server-choices" class="span8 offset2">
|
|
||||||
<caption><h4>How do they fare up?</h4></caption>
|
|
||||||
<col><colgroup span=4></colgroup>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th></th>
|
|
||||||
|
|
||||||
<th>Organization</th>
|
|
||||||
<th>Simplicity</th>
|
|
||||||
<th>Ease of Extension</th>
|
|
||||||
<th>No Restart Required?</th>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>Current</td>
|
|
||||||
|
|
||||||
<td class="label-warning"><i class="icon-question-sign"></i></td>
|
|
||||||
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
|
||||||
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
|
||||||
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Organize as a Package</td>
|
|
||||||
|
|
||||||
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
|
||||||
<td class="label-warning"><i class="icon-question-sign"></i></td>
|
|
||||||
<td class="label-warning"><i class="icon-question-sign"></i></td>
|
|
||||||
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Blueprints</td>
|
|
||||||
|
|
||||||
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
|
||||||
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
|
||||||
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
|
||||||
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Application Dispatch</td>
|
|
||||||
|
|
||||||
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
|
||||||
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
|
||||||
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
|
||||||
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div></div>
|
|
||||||
<p>In light of this chart, it seems like Blueprints are the clear option. Also, "organize as package" is really vague. What they suggested didn't sound very helpful - but making python packages (finally learning how to use <span class="filename">__init__.py</span> files!) will probably get used in the solution I'm thinking I'll use, which looks something like this:</p>
|
|
||||||
<ul class="file-tree">
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">server/</span>
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-file"></i> <span class="filename">server.py</span></li>
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">articles/</span>
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-file"></i> <span class="filename">article_routing_blueprint.py</span></li>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span></li>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">language-for-games.html</span></li>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span></li>
|
|
||||||
<li><i class="icon-folder-close"></i> <span class="filename">tamari_files</span></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">games/</span>
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-file"></i> <span class="filename">games_blueprint.py</span></li>
|
|
||||||
<li><i class="icon-signal"></i> <span class="filename">scores.csv</span></li>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">play_the_game.html</span></li>
|
|
||||||
<li><i class="icon-align-left"></i> <span class="filename">game.js</span></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li><i class="icon-folder-open"></i> <span class="filename">static/</span>
|
|
||||||
<ul>
|
|
||||||
<li><i class="icon-picture"></i> <span class="filename">favicon.ico</span></li>
|
|
||||||
<li><i class="icon-eye-open"></i> <span class="filename">stylesheet.css</span></li>
|
|
||||||
<li><i class="icon-picture"></i> <span class="filename">lol_a_cat.jpg</span></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>If there's static content that is globally important, with simple routing rules, it can - of course - be stored in the server root's <span class="filename">static/</span> directory. Static file handlers don't take much configuration, so this can go in the root.</p>
|
|
||||||
<p>All the files related to articles are contained in the <span class="filename">articles/</span> directory, or subdirectories. <span class="filename">article_routing_blueprint.py</span> contains a blueprint definition that tells the server how to route calls that result in the rendering of the various articles I've written.</p>
|
|
||||||
<p>All files related to the little javascript games I've made, on the other hand, go in the <span class="filename">games/</span> directory. State for this application is managed by <span class="filename">games_blueprint.py</span>, which is sort of like a very tiny application. I think it's possible to keep track of state, if you remember to keep variables global... This is tricksy, but should be doable - and if it gets larger, it should almost certainly be developed as a separate application entirely. At that point, I should figure out how to include multiple applications in one website!</p>
|
|
||||||
<p>I want to finish this bit by writing down some code for the base <span class="filename">server.py</span> logic:</p>
|
|
||||||
<pre>
|
|
||||||
<code class="language-python">from flask import Flask
|
|
||||||
|
|
||||||
# app configuration and initialization
|
|
||||||
app = Flask(__name__)
|
|
||||||
app.debug = True
|
|
||||||
|
|
||||||
# content in <span class="filename">articles/</span>
|
|
||||||
import articles
|
|
||||||
app.register_blueprint(articles.blueprint)
|
|
||||||
|
|
||||||
# content in <span class="filename">games/</span>
|
|
||||||
import games
|
|
||||||
app.register_blueprint(games.blueprint, url_prefix="<span class="url">/games</span>")</code></pre>
|
|
||||||
<hr>
|
|
||||||
<h3>Okay, one last thing.</h3>
|
|
||||||
<p>This has been a lot about how to get some basic extensible functionality working. <i class="that-guy">But wait</i>, someone cries in the distance! <i class="that-guy">Why are we going to such lengths to do all this in the first place, when you're just serving static HTML files? Isn't this way more work than you need?</i><span class="sidenote span4">In case you're reading this article long after I've finished these changes (I hope so, 'cause I should get to work on this immediately), at this point all the articles were static HTML files. That voice speaks the truth.</span></p>
|
|
||||||
<p>Thanks for asking. The answer is that I want to change how this site is structured, and the articles are the specific thing I want to change. See, as it is, each article has basically the same header at the top, and basically the same footer at the bottom, and... Well, they're just all enclosed in the same stuff, and so when I change the styling of the website - or, horror of horrors, try to add a sidebar across the hwole site - I have to change all of them! And, as I think we've been over before, I'm <em>lazy</em>.</p>
|
|
||||||
<p>Conveniently, as I've been obsessively reading discussions of standards-compliant HTML5 and document formats and such lately, this laziness messes with my indomitable enthusiasm for conceptually pleasing solutions. Here's what I've got:</p>
|
|
||||||
<ul>
|
|
||||||
<li><b>Articles</b> on my site are blocks of text, consisting of my rambling on some topic. Something I've written down. They can have some amount of associated content, but for the most part they're just text. So, I'm going to reduce them down to their bare minimum of unique content - in many cases, just an <code language="html"><article></code> tag containing what I wrote!</li>
|
|
||||||
<li>But sometimes I want to have multiple articles display in one page! Sometimes my articles are single paragraphs. Sometimes they can be grouped into related, uh, groups! What do we do then? The answer is <strong>templates</strong>. Flask uses <a href="http://jinja.pocoo.org/">Jinja2</a>, a perfectly nice templating engine - and why not use it?</li>
|
|
||||||
<li>If I want to display the articles contained in <span class="filename">articles/parkour_is_awesome.html</span>, <span class="filename">articles/exercise.html</span>, and <span class="filename">articles/how_is_body.html</span>), then I just make a new page, a Jinja2 template, which contains this:
|
|
||||||
<pre>
|
|
||||||
<code class="language-jinja2"><!--{{ "-->{%<!--" }}--> include "<span class="filename">articles/parkour_is_awesome.html</span>" <!--{{ "-->%}<!--" }}-->
|
|
||||||
<!--{{ "-->{%<!--" }}--> include "<span class="filename">articles/exercise.html</span>" <!--{{ "-->%}<!--" }}-->
|
|
||||||
<!--{{ "-->{%<!--" }}--> include "<span class="filename">articles/how_is_body.html</span>" <!--{{ "-->%}<!--" }}--></code></pre>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>And ta-da! We now have a page which has those three articles in a row.</p>
|
|
||||||
<p>This, of course, also means we have a neat format for how to display things in general. Someone requested access to a URL! Find the file it points to. If it's an HTML fragment, then point the <b>general page template</b> to that file, and render. The general page template is just a template that adds the header, footer, sidebar, universal styling, and so on, as required, for universality.</p>
|
|
||||||
<p>So if you go to <span class="url">example.com/tamari/</span>, the server says "Okay, you want to look at the article in the HTML fragment file <span class="filename">articles/tamari.html</span>." It renders the general page template around that article, and returns that to the user.</p>
|
|
||||||
<p>Because I like having the option to look at these things many ways, I'm probably also going to allow for a user to do <code class="language-bash">python articles.py --generate [path]</code>, which will simply spit out the the rendered results of going to <code class="language-bash">[path]</code>. I guess that <em>might</em> just be indistinguishable from using <code class="language-bash">wget</code>, but hey. It can't hurt to give more functionality!</p>
|
|
||||||
<p>It remains to be seen precisely how many pages on this site will use the general page template. I don't want to rely on it too much, but, man, is there <em>any</em> reason not to? Basically, it means that I don't have to worry about writing the headers of anything on my website. I guess I'll need to be able to throw it off when I'm making subpages that are intended to be stylistically distinct from the rest of my site.</p>
|
|
||||||
</article>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,150 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>A Language for Games</title>
|
|
||||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
|
||||||
<link href="../static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
|
||||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<p>I like making games but sometimes I spend a lot of time doing stuff that is just annoying. What if a language or environment were designed to make those things easy?</p>
|
|
||||||
<hr>
|
|
||||||
<article class="project">
|
|
||||||
<header>
|
|
||||||
<h1>Snorlax Evaluation</h1>
|
|
||||||
<p>(define-by-reference, or: lazy evaluation taken to extremes)</p>
|
|
||||||
</header>
|
|
||||||
<p>Okay, so I've got a <code>Bomb</code> entity in my game. It's already got the behavior for flying toward its <code>destination</code>. What if I want to make a <code>SmartBomb</code> that tracks a target even if they move? I might do it something like this:</p>
|
|
||||||
<pre><code>SmartBomb.on_update = function (timestep) {
|
|
||||||
// other update behaviors go in this function as well
|
|
||||||
this.destination = target.position
|
|
||||||
}</code></pre>
|
|
||||||
<p>I have to explicitly tell my engine to execute this every frame. I think in terms of this kind of thing already, because I'm a math and physics person. Why can't I define relationships like this more simply? What if, in fact, this was the default way we referred to values? <span class="sidenote span4">It's worth noting that what I've thought of here is essentially just <a href="https://en.wikipedia.org/wiki/Functional_reactive_programming">functional reactive programming</a>. You can go read wikipedia if you want.</span></p>
|
|
||||||
<pre><code>SmartBomb.destination = target.position</code></pre>
|
|
||||||
<p>Any time something fetches the value of <code>SmartBomb.destination</code> it'll fetch the value of <code>target.position</code>. Writing it this way, instead of explicitly specifying which variables need to be kept up-to-date with other variables (and when they need to be updated!), means it's easier to give variables interesting dependencies on other values - like this <code>shield</code> which should float a certain distance between the <code>player</code> and the <code>enemy</code>:</p>
|
|
||||||
<pre><code>shield.position = player.position + shield.distance * unit_vector(enemy.position - player.position)</code></pre>
|
|
||||||
<p>If and when you <em>do</em> need to store something's value at a specific time, you can do that if you want - for example, this code when a bomb explodes:</p>
|
|
||||||
<pre><code>explosion_location = current_value(bomb.position)
|
|
||||||
// or maybe the syntax is like this:
|
|
||||||
explosion_location = bomb.position.current_value</code></pre>
|
|
||||||
<p>So far, everything's time-independent. For example, the <code>shield</code> object's <code>position</code> depends only on the positions of other objects.</p>
|
|
||||||
<p>Why not include time-dependence? A <code>bullet</code> has a <code>position</code> and a <code>velocity</code>, and these are related in a way that doesn't change at any point during gameplay. Why not codify that relationship in a similar way?</p>
|
|
||||||
<pre><code>bullet.position = bullet.position + time_step * bullet.velocity
|
|
||||||
// or maybe
|
|
||||||
bullet.position = bullet.position + bullet.position.time_since_last_calculation * bullet.velocity</code></pre>
|
|
||||||
<p>Okay, if this seems like impossible magic, I'm sorry. Let's walk through it:</p>
|
|
||||||
<ol>
|
|
||||||
<li>The global loop asks for <code>bullet.position</code> in order to know where it should be drawn.</li>
|
|
||||||
<li><code>bullet.position</code> looks at its cached value and sees that it's out of date.</li>
|
|
||||||
<li><code>bullet.position</code> subtracts timestamps to find the time step between now and whenever it last got calculated, and remembers this as <code>time_step</code></li>
|
|
||||||
<li>The time-dependence expression is now evaluated, using the last calculated value for <code>bullet.position</code>, and fetching <code>bullet.velocity</code> as normal.</li>
|
|
||||||
</ol>
|
|
||||||
<p>Hell, why not remember the entire history of a variable's values?<span class="sidenote span4">Performance.</span> When I fetch the last calculated value for <code>bullet.position</code>, why not go ahead and make that a graph-crawling reference-calculation just like everything else?<span class="sidenote span4">Reactive time-dependence is something to think about for an interesting mechanic, if nothing else - keeping track of dependencies on history means you could change a value at any point throughout the game's history and see how it changes things... Just like <a href="http://achrongame.com">Achron</a>! And the flaws that make it seem infeasible here wouldn't be a problem in, say, a turn-based time game.</span></p>
|
|
||||||
<p>Performance is a legitimate worry at that point. If you include the full-on time-dependence, then depending on implementation you might end up following a reference back through every frame the game's been through. This approach would obviously fall apart because every value in your world is going to be at least O(t) to calculate, which sucks - there should be <em>no</em> time-dependent complexity - but there are solutions:</p>
|
|
||||||
<ul>
|
|
||||||
<li>Careful design can ensure that your objects aren't too densely interlinked.</li>
|
|
||||||
<li>If you know you can do things more efficiently in some strenuous case, you can always hard-code it to extract current values and explicitly pass them around whenever you want.</li>
|
|
||||||
<li>Variables should carry metadata about when they last changed, and when their predecessors and descendents in the graph have changed - so that, in calculating the <code>shield</code>'s <code>position</code>, you don't re-fetch the <code>enemy.position</code>, if you know it hasn't changed.</li>
|
|
||||||
</ul>
|
|
||||||
<p>Besides which, we have fast computers, and without running into hard algorithmic complexity problems (collision detection, I'm lookin' at you!) it's not <em>that</em> easy to overload a modern gaming machine. And hey, maybe having declarative time-dependent values is a pipe dream - I don't care. The core idea is still awesome.</p>
|
|
||||||
<p>Here's an example (with more attention paid to data types) of how I'd come up with a vector that always points to a set offset from the position of <code>bullet</code>.</p>
|
|
||||||
<pre><code>bullet.position = Wrapper(v(1,2))
|
|
||||||
offset = v(3,4)
|
|
||||||
endpoint = bullet.position + offset
|
|
||||||
print endpoint</code>
|
|
||||||
<samp>--> WrapperSum(bullet.position, offset)</samp>
|
|
||||||
<code>print endpoint.current_value</code>
|
|
||||||
<samp>--> v(4,6)</samp>
|
|
||||||
<code>bullet.position.current_value = v(-10,0)
|
|
||||||
print endpoint.current_value</code>
|
|
||||||
<samp>--> v(-7,4)</samp></pre>
|
|
||||||
<p>Once I've started thinking and talking about this, I start wondering how much we need imperative game loops at all, for anything other than those troublesome time dependencies and feedback loops. I wonder...</p>
|
|
||||||
<pre><code>print bullet.contacts</code>
|
|
||||||
<samp>--> Wrapper(List<Contacts>)</samp>
|
|
||||||
<code>contact_acceleration = sum(contact.force_to_resolve for contact in bullet.contacts)
|
|
||||||
bullet.acceleration = contact_acceleration</code></pre>
|
|
||||||
<p>Assuming that force due to contacts is the only thing present in the world, then the bullet now feels enough acceleration to resolve all the conflicts. I mean, assuming contacts are simple to work with, and they always are. Right? Right?</p>
|
|
||||||
<p>I'm thinking about this a lot because this kind of referencing is very natural for things like defining interlinks between components in my game engine - I've got conflicting interests:</p>
|
|
||||||
<ul>
|
|
||||||
<li>I want to keep my vectors and properties lightweight, so that a <code>bullet</code>'s position should just be a vector, with which I should be able to do math as freely and easily as integers.</li>
|
|
||||||
<li>But I also want to ensure that the <code>collision component</code>'s position is the same as the <code>bullet</code>'s position! I'd like to do <code>collision_comp.position = bullet.position</code></li>
|
|
||||||
<li>And then I run into the problem that since I want my vectors as primitive as possible, if I change <code>bullet.position</code> then it's not going to change <code>collision_comp.position</code> because pass-by-value is the dominant paradigm.</li>
|
|
||||||
</ul>
|
|
||||||
<p>The solution I've been working with is wrap together <em>sets</em> of related data (as <i>components</i>). The <code>player</code> object has a <code>PositionComponent</code> and a <code>CollisionComponent</code>, and the <code>CollisionComponent</code> stores a reference to the <code>player</code>'s <code>PositionComponent</code> so that it can access it at any time. Actually holding those references constant means that there would be problems if the <code>player.position_component</code> suddenly changed to a different object - but that should never happen. I'm satisfied with this for the reasons I implemented it in the first place, but it doesn't get me the dynamic interlinking I'd like from something more like functional reactive programming.</p>
|
|
||||||
<p>So I don't know. I would love to have the <em>capacity</em> for functional reactive programming in my game engines, at the least! It's so useful for making bulletproof dynamic interactive systems.</p>
|
|
||||||
</article>
|
|
||||||
<hr>
|
|
||||||
<article class="project">
|
|
||||||
<header>
|
|
||||||
<h1>Time Integration</h1>
|
|
||||||
</header>
|
|
||||||
<p>I find myself writing cooldowns and countdowns all the time. Bullets can only fire so fast, bombs explode after five seconds, enemies spawn every 10-15 seconds. Every time I do it, I write the same boilerplate in the initialization:</p>
|
|
||||||
<pre><code>goomba.cooldown_max = 5 // 5 seconds to cool down
|
|
||||||
goomba.cooldown_timer = goomba.cooldown_max</code></pre>
|
|
||||||
<p>and the same boilerplate in the update function:</p>
|
|
||||||
<pre><code>if goomba.cooldown_timer > 0:
|
|
||||||
goomba.cooldown_timer -= time_step
|
|
||||||
if goomba.cooldown_timer < 0:
|
|
||||||
// insert end behavior here</code></pre>
|
|
||||||
<p>and somewhere, I activate this behavior (in response to a keypress, or proximit, or contact):</p>
|
|
||||||
<pre><code>goomba.cooldown_timer = goomba.cooldown_max</code></pre>
|
|
||||||
<p>I do this kind of thing so often that I feel like it should be one of the basic functionalities offered when I'm trying to describe game entity behavior.</p>
|
|
||||||
<pre><code>// initialization
|
|
||||||
goomba.shot_timer = new CooldownTimer(length=5s, on_end=function() {...})
|
|
||||||
// update functionality should be taken care of automatically, but if not:
|
|
||||||
goomba.shot_timer.step(time_step)
|
|
||||||
// activating the timer:
|
|
||||||
goomba.shot_timer.start()</code></pre>
|
|
||||||
<p>Now, wasn't that easy?</p>
|
|
||||||
<p>Of course, that's a pretty simple case! There are obvious extensions, though:</p>
|
|
||||||
<pre><code>goomba.blink_timer = new EndlessTimer()
|
|
||||||
goomba.blink_timer.interval = 5s
|
|
||||||
goomba.blink_timer.at_progress(0%, goomba.change_color) // change color at the start of each interval
|
|
||||||
goomba.blink_timer.at_progress(50%, goomba.take_step) // take a step once every interval halfway through</code></pre>
|
|
||||||
<p>And now making timed behavior for our goomba is easy! We can even speed up the goomba easily: <code>goomba.blink_timer.interval = 3s</code></p>
|
|
||||||
<p>Ideally, you don't need to even specify when to <code>step</code> your timers - that should be taken care of automatically. Of course, that means we'd want to <em>register</em> these timers instead of simply declaring them as a member - but maybe that's a matter of a grander architectural problem.</p>
|
|
||||||
<p>Although! If we <em>do</em> let the developer take care of stepping the timers, then we can also use it for things that <em>aren't</em> time-dependent:</p>
|
|
||||||
<pre><code>player.limit_bar = new Meter(length=100) // general verison of the CooldownTimer
|
|
||||||
player.on('hit by enemy', player.limit_bar.step)
|
|
||||||
player.limit_bar.at_progress(100%, player.limit_break)</code></pre>
|
|
||||||
<p>And now we've got a way for limit breaks to engage. Assuming there's a pre-existing event system and everything is architected carefully, it's now incredibly easy to fill meters in response to events.</p>
|
|
||||||
</article>
|
|
||||||
<article class="project">
|
|
||||||
<header>
|
|
||||||
<h1>Easy Peasy State Machinesy</h1>
|
|
||||||
</header>
|
|
||||||
<p>Why do I always have to actually use boolean flags (manually setting and unsetting them) to track the states of my entities?</p>
|
|
||||||
<pre>
|
|
||||||
<code>player.shielding = new Toggle()
|
|
||||||
keyboard.on('w pressed', player.shielding.next)</code></pre>
|
|
||||||
<p>I'm just throwing this syntax together off the top of my head. The syntax isn't important - what's important is that I should be able to describe this and have it happen.</p>
|
|
||||||
<pre>
|
|
||||||
<code>strobelight.color = new Sequence(['red', 'green', 'blue'])
|
|
||||||
strobelight.update = function(dt) {
|
|
||||||
strobelight.color.next()
|
|
||||||
strobelight.draw()
|
|
||||||
}</code></pre>
|
|
||||||
<p>Seriously, don't worry about this syntax - it's ugly and I just threw it together. The point is the kinds of things I should be able to do. This is all totally feasible.</p>
|
|
||||||
<pre>
|
|
||||||
<code>goomba.ai = new StateMachine(['sleep', 'suspicious', 'alert'])
|
|
||||||
goomba.ai['sleep'].transitions_to['suspicious'].on(goomba.near(player))
|
|
||||||
// the state 'sleep' should transition to 'suspicious' on the event goomba.near(player)
|
|
||||||
goomba.ai['sleep'].update = goomba.draw_snores
|
|
||||||
|
|
||||||
goomba.ai['suspicious'].transitions_to['alert'].on(goomba.sees(player))
|
|
||||||
goomba.ai['suspicious'].update = goomba.search_for_player
|
|
||||||
|
|
||||||
// shit we forgot to make a state for just patrolling
|
|
||||||
goomba.ai.add_state('patrol')
|
|
||||||
goomba.ai['patrol'].transitions_to['sleep'].after(5 seconds)
|
|
||||||
goomba.ai['patrol'].update = goomba.wander
|
|
||||||
|
|
||||||
// oh hey, she should occasionally wake up to patrol!
|
|
||||||
goomba.ai['sleep'].transitions_to['patrol'].after(5-10 seconds)</code></pre>
|
|
||||||
<p>So y'know. State machines are powerful. In order to really use them, you need a robust event system, or else they're a huge pain - it's still possible, you just... need to code it to check the conditions on each update loop. That could get expensive!</p>
|
|
||||||
<p>For the example of checking <code>goomba.near(player)</code> - which has an optional argument for the distance - that function checks if there's already a collision detection object attached to <code>goomba</code> for setting off proximity events. If there is, it returns the event handle, which can be used for binding behaviors to the firing of that event. If a proximity collider of the right size <em>doesn't</em> exist, then it creates one, and returns the event handle.</p>
|
|
||||||
<p></p>
|
|
||||||
</article>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,87 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Tamari Lattices</title>
|
|
||||||
<link href="http://li60-203.members.linode.com/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
|
||||||
<link href="http://li60-203.members.linode.com/static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
|
||||||
<link href="http://li60-203.members.linode.com/static/shoofle.css" rel="stylesheet" type="text/css">
|
|
||||||
<style>
|
|
||||||
figure {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
figcaption {
|
|
||||||
font-style: italic;
|
|
||||||
font-family: serif;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<article class="project">
|
|
||||||
<h1>Tamari Lattices!</h1>
|
|
||||||
<p>Tamari lattices are graphs (in the mathematical sense - a set of nodes with connections between them) describing a particular set of operations. I like them because they're pretty!</p>
|
|
||||||
<figure>
|
|
||||||
<img src="http://li60-203.members.linode.com/static/tamari/tamari_3.png" alt="The (trivial) Tamari lattice for a three-element tree.">
|
|
||||||
<figcaption>A (trivial) Tamari lattice, generated by the associations of three elements. <a class="source" href="http://li60-203.members.linode.com/static/tamari/tamari_3.dot">Source file.</a></figcaption>
|
|
||||||
</figure>
|
|
||||||
<p>Oh - oh dear. How'd that get there? Okay, that's not a very good example.</p>
|
|
||||||
<p>There are many ways to generate and think of a Tamari lattice. The way I prefer to think of it is this: Consider some binary operation - you take two elements to produce a new one. You want to combine several of these elements. So long as you have three or more elements, there are multiple ways to combine them.</p>
|
|
||||||
<p>The game we play is this: You're allowed to step from one way of combining the elements to another, but only by <i class="keyword">left-association</i>: turning <code>(a, (b, c))</code> into <code>((a, b), c)</code>.</p>
|
|
||||||
<p>The only remaining rule is that if you can step from one combination to another, the second one has to appear below the first one when you draw it.</p>
|
|
||||||
<figure>
|
|
||||||
<img src="http://li60-203.members.linode.com/static/tamari/tamari_4.png" alt="A Tamari lattice for a four-element tree.">
|
|
||||||
<figcaption>As above, but generated by a four-element tree. <a class="source" href="http://li60-203.members.linode.com/static/tamari/tamari_4.dot">Source file.</a></figcaption>
|
|
||||||
</figure>
|
|
||||||
<p>You can also think about it in terms of <a href="http://wikipedia.org/wiki/Tree_rotation">tree rotations</a> - but remember that that's a different tree than the one we're building as the Tamari lattice. Tree rotations are just another way to think of left-association and right-association.</p>
|
|
||||||
<p>If you look at <a href="http://wikipedia.org/wiki/Tamari_lattice">the wikipedia article on Tamari lattices</a>, you'll see a very pretty image:</p>
|
|
||||||
<img src="http://upload.wikimedia.org/wikipedia/commons/4/46/Tamari_lattice.svg">
|
|
||||||
<p>There are a lot of ways to reorganize a Tamari lattice, and it takes some artistic work to make one that really looks good. You can even visualize the same graph as <a href="http://en.wikipedia.org/wiki/Associahedron">a 3D shape called an "associahedron"</a>, but I like it in the simple gridded lattice form above. It reminds me how much beauty there can be in regularity - you can see the grid, but it doesn't look constrained by it. I might get a tattoo of the five-element Tamari lattice someday.</p>
|
|
||||||
<figure>
|
|
||||||
<img src="http://li60-203.members.linode.com/static/tamari/tamari_5.png" alt="Tamari lattice for a five-element tree.">
|
|
||||||
<figcaption>Also the five-element lattice! Compare to the <a href="http://wikipedia.org/wiki/Tamari_lattice">example above, on wikipedia.</a>. <a class="source" href="http://li60-203.members.linode.com/static/tamari/tamari_5.dot">Source file.</a></figcaption>
|
|
||||||
</figure>
|
|
||||||
<p>All these graphs with the ovals and the curvy lines were generated by yours truly! I made some python that would take a string representation of an association of a number of elements and convert it into an easily-manipulated memory representation. Then, a few tree rotations spit out all the possible results of left-associating on it, and it was relatively simple to print out a <code>.dot</code> file, parseable by <a href="http://www.graphviz.org/">graphviz</a>, that described the graph. It even labeled the nodes!</p>
|
|
||||||
<p><code>dot</code> happily converted them into the <code>png</code> files you're looking at. Of course, they don't have the human touch, so they're not organized into beautiful grid lines and 45° angles - but it can be fun to try to mentally reorganize them into a nicer shape. If you want, you can download the <code>.dot</code> source files for any of these, and play around with them in a graph-editing program (such as <a href="https://github.com/jrfonseca/xdot.py">XDot</a>)</p>
|
|
||||||
<figure>
|
|
||||||
<img src="http://li60-203.members.linode.com/static/tamari/tamari_6.png" alt="Tamari lattice for a six-element tree.">
|
|
||||||
<figcaption>It's starting to get out of hand, I think.<a class="source" href="http://li60-203.members.linode.com/static/tamari/tamari_6.dot">Source file.</a></figcaption>
|
|
||||||
</figure>
|
|
||||||
<p>Unfortunately, at a certain point I think it's going to get difficult to make these pretty. It turns out there are a lot of ways to associate a larger number of elements! Starting with a six-element tree or string, there are 42 elements (above). With seven, there are 132! Wowie!</p>
|
|
||||||
<figure>
|
|
||||||
<img src="http://li60-203.members.linode.com/static/tamari/tamari_7.png" alt="Tamari lattice for a seven-element tree.">
|
|
||||||
<figcaption>Oh dear. <a class="source" href="http://li60-203.members.linode.com/static/tamari/tamari_7.dot">Source file.</a></figcaption>
|
|
||||||
</figure>
|
|
||||||
<p>My server was chugging along trying to generate <code>tamari_8.dot</code> but I started getting messages from linode about going over my CPU quotas, so I canceled it - after it ran for an hour or so, without finishing. I think the seven-element one is messy-looking enough!</p>
|
|
||||||
<p>You can look at the <a class="source" href="http://li60-203.members.linode.com/static/tamari/tamari.py">python script</a> I used to make this, but it's not particularly pretty - I was bored one day and decided I was going to figure out how to generate these... It's not exactly meant to be extensible. It's got a basic binary tree node class I threw together and a handful of (really ugly) helper functions. I just went through and rewrote it a bit to be nicer - the final output loop may please you if you enjoy <code>set</code>s and list comprehensions:</p>
|
|
||||||
<pre>
|
|
||||||
<code class="language-python">current_generation = set()
|
|
||||||
next_generation = {RootOfAllEvil}
|
|
||||||
edges = set()
|
|
||||||
labels = set()
|
|
||||||
|
|
||||||
while next_generation: # While there are trees to examine.
|
|
||||||
# Move to look at the next generation.
|
|
||||||
current_generation = next_generation
|
|
||||||
|
|
||||||
# Clear out the next gen to fill it with the children of this generation.
|
|
||||||
next_generation = set()
|
|
||||||
|
|
||||||
# Ensure there are labels for this generation.
|
|
||||||
labels = labels | set(label_from_node(parent) for parent in current_generation)
|
|
||||||
|
|
||||||
for parent in current_generation:
|
|
||||||
children = generate_children(parent)
|
|
||||||
|
|
||||||
labels = labels | set(label_from_node(child) for child in children)
|
|
||||||
edges = edges | set(str(parent) + " -> " + str(child) + ";" for child in children)
|
|
||||||
next_generation = next_generation | children
|
|
||||||
|
|
||||||
# Output a dot format stream!
|
|
||||||
args.output.write(u"digraph tamari {\n")
|
|
||||||
args.output.write(u"\n".join(labels) + "\n")
|
|
||||||
args.output.write(u"\n".join(edges))
|
|
||||||
args.output.write(u"\n}\n")</code></pre>
|
|
||||||
<p>The full script can be used by running <code class="language-bash">python tamari.py --length 4 | dot -Tpng > output.png</code> to produce a graph. <code>tamari.py</code> will print out to a specified file if you also include a filename: <code class="language-bash">python tamari.py --length 5 output.dot</code></p>
|
|
||||||
</article>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -4,9 +4,9 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Projects, by Shoofle</title>
|
<title>Projects, by Shoofle</title>
|
||||||
<link href="static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||||
<link href="static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
<link href="/static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||||
<link href="static/shoofle.css" rel="stylesheet" type="text/css">
|
<link href="/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
|
@ -1,21 +1,19 @@
|
|||||||
import os
|
import os
|
||||||
from os.path import join, isfile
|
from os.path import join, isfile
|
||||||
from flask import Flask, render_template, url_for, redirect
|
|
||||||
|
from flask import Flask, render_template, url_for, redirect, send_from_directory
|
||||||
|
|
||||||
|
from articles import bloop
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.template_folder = "."
|
app.template_folder = ""
|
||||||
server_directory = "/home/shoofle/auriga/"
|
#server_directory = "/home/shoofle/auriga/"
|
||||||
project_directory = join(server_directory, "pages")
|
#project_directory = join(server_directory, "pages")
|
||||||
guitar_directory = join(server_directory, "guitar")
|
#guitar_directory = join(server_directory, "guitar")
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/favicon.<extension>")
|
||||||
def project_list():
|
def favicon(extension=None):
|
||||||
return render_template("project_list.html")
|
return send_from_directory(join(app.root_path, "static"), "favicon.png", mimetype="image/png")
|
||||||
|
|
||||||
@app.route("/miscellany/")
|
|
||||||
def miscellany():
|
|
||||||
guitar_files = [ f for f in os.listdir(guitar_directory) if isfile(join(guitar_directory, f)) and "html" not in f ]
|
|
||||||
return render_template("pages/miscellany.html", guitar_files=guitar_files)
|
|
||||||
|
|
||||||
@app.route("/guitar_tab/")
|
@app.route("/guitar_tab/")
|
||||||
@app.route("/guitar_tab/<file_name>")
|
@app.route("/guitar_tab/<file_name>")
|
||||||
@ -27,15 +25,8 @@ def guitar_display(file_name=None):
|
|||||||
return render_template("guitar/render_tab.html", contents=c)
|
return render_template("guitar/render_tab.html", contents=c)
|
||||||
return render_template("guitar/default.html", guitar_files=guitar_files)
|
return render_template("guitar/default.html", guitar_files=guitar_files)
|
||||||
|
|
||||||
@app.route("/<project_name>/")
|
app.register_blueprint(bloop)
|
||||||
def unknown_project(project_name="miscellany"):
|
|
||||||
for file_name in os.listdir(project_directory):
|
|
||||||
if not isfile(join(project_directory, file_name)):
|
|
||||||
continue
|
|
||||||
if file_name == project_name.replace("-","_") + ".html":
|
|
||||||
return render_template("pages/" + file_name)
|
|
||||||
else:
|
|
||||||
return redirect(url_for('miscellany') + '#' + project_name)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
app.debug = True
|
||||||
app.run()
|
app.run()
|
||||||
|
BIN
pure_flask.pyc
BIN
pure_flask.pyc
Binary file not shown.
305
static/auriga.html
Normal file
305
static/auriga.html
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>How should this website be laid out?</title>
|
||||||
|
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||||
|
<link href="/static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||||
|
<link href="/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<style type="text/css">
|
||||||
|
#server-choices colgroup { width: 20%; }
|
||||||
|
#server-choices tr { height: 3em; }
|
||||||
|
#server-choices tr>td { text-align: center; }
|
||||||
|
#server-choices tr>td:first-child {
|
||||||
|
text-align: left;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<article class="project">
|
||||||
|
<h1>Shit, I better make this server work.</h1>
|
||||||
|
<h3>On the layout of folders and files!</h3>
|
||||||
|
<p>Basically I'm not sure how I should lay out this website. The current organization looks something like this:</p>
|
||||||
|
<ul class="file-tree">
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">server/</span> (server root)
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">pages/</span> (articles with nice links)
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span> (accessed as <span class="url">http://example.com/auriga/</span>)</li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">language_for_games.html</span> (<span class="url">http://example.com/language-for-games/</span>)</li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span> (<span class="url">http://example.com/tamari/</span>)
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">static/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-eye-open"></i> <span class="filename">stylesheet.css</span> (global stying)</li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">favicon.ico</span></li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">banner.png</span></li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">tamari/</span> (files for an article)
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">figure_1.png</span></li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">figure_2.png</span></li>
|
||||||
|
<li><i class="icon-signal"></i> <span class="filename">experiment_data.csv</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>This has a number of problems. First and foremost, barely any thought has gone into naming of folders and files - which is because not much thought has gone into their placement and hierarchy.</p>
|
||||||
|
<p>The server is written using <a href="http://flask.pocoo.org">Flask</a>, and this is the rundown on how it works when a user goes to <span class="url">http://example.com/some-path/</span>:</p>
|
||||||
|
<ol>
|
||||||
|
<li>If the path requested is the root of the website, render <span class="filename">main_page.html</span>.</li>
|
||||||
|
<li>If the path requested begins with <span class="url">static/</span>, render a file from the static content directory.</li>
|
||||||
|
<li>Else, convert the path (<span class="url">some-path</span>) into the filename (<span class="filename">pages/some_path.html</span>) assuming it's an article. If it exists, render it.</li>
|
||||||
|
<li>If there's no article by that name, display the miscellaneous articles page. Or 404. The current behavior isn't very high on my priorities.</li>
|
||||||
|
</ol>
|
||||||
|
<p>There are a bunch of problems with this system - it's kind of brittle, file paths have the meaningless-to-the-user <span class="url">static/</span> at the beginning, and it means that when I include a resource in <span class="url">http://example.com/tamari/</span> (the file <span class="filename">pages/tamari.html</span>) I have to use a path like <span class="url">../static/tamari/figure_1.png</span> - when I should be able to reference files related to the Tamari article by a closely-related URL: <span class="url">./figure_1.png</span>.</p>
|
||||||
|
<p>All this points to the idea of having my articles be in folders, so it would look something like this:</p>
|
||||||
|
<ul class="file-tree">
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">server/</span> (server root)
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">articles/</span> (articles with nice links)
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">auriga/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">language-for-games/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">language_for_games.html</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">tamari/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span></li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">figure_1.png</span></li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">figure_2.png</span></li>
|
||||||
|
<li><i class="icon-signal"></i> <span class="filename">experiment_data.csv</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">static/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-eye-open"></i> <span class="filename">stylesheet.css</span> (global stying)</li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">favicon.ico</span></li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">banner.png</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>And hell, at this point having the filenames match the folders (<span class="filename">auriga/auriga.html</span>) is just a pain, so we could name the main page in each folder <span class="filename">index.html</span>, and suddenly this looks very standard. So why don't I do this?</p>
|
||||||
|
<p>Well... I don't know. But something always bothered me about the <span class="filename">index.html</span> standard. Maybe it's just that my article about Tamari lattices <em>isn't</em> an index, so I don't think it should be called one. That's certainly part of it. Also, some of my articles and pages are going to be very short - in theory I'd like them to be able to be tiny snippets, which could be included on other pages. It'd be annoying to have a subfolder for every single article I write! But... maybe not <em>too</em> annoying. I'll have to think about that.</p>
|
||||||
|
<hr>
|
||||||
|
<h3>But what are we <em>doing</em>?</h3>
|
||||||
|
<p>What would my ideal web framework be? Well, something like Flask, really. I like flask because this is easy:</p>
|
||||||
|
<pre>
|
||||||
|
<code class="language-python">@app.route("<span class="url">/some-convoluted/url/<options>/with-stuff/</span>")
|
||||||
|
def render_shoofle_page(options=None):
|
||||||
|
if options == "bananas":
|
||||||
|
return render_page("<span class="filename">bananas.html</span>")
|
||||||
|
else:
|
||||||
|
return render_page("<span class="filename">some_other_template.html</span>", options=options)</code></pre>
|
||||||
|
<p>And, lo and behold, I can go to <span class="url">example.com/some-convoluted/url/bananas/with-stuff/</span> and see the right generated page! I like having that capacity at my fingertips. In particular, it makes it easy to respond to various other kinds of requests. That's what I really like about Flask - I feel like I can do <em>everything</em> a webserver can do, but it all takes the same very small amount of work. This compares to, say, PHP, where it's easy to make pages... But more complicated behavior, especially anything involving dynamic URL paths, involves jumping through hoops.<span class="sidenote span4">It might seem like an overblown complaint, but the integrity of my mental models is important to me - and in PHP, I don't understand what gets sent to the requestor. If I make a Flask route returning JSON, I know it's exactly what a script wants. With PHP, I would <em>hope</em> that it wouldn't have weird headers or content type or additional markup.</span> Plus, you have to work with PHP, which I would wish on no one.</p>
|
||||||
|
<p>I don't like Flask because I need to specify all the behaviors, and I'm worried that I'll get it wrong (thus, this article).</p>
|
||||||
|
<p>My ideal world solution would be something that lets me pass requests for subpaths to other python modules:<p>
|
||||||
|
<ul class="file-tree">
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">server/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-file"></i> <span class="filename">server.py</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">articles/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-file"></i> <span class="filename">articles.py</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">language-for-games.html</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">games/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-file"></i> <span class="filename">games.py</span></li>
|
||||||
|
<li><i class="icon-signal"></i> <span class="filename">scores.csv</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">play_the_game.html</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">game.js</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>Aaaand how it works would be simple:</p>
|
||||||
|
<ol>
|
||||||
|
<li>A request comes in to <span class="url">http://example.com/tamari/</span>, and it is handled by <span class="filename">server.py</span>.</li>
|
||||||
|
<li><span class="filename">server.py</span> says "Okay, I don't have any specific handlers that do anything with this URL, but I think <span class="filename">articles/articles.py</span> does!" and sends the request to <span class="filename">articles.py</span>.</li>
|
||||||
|
<li><span class="filename">articles.py</span> receives a request for <span class="url">/tamari/</span> and has a rule for handling that, and so it renders the appropriate HTML file.</li>
|
||||||
|
</ol>
|
||||||
|
<p>The basic idea is that requests can be routed to other python modules. If those modules can be reloaded easily (or automatically!), this would mean I could write complicated URL handling in subdirectories of my website - without having to touch any of the code that handles anything else. It means I can modularize - and that's <em>awesome</em>.</p>
|
||||||
|
<ol>
|
||||||
|
<li>An HTTP GET request comes in to <span class="url">http://example.com/games/points</span>, and <span class="filename">server.py</span> takes it.</li>
|
||||||
|
<li><span class="filename">server.py</span> doesn't know what to do with it, but it knows that requests for URLs starting with <span class="url">/games</span> should be handled by <span class="filename">games/games.py</span>.</li>
|
||||||
|
<li><span class="filename">games.py</span> receives an HTTP GET request for <span class="url">/games/points</span>, and so it can respond to this with a JSON object that tells the requestor how many points they got.</li>
|
||||||
|
</ol>
|
||||||
|
<p>This is the main point of the tiered handlers system - that I can write handlers for all kinds of requests, without having to interact with other parts of my website.</p>
|
||||||
|
<p>Basically, I want to combine the simple directory structure of PHP websites with the principles of Flask I really like - separating content from server logic, keeping things simple, and having control.</p>
|
||||||
|
<p>Here's how I imagine this would work:</p>
|
||||||
|
<pre>
|
||||||
|
<code>from flask import Flask, render_template, redirect
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
def main_page(): return render_template("<span class="filename">main.html</span>")
|
||||||
|
app.add_url_rule("<span class="url">/</span>", main_page)
|
||||||
|
|
||||||
|
import games
|
||||||
|
app.add_module_url_rule("<span class="url">/games/<path:rest></span>", games)</code></pre>
|
||||||
|
<p>As usual, don't think too hard about the syntax I just proposed. The point is to distribute URL routing logic throughout multiple files, so that my entire website isn't controlled by one brutalistic overlord <span class="filename">server.py</span> file that decrees the entire path of every request. I want things split up, dammit!</p>
|
||||||
|
<hr>
|
||||||
|
<p>Now I'm reading up on the Flask docs, and it turns out that it already has the capacity for this. Unfortunately, it's complicated and I'm <em>whiiiny</em>.</p>
|
||||||
|
<p>It seems that Flask provides the developer with three options:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Package Organization: Essentially, break up your server code, like configuration and URL route assignment, into separate files. This doesn't actually solve any of my issues - most of what this does (as far as I can tell) is separate the server initialization logic from the routing and response logic. Plus, it makes it easier to use your application in something else. More on this soon.</li>
|
||||||
|
<li>Blueprints: Very close to what I want. I could define a Blueprint object in <span class="filename">articles.py</span>. This Blueprint object would register all the routes and endpoints that I want to register - and then, when the server starts, it gets all of those from the blueprint. This means we can <em>actually</em> factor views out. I'm really not sure, though, what this affords that the organizing your application as a package doesn't.</li>
|
||||||
|
<li>Application Dispatching: The most powerful of the three! This is a slightly lower-level solution, wherein you actually run multiple applications concurrently, and dispatch requests to them. This is kind of overkill, but at least it's nice to know that it's possible - things like the <span class="url">async_app</span> example from previous could really make sense, if the app is large enough in scope. Application dispatching means you can just pull in another application and route things to it on the WSGI layer. Or something.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Okay, but... how do they score up? I have some requirements:</p>
|
||||||
|
<dl>
|
||||||
|
<dt>Organization</dt>
|
||||||
|
<dd>I want to define the behavior for <span class="url">example.com/articles/tamari/</span> in the same place as <span class="url">example.com/articles/language-for-games/</span> is defined, but in a different file from where <span class="url">example.com/games/hunt-the-wumpus</span> is defined.</dd>
|
||||||
|
<dt>Simplicity</dt>
|
||||||
|
<dd>Defining a URL route and endpoint for each subfolder of my application shouldn't be much more complicated than defining behaviors in a flat system. Ideally, registering all the behaviors for the <span class="url">articles/</span> subpath is no more complicated than <code>app.route("<span class="url">/articles/</span>", articles_handler)</code></dd>
|
||||||
|
<dt>Ease of Extension</dt>
|
||||||
|
<dd>I'm writing a family of pages. They're starting to get a little too complicated. It should be really easy to go from that situation to having a nicely-delineated subsection of my website.</dd>
|
||||||
|
<dt>Do I <em>Need</em> to Restart the Server?</dt>
|
||||||
|
<dd>I hate restarting the server. Maybe this is a little thing, but gah! I want the server to detect changes automatically! This shouldn't be that hard. Of course, this is a much thornier topic when it comes to subpages that might store their own state... So it might be out the window unless I want to get my hands <em>way</em> more dirty.</dd>
|
||||||
|
</dl>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row-fluid">
|
||||||
|
<table id="server-choices" class="span8 offset2">
|
||||||
|
<caption><h4>How do they fare up?</h4></caption>
|
||||||
|
<col><colgroup span=4></colgroup>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
|
||||||
|
<th>Organization</th>
|
||||||
|
<th>Simplicity</th>
|
||||||
|
<th>Ease of Extension</th>
|
||||||
|
<th>No Restart Required?</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Current</td>
|
||||||
|
|
||||||
|
<td class="label-warning"><i class="icon-question-sign"></i></td>
|
||||||
|
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||||
|
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||||
|
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Organize as a Package</td>
|
||||||
|
|
||||||
|
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||||
|
<td class="label-warning"><i class="icon-question-sign"></i></td>
|
||||||
|
<td class="label-warning"><i class="icon-question-sign"></i></td>
|
||||||
|
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Blueprints</td>
|
||||||
|
|
||||||
|
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||||
|
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||||
|
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||||
|
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Application Dispatch</td>
|
||||||
|
|
||||||
|
<td class="label-success"><i class="icon-ok-sign"></i></td>
|
||||||
|
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||||
|
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||||
|
<td class="label-important"><i class="icon-remove-sign"></i></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div></div>
|
||||||
|
<p>In light of this chart, it seems like Blueprints are the clear option. Also, "organize as package" is really vague. What they suggested didn't sound very helpful - but making python packages (finally learning how to use <span class="filename">__init__.py</span> files!) will probably get used in the solution I'm thinking I'll use, which looks something like this:</p>
|
||||||
|
<ul class="file-tree">
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">server/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-file"></i> <span class="filename">server.py</span></li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">articles/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-file"></i> <span class="filename">article_routing_blueprint.py</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">main_page.html</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">auriga.html</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">language-for-games.html</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">tamari.html</span></li>
|
||||||
|
<li><i class="icon-folder-close"></i> <span class="filename">tamari_files</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">games/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-file"></i> <span class="filename">games_blueprint.py</span></li>
|
||||||
|
<li><i class="icon-signal"></i> <span class="filename">scores.csv</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">play_the_game.html</span></li>
|
||||||
|
<li><i class="icon-align-left"></i> <span class="filename">game.js</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><i class="icon-folder-open"></i> <span class="filename">static/</span>
|
||||||
|
<ul>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">favicon.ico</span></li>
|
||||||
|
<li><i class="icon-eye-open"></i> <span class="filename">stylesheet.css</span></li>
|
||||||
|
<li><i class="icon-picture"></i> <span class="filename">lol_a_cat.jpg</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>If there's static content that is globally important, with simple routing rules, it can - of course - be stored in the server root's <span class="filename">static/</span> directory. Static file handlers don't take much configuration, so this can go in the root.</p>
|
||||||
|
<p>All the files related to articles are contained in the <span class="filename">articles/</span> directory, or subdirectories. <span class="filename">article_routing_blueprint.py</span> contains a blueprint definition that tells the server how to route calls that result in the rendering of the various articles I've written.</p>
|
||||||
|
<p>All files related to the little javascript games I've made, on the other hand, go in the <span class="filename">games/</span> directory. State for this application is managed by <span class="filename">games_blueprint.py</span>, which is sort of like a very tiny application. I think it's possible to keep track of state, if you remember to keep variables global... This is tricksy, but should be doable - and if it gets larger, it should almost certainly be developed as a separate application entirely. At that point, I should figure out how to include multiple applications in one website!</p>
|
||||||
|
<p>I want to finish this bit by writing down some code for the base <span class="filename">server.py</span> logic:</p>
|
||||||
|
<pre>
|
||||||
|
<code class="language-python">from flask import Flask
|
||||||
|
|
||||||
|
# app configuration and initialization
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.debug = True
|
||||||
|
|
||||||
|
# content in <span class="filename">articles/</span>
|
||||||
|
import articles
|
||||||
|
app.register_blueprint(articles.blueprint)
|
||||||
|
|
||||||
|
# content in <span class="filename">games/</span>
|
||||||
|
import games
|
||||||
|
app.register_blueprint(games.blueprint, url_prefix="<span class="url">/games</span>")</code></pre>
|
||||||
|
<hr>
|
||||||
|
<h3>Okay, one last thing.</h3>
|
||||||
|
<p>This has been a lot about how to get some basic extensible functionality working. <i class="that-guy">But wait</i>, someone cries in the distance! <i class="that-guy">Why are we going to such lengths to do all this in the first place, when you're just serving static HTML files? Isn't this way more work than you need?</i><span class="sidenote span4">In case you're reading this article long after I've finished these changes (I hope so, 'cause I should get to work on this immediately), at this point all the articles were static HTML files. That voice speaks the truth.</span></p>
|
||||||
|
<p>Thanks for asking. The answer is that I want to change how this site is structured, and the articles are the specific thing I want to change. See, as it is, each article has basically the same header at the top, and basically the same footer at the bottom, and... Well, they're just all enclosed in the same stuff, and so when I change the styling of the website - or, horror of horrors, try to add a sidebar across the hwole site - I have to change all of them! And, as I think we've been over before, I'm <em>lazy</em>.</p>
|
||||||
|
<p>Conveniently, as I've been obsessively reading discussions of standards-compliant HTML5 and document formats and such lately, this laziness messes with my indomitable enthusiasm for conceptually pleasing solutions. Here's what I've got:</p>
|
||||||
|
<ul>
|
||||||
|
<li><b>Articles</b> on my site are blocks of text, consisting of my rambling on some topic. Something I've written down. They can have some amount of associated content, but for the most part they're just text. So, I'm going to reduce them down to their bare minimum of unique content - in many cases, just an <code language="html"><article></code> tag containing what I wrote!</li>
|
||||||
|
<li>But sometimes I want to have multiple articles display in one page! Sometimes my articles are single paragraphs. Sometimes they can be grouped into related, uh, groups! What do we do then? The answer is <strong>templates</strong>. Flask uses <a href="http://jinja.pocoo.org/">Jinja2</a>, a perfectly nice templating engine - and why not use it?</li>
|
||||||
|
<li>If I want to display the articles contained in <span class="filename">articles/parkour_is_awesome.html</span>, <span class="filename">articles/exercise.html</span>, and <span class="filename">articles/how_is_body.html</span>), then I just make a new page, a Jinja2 template, which contains this:
|
||||||
|
<pre>
|
||||||
|
<code class="language-jinja2"><!-- {% raw %} -->{% include "<span class="filename">articles/parkour_is_awesome.html</span>" %}
|
||||||
|
{% include "<span class="filename">articles/exercise.html</span>" %}
|
||||||
|
{% include "<span class="filename">articles/how_is_body.html</span>" %}<!-- {% endraw %} --></code></pre>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>And ta-da! We now have a page which has those three articles in a row.</p>
|
||||||
|
<p>This, of course, also means we have a neat format for how to display things in general. Someone requested access to a URL! Find the file it points to. If it's an HTML fragment, then point the <b>general page template</b> to that file, and render. The general page template is just a template that adds the header, footer, sidebar, universal styling, and so on, as required, for universality.</p>
|
||||||
|
<p>So if you go to <span class="url">example.com/tamari/</span>, the server says "Okay, you want to look at the article in the HTML fragment file <span class="filename">articles/tamari.html</span>." It renders the general page template around that article, and returns that to the user.</p>
|
||||||
|
<p>Because I like having the option to look at these things many ways, I'm probably also going to allow for a user to do <code class="language-bash">python articles.py --generate [path]</code>, which will simply spit out the the rendered results of going to <code class="language-bash">[path]</code>. I guess that <em>might</em> just be indistinguishable from using <code class="language-bash">wget</code>, but hey. It can't hurt to give more functionality!</p>
|
||||||
|
<p>It remains to be seen precisely how many pages on this site will use the general page template. I don't want to rely on it too much, but, man, is there <em>any</em> reason not to? Basically, it means that I don't have to worry about writing the headers of anything on my website. I guess I'll need to be able to throw it off when I'm making subpages that are intended to be stylistically distinct from the rest of my site.</p>
|
||||||
|
</article>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -3,9 +3,9 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Game Log</title>
|
<title>Game Log</title>
|
||||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||||
<link href="../static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
<link href="/static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
<link href="/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
150
static/backup/language_for_games.html
Normal file
150
static/backup/language_for_games.html
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>A Language for Games</title>
|
||||||
|
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||||
|
<link href="/static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||||
|
<link href="/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>I like making games but sometimes I spend a lot of time doing stuff that is just annoying. What if a language or environment were designed to make those things easy?</p>
|
||||||
|
<hr>
|
||||||
|
<article class="project">
|
||||||
|
<header>
|
||||||
|
<h1>Snorlax Evaluation</h1>
|
||||||
|
<p>(define-by-reference, or: lazy evaluation taken to extremes)</p>
|
||||||
|
</header>
|
||||||
|
<p>Okay, so I've got a <code>Bomb</code> entity in my game. It's already got the behavior for flying toward its <code>destination</code>. What if I want to make a <code>SmartBomb</code> that tracks a target even if they move? I might do it something like this:</p>
|
||||||
|
<pre><code>SmartBomb.on_update = function (timestep) {
|
||||||
|
// other update behaviors go in this function as well
|
||||||
|
this.destination = target.position
|
||||||
|
}</code></pre>
|
||||||
|
<p>I have to explicitly tell my engine to execute this every frame. I think in terms of this kind of thing already, because I'm a math and physics person. Why can't I define relationships like this more simply? What if, in fact, this was the default way we referred to values? <span class="sidenote span4">It's worth noting that what I've thought of here is essentially just <a href="https://en.wikipedia.org/wiki/Functional_reactive_programming">functional reactive programming</a>. You can go read wikipedia if you want.</span></p>
|
||||||
|
<pre><code>SmartBomb.destination = target.position</code></pre>
|
||||||
|
<p>Any time something fetches the value of <code>SmartBomb.destination</code> it'll fetch the value of <code>target.position</code>. Writing it this way, instead of explicitly specifying which variables need to be kept up-to-date with other variables (and when they need to be updated!), means it's easier to give variables interesting dependencies on other values - like this <code>shield</code> which should float a certain distance between the <code>player</code> and the <code>enemy</code>:</p>
|
||||||
|
<pre><code>shield.position = player.position + shield.distance * unit_vector(enemy.position - player.position)</code></pre>
|
||||||
|
<p>If and when you <em>do</em> need to store something's value at a specific time, you can do that if you want - for example, this code when a bomb explodes:</p>
|
||||||
|
<pre><code>explosion_location = current_value(bomb.position)
|
||||||
|
// or maybe the syntax is like this:
|
||||||
|
explosion_location = bomb.position.current_value</code></pre>
|
||||||
|
<p>So far, everything's time-independent. For example, the <code>shield</code> object's <code>position</code> depends only on the positions of other objects.</p>
|
||||||
|
<p>Why not include time-dependence? A <code>bullet</code> has a <code>position</code> and a <code>velocity</code>, and these are related in a way that doesn't change at any point during gameplay. Why not codify that relationship in a similar way?</p>
|
||||||
|
<pre><code>bullet.position = bullet.position + time_step * bullet.velocity
|
||||||
|
// or maybe
|
||||||
|
bullet.position = bullet.position + bullet.position.time_since_last_calculation * bullet.velocity</code></pre>
|
||||||
|
<p>Okay, if this seems like impossible magic, I'm sorry. Let's walk through it:</p>
|
||||||
|
<ol>
|
||||||
|
<li>The global loop asks for <code>bullet.position</code> in order to know where it should be drawn.</li>
|
||||||
|
<li><code>bullet.position</code> looks at its cached value and sees that it's out of date.</li>
|
||||||
|
<li><code>bullet.position</code> subtracts timestamps to find the time step between now and whenever it last got calculated, and remembers this as <code>time_step</code></li>
|
||||||
|
<li>The time-dependence expression is now evaluated, using the last calculated value for <code>bullet.position</code>, and fetching <code>bullet.velocity</code> as normal.</li>
|
||||||
|
</ol>
|
||||||
|
<p>Hell, why not remember the entire history of a variable's values?<span class="sidenote span4">Performance.</span> When I fetch the last calculated value for <code>bullet.position</code>, why not go ahead and make that a graph-crawling reference-calculation just like everything else?<span class="sidenote span4">Reactive time-dependence is something to think about for an interesting mechanic, if nothing else - keeping track of dependencies on history means you could change a value at any point throughout the game's history and see how it changes things... Just like <a href="http://achrongame.com">Achron</a>! And the flaws that make it seem infeasible here wouldn't be a problem in, say, a turn-based time game.</span></p>
|
||||||
|
<p>Performance is a legitimate worry at that point. If you include the full-on time-dependence, then depending on implementation you might end up following a reference back through every frame the game's been through. This approach would obviously fall apart because every value in your world is going to be at least O(t) to calculate, which sucks - there should be <em>no</em> time-dependent complexity - but there are solutions:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Careful design can ensure that your objects aren't too densely interlinked.</li>
|
||||||
|
<li>If you know you can do things more efficiently in some strenuous case, you can always hard-code it to extract current values and explicitly pass them around whenever you want.</li>
|
||||||
|
<li>Variables should carry metadata about when they last changed, and when their predecessors and descendents in the graph have changed - so that, in calculating the <code>shield</code>'s <code>position</code>, you don't re-fetch the <code>enemy.position</code>, if you know it hasn't changed.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Besides which, we have fast computers, and without running into hard algorithmic complexity problems (collision detection, I'm lookin' at you!) it's not <em>that</em> easy to overload a modern gaming machine. And hey, maybe having declarative time-dependent values is a pipe dream - I don't care. The core idea is still awesome.</p>
|
||||||
|
<p>Here's an example (with more attention paid to data types) of how I'd come up with a vector that always points to a set offset from the position of <code>bullet</code>.</p>
|
||||||
|
<pre><code>bullet.position = Wrapper(v(1,2))
|
||||||
|
offset = v(3,4)
|
||||||
|
endpoint = bullet.position + offset
|
||||||
|
print endpoint</code>
|
||||||
|
<samp>--> WrapperSum(bullet.position, offset)</samp>
|
||||||
|
<code>print endpoint.current_value</code>
|
||||||
|
<samp>--> v(4,6)</samp>
|
||||||
|
<code>bullet.position.current_value = v(-10,0)
|
||||||
|
print endpoint.current_value</code>
|
||||||
|
<samp>--> v(-7,4)</samp></pre>
|
||||||
|
<p>Once I've started thinking and talking about this, I start wondering how much we need imperative game loops at all, for anything other than those troublesome time dependencies and feedback loops. I wonder...</p>
|
||||||
|
<pre><code>print bullet.contacts</code>
|
||||||
|
<samp>--> Wrapper(List<Contacts>)</samp>
|
||||||
|
<code>contact_acceleration = sum(contact.force_to_resolve for contact in bullet.contacts)
|
||||||
|
bullet.acceleration = contact_acceleration</code></pre>
|
||||||
|
<p>Assuming that force due to contacts is the only thing present in the world, then the bullet now feels enough acceleration to resolve all the conflicts. I mean, assuming contacts are simple to work with, and they always are. Right? Right?</p>
|
||||||
|
<p>I'm thinking about this a lot because this kind of referencing is very natural for things like defining interlinks between components in my game engine - I've got conflicting interests:</p>
|
||||||
|
<ul>
|
||||||
|
<li>I want to keep my vectors and properties lightweight, so that a <code>bullet</code>'s position should just be a vector, with which I should be able to do math as freely and easily as integers.</li>
|
||||||
|
<li>But I also want to ensure that the <code>collision component</code>'s position is the same as the <code>bullet</code>'s position! I'd like to do <code>collision_comp.position = bullet.position</code></li>
|
||||||
|
<li>And then I run into the problem that since I want my vectors as primitive as possible, if I change <code>bullet.position</code> then it's not going to change <code>collision_comp.position</code> because pass-by-value is the dominant paradigm.</li>
|
||||||
|
</ul>
|
||||||
|
<p>The solution I've been working with is wrap together <em>sets</em> of related data (as <i>components</i>). The <code>player</code> object has a <code>PositionComponent</code> and a <code>CollisionComponent</code>, and the <code>CollisionComponent</code> stores a reference to the <code>player</code>'s <code>PositionComponent</code> so that it can access it at any time. Actually holding those references constant means that there would be problems if the <code>player.position_component</code> suddenly changed to a different object - but that should never happen. I'm satisfied with this for the reasons I implemented it in the first place, but it doesn't get me the dynamic interlinking I'd like from something more like functional reactive programming.</p>
|
||||||
|
<p>So I don't know. I would love to have the <em>capacity</em> for functional reactive programming in my game engines, at the least! It's so useful for making bulletproof dynamic interactive systems.</p>
|
||||||
|
</article>
|
||||||
|
<hr>
|
||||||
|
<article class="project">
|
||||||
|
<header>
|
||||||
|
<h1>Time Integration</h1>
|
||||||
|
</header>
|
||||||
|
<p>I find myself writing cooldowns and countdowns all the time. Bullets can only fire so fast, bombs explode after five seconds, enemies spawn every 10-15 seconds. Every time I do it, I write the same boilerplate in the initialization:</p>
|
||||||
|
<pre><code>goomba.cooldown_max = 5 // 5 seconds to cool down
|
||||||
|
goomba.cooldown_timer = goomba.cooldown_max</code></pre>
|
||||||
|
<p>and the same boilerplate in the update function:</p>
|
||||||
|
<pre><code>if goomba.cooldown_timer > 0:
|
||||||
|
goomba.cooldown_timer -= time_step
|
||||||
|
if goomba.cooldown_timer < 0:
|
||||||
|
// insert end behavior here</code></pre>
|
||||||
|
<p>and somewhere, I activate this behavior (in response to a keypress, or proximit, or contact):</p>
|
||||||
|
<pre><code>goomba.cooldown_timer = goomba.cooldown_max</code></pre>
|
||||||
|
<p>I do this kind of thing so often that I feel like it should be one of the basic functionalities offered when I'm trying to describe game entity behavior.</p>
|
||||||
|
<pre><code>// initialization
|
||||||
|
goomba.shot_timer = new CooldownTimer(length=5s, on_end=function() {...})
|
||||||
|
// update functionality should be taken care of automatically, but if not:
|
||||||
|
goomba.shot_timer.step(time_step)
|
||||||
|
// activating the timer:
|
||||||
|
goomba.shot_timer.start()</code></pre>
|
||||||
|
<p>Now, wasn't that easy?</p>
|
||||||
|
<p>Of course, that's a pretty simple case! There are obvious extensions, though:</p>
|
||||||
|
<pre><code>goomba.blink_timer = new EndlessTimer()
|
||||||
|
goomba.blink_timer.interval = 5s
|
||||||
|
goomba.blink_timer.at_progress(0%, goomba.change_color) // change color at the start of each interval
|
||||||
|
goomba.blink_timer.at_progress(50%, goomba.take_step) // take a step once every interval halfway through</code></pre>
|
||||||
|
<p>And now making timed behavior for our goomba is easy! We can even speed up the goomba easily: <code>goomba.blink_timer.interval = 3s</code></p>
|
||||||
|
<p>Ideally, you don't need to even specify when to <code>step</code> your timers - that should be taken care of automatically. Of course, that means we'd want to <em>register</em> these timers instead of simply declaring them as a member - but maybe that's a matter of a grander architectural problem.</p>
|
||||||
|
<p>Although! If we <em>do</em> let the developer take care of stepping the timers, then we can also use it for things that <em>aren't</em> time-dependent:</p>
|
||||||
|
<pre><code>player.limit_bar = new Meter(length=100) // general verison of the CooldownTimer
|
||||||
|
player.on('hit by enemy', player.limit_bar.step)
|
||||||
|
player.limit_bar.at_progress(100%, player.limit_break)</code></pre>
|
||||||
|
<p>And now we've got a way for limit breaks to engage. Assuming there's a pre-existing event system and everything is architected carefully, it's now incredibly easy to fill meters in response to events.</p>
|
||||||
|
</article>
|
||||||
|
<article class="project">
|
||||||
|
<header>
|
||||||
|
<h1>Easy Peasy State Machinesy</h1>
|
||||||
|
</header>
|
||||||
|
<p>Why do I always have to actually use boolean flags (manually setting and unsetting them) to track the states of my entities?</p>
|
||||||
|
<pre>
|
||||||
|
<code>player.shielding = new Toggle()
|
||||||
|
keyboard.on('w pressed', player.shielding.next)</code></pre>
|
||||||
|
<p>I'm just throwing this syntax together off the top of my head. The syntax isn't important - what's important is that I should be able to describe this and have it happen.</p>
|
||||||
|
<pre>
|
||||||
|
<code>strobelight.color = new Sequence(['red', 'green', 'blue'])
|
||||||
|
strobelight.update = function(dt) {
|
||||||
|
strobelight.color.next()
|
||||||
|
strobelight.draw()
|
||||||
|
}</code></pre>
|
||||||
|
<p>Seriously, don't worry about this syntax - it's ugly and I just threw it together. The point is the kinds of things I should be able to do. This is all totally feasible.</p>
|
||||||
|
<pre>
|
||||||
|
<code>goomba.ai = new StateMachine(['sleep', 'suspicious', 'alert'])
|
||||||
|
goomba.ai['sleep'].transitions_to['suspicious'].on(goomba.near(player))
|
||||||
|
// the state 'sleep' should transition to 'suspicious' on the event goomba.near(player)
|
||||||
|
goomba.ai['sleep'].update = goomba.draw_snores
|
||||||
|
|
||||||
|
goomba.ai['suspicious'].transitions_to['alert'].on(goomba.sees(player))
|
||||||
|
goomba.ai['suspicious'].update = goomba.search_for_player
|
||||||
|
|
||||||
|
// shit we forgot to make a state for just patrolling
|
||||||
|
goomba.ai.add_state('patrol')
|
||||||
|
goomba.ai['patrol'].transitions_to['sleep'].after(5 seconds)
|
||||||
|
goomba.ai['patrol'].update = goomba.wander
|
||||||
|
|
||||||
|
// oh hey, she should occasionally wake up to patrol!
|
||||||
|
goomba.ai['sleep'].transitions_to['patrol'].after(5-10 seconds)</code></pre>
|
||||||
|
<p>So y'know. State machines are powerful. In order to really use them, you need a robust event system, or else they're a huge pain - it's still possible, you just... need to code it to check the conditions on each update loop. That could get expensive!</p>
|
||||||
|
<p>For the example of checking <code>goomba.near(player)</code> - which has an optional argument for the distance - that function checks if there's already a collision detection object attached to <code>goomba</code> for setting off proximity events. If there is, it returns the event handle, which can be used for binding behaviors to the firing of that event. If a proximity collider of the right size <em>doesn't</em> exist, then it creates one, and returns the event handle.</p>
|
||||||
|
<p></p>
|
||||||
|
</article>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -3,8 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Projects, by Shoofle</title>
|
<title>Projects, by Shoofle</title>
|
||||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
<link href="/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<article class="project">
|
<article class="project">
|
@ -3,8 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Shoofle and OAuth</title>
|
<title>Shoofle and OAuth</title>
|
||||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
<link href="/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<article class="project">
|
<article class="project">
|
@ -3,8 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Projects, by Shoofle</title>
|
<title>Projects, by Shoofle</title>
|
||||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
<link href="/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<article class="project">
|
<article class="project">
|
@ -3,8 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Projects, by Shoofle</title>
|
<title>Projects, by Shoofle</title>
|
||||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
<link href="/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<article class="project">
|
<article class="project">
|
@ -3,8 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Projects, by Shoofle</title>
|
<title>Projects, by Shoofle</title>
|
||||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
<link href="/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<article class="project">
|
<article class="project">
|
||||||
@ -51,6 +51,7 @@
|
|||||||
<li>Neck wraps, shoulder wraps</li>
|
<li>Neck wraps, shoulder wraps</li>
|
||||||
<li>Fishtails (forward only, right hand only)</li>
|
<li>Fishtails (forward only, right hand only)</li>
|
||||||
<li>Rainbow Stalls</li>
|
<li>Rainbow Stalls</li>
|
||||||
|
<li>Conveyor Belts</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>I'd like to learn to spin a dragon staff someday.</p>
|
<p>I'd like to learn to spin a dragon staff someday.</p>
|
||||||
</section>
|
</section>
|
78
static/backup/tamari.html
Normal file
78
static/backup/tamari.html
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Tamari Lattices</title>
|
||||||
|
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||||
|
<link href="/static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||||
|
<link href="/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<article class="project">
|
||||||
|
<h1>Tamari Lattices!</h1>
|
||||||
|
<p>Tamari lattices are graphs (in the mathematical sense - a set of nodes with connections between them) describing a particular set of operations. I like them because they're pretty!</p>
|
||||||
|
<figure>
|
||||||
|
<img src="/static/tamari/tamari_3.png" alt="The (trivial) Tamari lattice for a three-element tree.">
|
||||||
|
<figcaption>A (trivial) Tamari lattice, generated by the associations of three elements. <a class="source" href="/static/tamari/tamari_3.dot">Source file.</a></figcaption>
|
||||||
|
</figure>
|
||||||
|
<p>Oh - oh dear. How'd that get there? Okay, that's not a very good example.</p>
|
||||||
|
<p>There are many ways to generate and think of a Tamari lattice. The way I prefer to think of it is this: Consider some binary operation - you take two elements to produce a new one. You want to combine several of these elements. So long as you have three or more elements, there are multiple ways to combine them.</p>
|
||||||
|
<p>The game we play is this: You're allowed to step from one way of combining the elements to another, but only by <i class="keyword">left-association</i>: turning <code>(a, (b, c))</code> into <code>((a, b), c)</code>.</p>
|
||||||
|
<p>The only remaining rule is that if you can step from one combination to another, the second one has to appear below the first one when you draw it.</p>
|
||||||
|
<figure>
|
||||||
|
<img src="/static/tamari/tamari_4.png" alt="A Tamari lattice for a four-element tree.">
|
||||||
|
<figcaption>As above, but generated by a four-element tree. <a class="source" href="/static/tamari/tamari_4.dot">Source file.</a></figcaption>
|
||||||
|
</figure>
|
||||||
|
<p>You can also think about it in terms of <a href="http://wikipedia.org/wiki/Tree_rotation">tree rotations</a> - but remember that that's a different tree than the one we're building as the Tamari lattice. Tree rotations are just another way to think of left-association and right-association.</p>
|
||||||
|
<p>If you look at <a href="http://wikipedia.org/wiki/Tamari_lattice">the wikipedia article on Tamari lattices</a>, you'll see a very pretty image:</p>
|
||||||
|
<img src="http://upload.wikimedia.org/wikipedia/commons/4/46/Tamari_lattice.svg">
|
||||||
|
<p>There are a lot of ways to reorganize a Tamari lattice, and it takes some artistic work to make one that really looks good. You can even visualize the same graph as <a href="http://en.wikipedia.org/wiki/Associahedron">a 3D shape called an "associahedron"</a>, but I like it in the simple gridded lattice form above. It reminds me how much beauty there can be in regularity - you can see the grid, but it doesn't look constrained by it. I might get a tattoo of the five-element Tamari lattice someday.</p>
|
||||||
|
<figure>
|
||||||
|
<img src="/static/tamari/tamari_5.png" alt="Tamari lattice for a five-element tree.">
|
||||||
|
<figcaption>Also the five-element lattice! Compare to the <a href="http://wikipedia.org/wiki/Tamari_lattice">example above, on wikipedia.</a>. <a class="source" href="/static/tamari/tamari_5.dot">Source file.</a></figcaption>
|
||||||
|
</figure>
|
||||||
|
<p>All these graphs with the ovals and the curvy lines were generated by yours truly! I made some python that would take a string representation of an association of a number of elements and convert it into an easily-manipulated memory representation. Then, a few tree rotations spit out all the possible results of left-associating on it, and it was relatively simple to print out a <code>.dot</code> file, parseable by <a href="http://www.graphviz.org/">graphviz</a>, that described the graph. It even labeled the nodes!</p>
|
||||||
|
<p><code>dot</code> happily converted them into the <code>png</code> files you're looking at. Of course, they don't have the human touch, so they're not organized into beautiful grid lines and 45° angles - but it can be fun to try to mentally reorganize them into a nicer shape. If you want, you can download the <code>.dot</code> source files for any of these, and play around with them in a graph-editing program (such as <a href="https://github.com/jrfonseca/xdot.py">XDot</a>)</p>
|
||||||
|
<figure>
|
||||||
|
<img src="/static/tamari/tamari_6.png" alt="Tamari lattice for a six-element tree.">
|
||||||
|
<figcaption>It's starting to get out of hand, I think.<a class="source" href="/static/tamari/tamari_6.dot">Source file.</a></figcaption>
|
||||||
|
</figure>
|
||||||
|
<p>Unfortunately, at a certain point I think it's going to get difficult to make these pretty. It turns out there are a lot of ways to associate a larger number of elements! Starting with a six-element tree or string, there are 42 elements (above). With seven, there are 132! Wowie!</p>
|
||||||
|
<figure>
|
||||||
|
<img src="/static/tamari/tamari_7.png" alt="Tamari lattice for a seven-element tree.">
|
||||||
|
<figcaption>Oh dear. <a class="source" href="/static/tamari/tamari_7.dot">Source file.</a></figcaption>
|
||||||
|
</figure>
|
||||||
|
<p>My server was chugging along trying to generate <code>tamari_8.dot</code> but I started getting messages from linode about going over my CPU quotas, so I canceled it - after it ran for an hour or so, without finishing. I think the seven-element one is messy-looking enough!</p>
|
||||||
|
<p>You can look at the <a class="source" href="/static/tamari/tamari.py">python script</a> I used to make this, but it's not particularly pretty - I was bored one day and decided I was going to figure out how to generate these... It's not exactly meant to be extensible. It's got a basic binary tree node class I threw together and a handful of (really ugly) helper functions. I just went through and rewrote it a bit to be nicer - the final output loop may please you if you enjoy <code>set</code>s and list comprehensions:</p>
|
||||||
|
<pre>
|
||||||
|
<code class="language-python">current_generation = set()
|
||||||
|
next_generation = {RootOfAllEvil}
|
||||||
|
edges = set()
|
||||||
|
labels = set()
|
||||||
|
|
||||||
|
while next_generation: # While there are trees to examine.
|
||||||
|
# Move to look at the next generation.
|
||||||
|
current_generation = next_generation
|
||||||
|
|
||||||
|
# Clear out the next gen to fill it with the children of this generation.
|
||||||
|
next_generation = set()
|
||||||
|
|
||||||
|
# Ensure there are labels for this generation.
|
||||||
|
labels = labels | set(label_from_node(parent) for parent in current_generation)
|
||||||
|
|
||||||
|
for parent in current_generation:
|
||||||
|
children = generate_children(parent)
|
||||||
|
|
||||||
|
labels = labels | set(label_from_node(child) for child in children)
|
||||||
|
edges = edges | set(str(parent) + " -> " + str(child) + ";" for child in children)
|
||||||
|
next_generation = next_generation | children
|
||||||
|
|
||||||
|
# Output a dot format stream!
|
||||||
|
args.output.write(u"digraph tamari {\n")
|
||||||
|
args.output.write(u"\n".join(labels) + "\n")
|
||||||
|
args.output.write(u"\n".join(edges))
|
||||||
|
args.output.write(u"\n}\n")</code></pre>
|
||||||
|
<p>The full script can be used by running <code class="language-bash">python tamari.py --length 4 | dot -Tpng > output.png</code> to produce a graph. <code>tamari.py</code> will print out to a specified file if you also include a filename: <code class="language-bash">python tamari.py --length 5 output.dot</code></p>
|
||||||
|
</article>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -3,8 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>This is a test</title>
|
<title>This is a test</title>
|
||||||
<link href="../static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||||
<link href="../static/shoofle.css" rel="stylesheet" type="text/css">
|
<link href="/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<article class="project">
|
<article class="project">
|
BIN
static/favicon.png
Normal file
BIN
static/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 765 B |
@ -8,6 +8,14 @@ article, .project {
|
|||||||
margin: 0.5em;
|
margin: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
figcaption {
|
||||||
|
font-style: italic;
|
||||||
|
font-family: serif;
|
||||||
|
}
|
||||||
|
|
||||||
.small_project {
|
.small_project {
|
||||||
border: 1px solid gray;
|
border: 1px solid gray;
|
||||||
border-radius: 1em;
|
border-radius: 1em;
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
digraph tamari {
|
|
||||||
OOOaObcde -> OOOOabcde;
|
|
||||||
OaObOOcde -> OOabOOcde;
|
|
||||||
OOaObcOde -> OOOaObcde;
|
|
||||||
OaObOcOde -> OaObOOcde;
|
|
||||||
OOabOcOde -> OOabOOcde;
|
|
||||||
OaOObOcde -> OaOOObcde;
|
|
||||||
OOabOcOde -> OOOabcOde;
|
|
||||||
OOaOObcde -> OOOaObcde;
|
|
||||||
OOOabcOde -> OOOOabcde;
|
|
||||||
OaOOObcde -> OOaOObcde;
|
|
||||||
OaObOcOde -> OaOObcOde;
|
|
||||||
OaOObcOde -> OaOOObcde;
|
|
||||||
OOabOOcde -> OOOabOcde;
|
|
||||||
OOaObOcde -> OOOabOcde;
|
|
||||||
OOaObcOde -> OOOabcOde;
|
|
||||||
OaOObOcde -> OOaObOcde;
|
|
||||||
OOaObOcde -> OOaOObcde;
|
|
||||||
OOOabOcde -> OOOOabcde;
|
|
||||||
OaObOcOde -> OOabOcOde;
|
|
||||||
OaObOOcde -> OaOObOcde;
|
|
||||||
OaOObcOde -> OOaObcOde;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user