Yesterday afternoon I drove out to Kirk County Park in Ottawa County, on the shore of Lake Michigan, to catch the last sunset of the year. Click any of the photos below to see the rest of the set. Or you can see the entire set as a slide show.
Pickerel Lake, 26 December, 2011
Photos taken the day after Christmas at Pickerel Lake in West Michigan. Click the photo above to see the rest of the set on Flickr.
On Walking to Work
For most of my career as a developer – say, nine of the past twelve years – I have lived within two miles of my workplace. Cybernet, BBK/PeopleDesign and now, Cynergy. On heavy traffic days it is actually faster for me to walk to work than to drive. Even on good days, driving saves me, at best, ten minutes in each direction. When weather permits, I ride my bike.
But I like best to walk. Especially in the morning, when the city is still waking up. The best days are in the cold parts of the year when the sun is just hitting the tops of the highest trees and buildings. Those are also the days when I walk home after dark.
Biking is more efficient, certainly, but – weather aside – I trust the drivers on the road less than during brighter parts of the year. There are fewer bikers from November through March, so drivers are even less aware of them (us) than usual. I can then choose to slalom quickly on the streets, slowly on the sidewalk, or just walk.
Currently I am exactly a mile and a half from work. The walk takes a little less than half an hour each way. Call it a total of fifty minutes a day, for three miles. Fifteen miles a week, and slightly over four hours. Sometimes I will stop for coffee at MadCap or the Grand Central Market. On the way home, I will often swing by the library. Sometimes I will stop back at the Grand Central Market for a sandwich.
The smell of the city changes from block to block and from month to month. In the summer, the city smells green and steamy. In the winter, earth and smoke. Currently, in the morning the scent trail goes something like this: leaves, earth, bread baking, pavement, car exhaust, bus fumes, cigarette smoke, concrete, pancakes, coffee, river, and occasionally hops from one of the local breweries. Each day is unique as a fingerprint.
This is the last work day of the year. Since i started this job on August 22, I have driven to work exactly twice. Call it 18 weeks. Or 17, when holidays are removed. So 17 weeks, five work-days a week, three miles a day. 255 miles. Or in my Subaru, a full tank of gas. Extrapolate it out and it is around 750 miles a year of using alternate transportation.
And the best part is that I feel more connected with Grand Rapids than I have in years. Working in front of a computer for 8+ hours a day, even in an office full of good people, is kind of alienating. Walking brings me back to earth.
Accessing Views From Flash in Drupal Gardens
Wow, life can be whacky.
So I am pretty sold on Drupal Gardens as a base for most of my future development projects. However, there are still a couple of useful pieces missing, that are out-of-the-box available on a full Drupal install. Specifically, the Services module. Services allow alternate means of accessing data stored in the Drupal database. So if I want to, say, use Drupal as a content management system for a Flash game, I can just pull information in as and when I need it, by referencing a URL and passing the appropriate parameters.
Drupal Gardens doesn’t allow that yet. Well, technically they do, but only in very specific ways, none of which are ideal for using Drupal as a straightforward CMS. Having said that, apparently adding this functionality is something they are looking into.
But enough carping! It is possible to use DG as a CMS for a Flash (or AJAX, or Silverlight, etc) application, provided you only need to pull content out of the database, not put it back in. It just takes a bit of a work-around to get everything up and running.
Note: The rest of this post assumes a familiarity with Actionscript, Drupal Views and RSS feeds. If not, take a few minutes to read up on them.
The Views module allows the contents of a view to be published as a Page, as a Block, or as an RSS feed. Say I am making a role-playing game, and I need to populate the world therein with wildlife. To keep things simple, each critter has the following information points:
- name
- description
- terrain (where the creature might be encountered)
- associated element ( from the classic 5, for combat purposes)
So after entering data for several animals, you would end up with a table which looks something like this:
Name | Description | Terrain | element |
---|---|---|---|
squirrel | cute, fluffy, voracious | forest | wood |
camel | cute, fluffy, spits a lot | desert | water |
walrus | truly, nature’s most majestic animal | plains | earth |
…at least, that’s how it looks in the database. To get it into Flash (in Drupal Gardens, at present) requires a little more work. But not a lot more work.
Pulling the RSS feed of a view is quite simple. Just create a “feed” version of an existing view, and set up a URL path for it, and voila! You have a feed of the contents of a view.
However, note that the actual contents of a view, when delivered in an RSS feed, are all packed into the <description> tag of the view, and include all of the HTML which would normally be rendered in the page. It looks something like this:
http://ecceludum.drupalgardens.com/feeds/monsters/terrain/desert en http://ecceludum.drupalgardens.com/content/camel <div class="field field-name-body field-type-text-with-summary field-label-hidden"> <div class="field-items"> <div class="field-item even" property="content:encoded"> <p>camel text</p> </div> </div> </div> <div class="field field-name-field-monster-element field-type-taxonomy-term-reference field-label-above"> <div class="field-label">element: </div> <div class="field-items"> <div class="field-item even"> <a href="/elements/water" typeof="skos:Concept" property="rdfs:label skos:prefLabel">Water </a> </div> </div> </div> <div class="field field-name-field-monster-terrain field-type-taxonomy-term-reference field-label-above"> <div class="field-label">terrain:&nbsp; </div> <div class="field-items"> <div class="field-item even"> <a href="/terrain/desert" typeof="skos:Concept" property="rdfs:label skos:prefLabel">desert </a> </div> </div> </div> Thu, 15 Dec 2011 18:22:47 +0000 John Winkelman 71 at http://ecceludum.drupalgardens.com http://ecceludum.drupalgardens.com/content/camel#comments
All well and good, except boy, are the contents of the DESCRIPTION tag ugly. That is because the angle brackets, ampersands, quote marks and non-breaking spaces have been re-written as plain text character entities. In a sense, they have been rendered as a picture of source code, rather than source code. There is a simple fix for this: When Flash pulls in an RSS feed (or any other XML-based document) it pulls this content in as plain text. It is not structured as XML until after it is loaded into the Flash movie. This means that the string can be parsed internally, and all of the character entities turned into their respective text elements. E.g. each instance of “>” can be replaced with a “>”. The simplest way might be the following line of code:
var newString = oldString.split("<").join("<").split(">").join(">").split(""").join("\"").split(" ").join(" "); var myXML = new XML(newString);
If that is run on the preceding big ugly bit of RSS feed, then the contents of the DESCRIPTION tags would suddenly look like this:
<div class="field field-name-body field-type-text-with-summary field-label-hidden"> <div class="field-items"> <div class="field-item even" property="content:encoded"> <p>camel text</p> </div> </div> </div> <div class="field field-name-field-monster-element field-type-taxonomy-term-reference field-label-above"> <div class="field-label">element: </div> <div class="field-items"> <div class="field-item even"> <a href="/elements/water" typeof="skos:Concept" property="rdfs:label skos:prefLabel">Water </a> </div> </div> </div> <div class="field field-name-field-monster-terrain field-type-taxonomy-term-reference field-label-above"> <div class="field-label">terrain: </div> <div class="field-items"> <div class="field-item even"> <a href="/terrain/desert" typeof="skos:Concept" property="rdfs:label skos:prefLabel">desert </a> </div> </div> </div>
Now the contents of the DESCRIPTION element of the RSS feed XML are structured and can be parsed using the Flash XML tools. In this instance, you would look for the contents of the elements div.field-name-field-monster-element a, div.field-name-field-monster-terrain a, and div.field-name-body p.
You will note that there are a lot of extra DIV tags, and many of them have huge long class names and/ir IDs. This is not a problem for two reasons: first, the data is well-structured, and second, it is consistent. Unless there are changes to the structure of the View in Drupal Gardens – e.g. changing the “terrain” data field to be called “territory” instead – every time the data is pulled from this RSS feed for this View, it will have exactly the same structure. Having five records or ten thousand won’t change things.
So there it is: An overview of how to access Views information from a Flash movie, via RSS, in Drupal Gardens.
Wikipedia as a Seed for Flash Fiction
Lacking for a creative outlet, I recently tried a new writing exercise:
- go to the front page of Wikipedia
- click “random article”
- research/plan for a maximum of one minute
- write for fifteen minutes, or 500 words, or one page, or some other arbitrarily small limit
You must use the first random page that comes up, and the subject of that random page must be integral to the story. No picking and choosing.
It actually turned out to be a lot of fun! In one afternoon I wrote short pieces about a coastal town in Kenya, an early 20th century ceramics artist, data compression, and a Dungeons and Dragons version of Hell. All told, a little over an hour of writing. My mind felt limbered up and cleared out. Dusted off, even; like hitting the gym after an extended absence. My favorite part was that it broke me out of my comfort zone. I know next to nothing about Kenya, or ceramics. But that is still more than I knew before I tried this exercise.
In a way, this could work as a brainstorming exercise for an external topic. Trying to fit disparate ideas into a common narrative creates new viewpoints for that narrative. Imagine writing a story about wineries of the Great Lakes region, and when stuck for inspiration, randomly hitting the following five pages: Inger Giskeødegård, Tahuna Breaks, Vincent Hallinan, List of Pittsburgh Pirates first-round draft picks, and Telephone numbers in the British Indian Ocean Territory. For each page, try to fit the the content or concept into the larger narrative. Completely random brainstorm. Let your mind go where it will. At the end of the exercise, go back through and see if there are any useful insights; any new and unusual ways of thinking about Great Lakes wine.
Procedural Generation X – User Modified Content
Having all the content in a game created dynamically simplifies many aspects of game design. One code base can potentially create an infinite number of unique gaming experiences. However, what if you want to include a save game feature? If the game content is created anew every time the game is loaded, how is it possible to close the game, then pick it up tomorrow without losing all my progress?
Fortunately, the very act of creating locations and objects can be used to allow data to persist across multiple sessions. Here is an example:
Imagine you have created a dungeon crawl in a procedurally generated cave. The player has the option to dig through walls to reach e.g. deposits of minerals. You want to have a save-game feature, but you don’t want to have the caves reset to new every time the game is reloaded.
Every location in the cave has a unique x/y coordinate, starting at the upper left corner with (0,0) and ending at the lower right with (63,63). Each of these points is either a wall or a floor tile. Now here is the brain-twisty part: you don’t need to store the individual tiles of the original state. Every time the tile map is regenerated, it will be exactly the same. It doesn’t need to be stored.
Your character blows up a chunk of wall, say, at (20,20). Suddenly, the tile map has changed. It has history. It exists in a state different from the one which was produced by the algorithm which created it. Does that mean the entire map needs to be saved now? No! The only piece which needs to be saved is the piece which has changed. And this can be done by creating a data file which saves only the changed pieces of the map.
{
x:20,
y:20,
z:0
terrain:0
}
Reading the above data, we can see that the map coordinate 20,20 on level 0 should be to the terrain-type 0. So a workflow would look something like this:
- generate the initial map data
- look for a save game file
- iterate through the save game file and, where necessary, change the tiles.
- render the map to the screen
Red-Tailed Hawk in Downtown Grand Rapids
Yesterday a large red-tailed hawk took a breather on a light pole just outside the Cynergy offices. I managed to grab a few shots before it took off. Clicking any of the photos will take you to the full-sized images on Flickr.
Rosy Mound Natural Area
This past Saturday I took a long walk along the beach at the Rosy Mound Natural Area in Ottawa County. The highlight: a pair of bald eagles eyeballing me from a tree at the edge of the dunes. Click here to see the whole set.
Away3d and Flash Player 11 – Source Code
Here is the source code for the Flash experiment I posted on Thursday.
package { import away3d.containers.ObjectContainer3D; import away3d.containers.View3D; import away3d.debug.AwayStats; import away3d.entities.Sprite3D; import away3d.filters.BloomFilter3D; import away3d.filters.BlurFilter3D; import away3d.filters.DepthOfFieldFilter3D; import away3d.lights.DirectionalLight; import away3d.lights.LightBase; import away3d.lights.PointLight; import away3d.materials.BitmapMaterial; import away3d.materials.ColorMaterial; import away3d.materials.methods.FogMethod; import away3d.primitives.Cube; import away3d.primitives.Plane; import away3d.primitives.Sphere; import flash.display.BitmapData; import flash.display.BlendMode; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.geom.ColorTransform; import flash.geom.Vector3D; import flash.utils.getTimer; /** * Cubes01 Stage3D Demo by Felix Turner - www.airtight.cc * Modified by John Winkelman - www.eccesignum.org */ [SWF( backgroundColor='0xffffff', frameRate='60', width='800', height='600')] public class Cubes02 extends Sprite { private var CUBE_COUNT:int = 500; private var MATERIAL_COUNT:int = 30; private var CUBE_SIZE:int = 10; private var view : View3D; private var cubes:Array = []; private var cubeHolder : ObjectContainer3D; private var theta:Number = 0; private var radius:Number = 150; private var orbitSteps:Number = 1000; // number of steps necessary to complete one orbit private var orbitSpeed:Number = Math.PI*2/orbitSteps; //amount by which theta will be incremented at each interval private var objectInterval:Number = orbitSteps/CUBE_COUNT; // distance between objects on the curve private var objectPosition:Number; private var direction:Number = 1; // or -1 - controls direction of orbit public function Cubes02(){ super(); stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; //init 3D world view = new View3D(); view.camera.z = -1000; addChild(view); //init object to hold cubes and rotate cubeHolder = new ObjectContainer3D(); view.scene.addChild(cubeHolder); //add lights var light:PointLight = new PointLight(); light.position = new Vector3D(-1000,1000,-1000); light.color = 0xffeeaa; view.scene.addChild(light); var light2:PointLight = new PointLight(); light2.position = new Vector3D(1000,1000,1000); light2.color = 0xFFFFFF; view.scene.addChild(light2); //init materials var materials:Array = []; for (var i:int = 0 ; i < MATERIAL_COUNT; i ++ ){ var material : ColorMaterial = new ColorMaterial(Math.random()*0xFFFFFF,1); //material.blendMode = BlendMode.ADD; material.lights = [light,light2]; materials.push(material); } for (var j:int = 0 ; j < CUBE_COUNT; j ++ ){ var s:Number = CUBE_SIZE; var cube:Cube = new Cube(materials[j % MATERIAL_COUNT], s,s,s); cubeHolder.addChild(cube); cube.x = 0; cube.y = 0; cube.z = 0; cubes.push(cube); } //add stats addChild(new AwayStats(view)); this.addEventListener(Event.ENTER_FRAME, onEnterFrame); stage.addEventListener(Event.RESIZE, onStageResize); onStageResize(null); } private function onStageResize(event : Event) : void{ view.width = stage.stageWidth; view.height = stage.stageHeight; } private function onEnterFrame(ev : Event) : void{ cubeHolder.rotationX+=.2; cubeHolder.rotationY+=.4; cubeHolder.rotationZ+=.8; for(var i:int=0; i < CUBE_COUNT; i++) { objectPosition = orbitSpeed*objectInterval*i; // each object is individually updated /* OBJECT MOVEMENT CODE GOES HERE */ cubes[i].x = radius * (Math.cos(theta + objectPosition) * (Math.pow(5,Math.cos(theta+objectPosition)) - 2 * Math.cos(4 * (theta+objectPosition)) - Math.pow(Math.sin((theta+objectPosition)/12),4))); cubes[i].y = radius * (Math.sin(theta + objectPosition) * (Math.pow(5,Math.cos(theta+objectPosition)) - 2 * Math.cos(4 * (theta+objectPosition)) - Math.pow(Math.sin((theta+objectPosition)/12),4))); cubes[i].z = radius * Math.sin(theta + objectPosition) - radius*1*(Math.sin((radius/radius + 3) * (theta + objectPosition))); /* OBJECT MOVEMENT CODE GOES HERE */ } theta += (orbitSpeed*direction); view.render(); } } }
Most everything is a duplication of a block of code I snagged from Airtight Interactive’s Stage3D vs. WebGL demo. In addition to finally understanding something of how programming for 3d interfaces works, this gave me an opportunity to dive back into some of the trigonometry experiments I built back in the day.
In the code above, look at the method onEnterFrame. In it, inside the for loop, are three lines which update the x, y, and z coordinates of each block. Those blocks have some scary looking math attached to them; lots of sin and cos and radii, and thetas. I cheated – I actually wrote that code almost three years ago for my Simple Trigonometric Curves Tutorial over on Kongregate. X and Y positions are set using a transcendental Butterfly curve. The Z position is set using a variation on an Epicycloid curve. For fun, grab some of the other curves out of the tutorial, and plug them in in place of the current formulae. If you come up with something interesting, post it.
Away3d and Flash Player 11
Click the image above to launch the experiment. Requires Flash Player 11. May beat up on older computers. A lot.
What you see here is a simple example of what the Flash 11 player is capable of. There are 500 cubes, dynamically lit, moving through a “Transcendent Butterfly” curve on the x and y axes, and a variation of an epicycloid in the Z. The whole formation is oscillating through the x, y, and z axes as well. The little box in the upper left corner shows frame rate and the amount of RAM which the animation is using. I have had as many as 1000 cubes running through this animation but the frame rate dropped down below 30 FPS. 500 cubes is plenty for the moment.
This animation was created using the Away3d code library.