Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Sunday, March 14, 2010

InstaPyGame progress report

I spent the last three days working on a prototype "space shooter" module for my InstaPyGame framework. I had hoped to have a prototype ready today, but the framework isn't usable yet. You can see my progress so far at my Google Code repository, but be warned; the code is messy and inconsistent, and nothing is set in stone.

However, I have created an API with which I'm satisfied. Making the sample below work properly is my goal for this prototype.


from insta.spaceshooter import *

def startDemo():

    game = Game(640, 480)
    
    player = Player()
    player.setSprite('resources/ship.gif')
    
    player.when(player.moving, 'left').setSprite('resources/bankingleft.gif')
    player.when(player.moving, 'right').setSprite('resources/bankingright.gif')
    
    shot = Shot()
    shot.setSprite('resources/shot.gif')
    
    player.setAmmo(shot)
    
    enemy = Enemy()
    enemy.setSprite('resources/alien.gif')
    
    boss = Enemy()
    boss.setSprite('resources/angryalien.gif')
    
    mapGen = LevelMapGenerator({'0' : None, '1' : player, '2' : enemy, '3' : boss})
    
    level = Level(mapGen.generate('data/levelmap1.txt'))
    level.setBGSprite('resources/space.gif')
    level.setBGMusic('resources/spacemusic.ogg')
    
    game.setLevels([level])
    game.start()

if __name__ == '__main__':

    startDemo()

Right now, I'm working on the event system and the controls, but the event system appears far more challenging. I'm planning to encapsulate the data for the "Player" and "Enemy" objects within another object, protecting the data behind its member functions. This should allow me to create a special data object that will apply its changes only when a condition is fulfilled.

Although the framework is far from complete, I'm excited about the possibilities. I have plenty of work ahead of me, but I think my goal is worth the effort.

Sunday, March 7, 2010

GSoC project idea: Insta-PyGame

I'm still trying to choose new GSoC organizations to join, but I know one of the organizations to which I'll apply: PyGame, the SDL-based Python multimedia library. I plan to write a micro-framework on top of PyGame to dramatically simplify the creation of conventional games.

The Problem

PyGame is a wrapper for the C SDL library. Some of the library hides the complexity of the underlying SDL library, but in most areas, PyGame is simply a Python binding for SDL. For that reason, you often need to write several lines of code to accomplish a simple task, such as checking whether the user has pressed a button. In addition, many pieces of the API are based on C coding idioms that are unfamiliar to most Python programmers.

The Plan

I propose the development of a new framework on to of PyGame that operates at a much higher level of abstraction. Through this new framework, people would create games by declaring the sprites the characters use, the arrangement and graphics of the levels, and the interactions between the player and the contents of the levels.

The framework would be divided into modules with each module representing a genre. The "platformer" module would contain everything necessary to create a platformer game, including a physics engine, a tile map engine, and enemies that die when you jump on them. In contrast, the "scrolling shooter" module would contain tools for controlling the behavior of projectiles and enemy ships.

Here's an example of the type of code games using the framework could look like. I haven't put much thought into the API, but I would like game code to be written at this level of abstraction.


from insta.menu import *

from insta.platformer import *



def startMenu():

    titleScreen = Screen(600, 400)
    titleScreen.setTheme(themes.MEDIEVAL)
    titleScreen.setTitle("Porcupine's Tiny Adventure")
    titleScreen.setOptions(["Play", "Controls", "Credits"])
    titleScreen.getOption("Play").setAction(startGame)
    # More code for other menu options

def startGame():

    game = Game()

    hero = Player()
    hero.setSprite("standing.gif")
    hero.setRunningSprites(["running1.gif", "running2.gif", "running3.gif"])
    hero.setJumpSprite("jumping.gif")
    hero.setDeathSprite("gravestone.gif")

    hero.setMovementTriggers(constants.ARROW_KEYS)
    hero.setJumpTrigger(constants.SPACE_BAR)

    goal = Item()
    goal.setSprite("bigring.gif")
    goal.setBehavior(constants.FLOATING)
    goal.setAction(game.nextLevel)

    itemGenerator = ItemGenerator([None, goal, hero])

    '''
    Tile generator translates level maps (text files full of numbers) into tile
    maps in a context-sensitive manner
    '''
    tileGenerator = TileGenerator()
    tileGenerator.setFloorSprite("levelground.gif")
    tileGenerator.setUndergroundSprite("underground.gif")
    tileGenerator.setPlatformSprite("platform.gif")
    # Edge and corner sprites could also be set

    mushroom = Enemy()
    mushroom.setRunningSprites(["step1.gif", "step2.gif"])
    mushroom.setDeathSprite("explosion.gif")
    # Some simple behaviors would be pre-defined
    mushroom.setBehavior(constants.WALKING)

    bird = Enemy()
    bird.setFlightSprites(["flap1.gif", "flap2.gif"])
    bird.setDeathSprite("feathers.gif")
    bird.setBehavior(constants.FLYING)

    # List associates enemy types with numbers in the text file
    enemyGenerator = EnemyGenerator([None, mushroom, bird])

    level = Level()
    level.setTileMap(tileGenerator.generateTileMap("levelmap1.txt"))
    level.setEnemyMap(enemyGenerator.generateEnemyMap("enemymap1.txt"))
    level.setItemMap(itemGenerator.generateItemMap("itemmap1.txt"))

    level.setBackground("background.gif")
    level.setBackgroundOptions([constants.TILED, constants.PARALLAX])

    game.setLevels([level])
    game.start()

if (__name__ == "__main__"):

    startMenu()

The Goal

I want to free PyGame developers from thinking about the hows of game development, allowing them to focus on the whats of their ideas. By freeing game creators from thinking about the implementation of their games, I hope to allow them to explore new ideas in video game design, such as dynamically-generated levels, media mashups, user-created content, and AI.

This is just a rough outline of the framework I'd like to build and the effects I hope to see. I plan to start work on a prototype soon if the PyGame community appears receptive to my idea.

Monday, February 22, 2010

My software development goals

I just recently finished my UF application — Woo-hoo! I'm glad to have it done, but I actually enjoyed writing one of the "statement of intent" essays. Here's the thought-provoking prompt.

What are the core skills and knowledge you hope to acquire by completing a degree in this major and how do you plan to apply these when you graduate?

I enjoyed elucidating what I hope to learn in my Computer Science program and how I plan to apply that knowledge. In the end, I came up with the following goals for my education and my career.

What I want to learn about programming

Good software design
In order to write readable, efficient code, I need to see examples of good code and learn what makes it good. I plan to study algorithms, design patterns, and best practices to learn how best to solve common programming problems.
Alternative programming methods and languages
If I only learn about common solutions to problems, I could never discover new solutions. That's why I'm going to learn about some of the more obscure and academic regions of software development, including functional programming, declarative programming, and other programming paradigms I don't even know about yet.
Low-level programming
I know that if I want to create truly groundbreaking software, I won't be able to rely on high-level languages and pretty abstractions. I'm going to learn about Assembly language and C in order to increase the efficiency of my own applications and to create entirely new OSs and languages.
Writing concurrent code
One of the safest bets in predicting the future of technology is that future computers will have an increasingly large number of processors. Applications that can't take advantage of multiple cores will soon be surpassed by programs that use concurrency effectively. I want to be on the winning side, so I'm going to learn to write concurrent applications with STM, Erlang, and *shudder* even threads. I believe knowledge of concurrent programming will be critical to many of my future projects.

How I will use my programming skills

Creating useful software
I have resolved to never work on an application that doesn't do something useful. Innovative code is nothing if it's part of a worthless piece of shovelware or a soulless enterprise application.
Making my software intuitive
I'll also try to make all my programs intuitive and easy-to-use. When I can, I'll put the needs and wants of the user first, before application structure, technological achievement, and even code readability, although I hope I never need to make that choice. I want my software to make a difference; it's rare that an application or library with an arbitrary, complex interface changes the world.
Improve the process of programming
I plan to work on projects that will not only serve typical computer users but also help other software developers. My goal is to make it easier for coders to write readable, efficient, correct code and create helpful, intuitive interfaces for their applications. I want to leave programming in a better state than I found it.
Explore new technologies
Memristors. Quantum computing. Optical processors. Biological computers. All these rapidly-approaching breakthrough computing technologies will require new programming methods to match. I will always be looking for opportunities to push the field of programming in new and exciting directions.

I know that I may not be able to learn all that I plan to learn, and I might not accomplish all that I hope to accomplish. However, writing out my programming goals has helped me to realize precisely what aspects of programming I find most interesting and important. I think every college student should list his education and/or career goals, if only to provide a derisive laugh or a grin of satisfaction when he reaches the end of his career.

Saturday, January 9, 2010

Snowflake SVG developer release

Recently, I have been learning SVG scripting by porting my old branching-web AS3 script to Javascript. This time around, I wanted to remedy some of the shortcomings of the previous incarnation. Here's a list of some of my goals and how they turned out.

Goals

  • Allow the user to customize each node individually, but don't add too much complexity.

    Success. The interface has become slightly more complex, but it's still relatively simple.

  • Let a node have only one child, allowing the user to taper the branches.

    Success. This effect is highly useful for creating snowflake patterns.

  • Improve the demo interface, enabling interactive editing of each node.

    Pending. I plan to tackle this feature next.

Demos

Classic snowflake

Screenshot of a classic snowflake drawn by my library
Click to view as SVG.


function startup(evt) {
    var svgDocument = evt.target.ownerDocument;
    
    var rect = svgDocument.createElementNS(svgNamespace, 'rect');
    rect.setAttributeNS(null, 'fill', 'skyblue');
    rect.setAttributeNS(null, 'width', '100%');
    rect.setAttributeNS(null, 'height', '100%');
    svgDocument.documentElement.appendChild(rect);
    
    var endPoint = createDataNode(0, 0, 0, []);
    var endCap = createDataNode(0, 5, 10, [endPoint]);
    var middleNode = createDataNode(60, 50, 10, [endCap, endCap, endCap]);
    var centerNode = createDataNode(360, 30, 10, [middleNode, middleNode, middleNode, middleNode, middleNode, middleNode]);
    
    var web = createWeb(centerNode, createPoint(0, 0), 0);
    
    var snowflake = createSnowflake(web);
    
    var snowflakeSVG = snowflake.toSVG(svgDocument);
    snowflakeSVG.setAttributeNS(null, 'fill', '#fff');
    snowflakeSVG.setAttributeNS(null, 'transform', 'translate(250 250)');
    svgDocument.documentElement.appendChild(snowflakeSVG);
}

Gothic cross snowflake

Screenshot of a gothic snowflake drawn by my library
Click to view as SVG.


function startup(evt) {

    var svgDocument = evt.target.ownerDocument;
    
    outerPoint = createDataNode(0, 0, 0, []);
    
    taperFork = createDataNode(0, 5, 10, [outerPoint]);
    
    bigFork = createDataNode(180, 25, 10, [taperFork, taperFork, taperFork]);
    
    nextFork = createDataNode(180, 25, 10, [taperFork, bigFork, taperFork]);
    
    innerFork = createDataNode(360, 15, 10, [nextFork, nextFork, nextFork, nextFork]);
    
    var web = createWeb(innerFork, createPoint(0, 0), 0);
    
    var snowflake = createSnowflake(web, innerFork);
    
    var snowflakeSVG = snowflake.toSVG(svgDocument);
    snowflakeSVG.setAttributeNS(null, 'transform', 'translate(250 250)');
    svgDocument.documentElement.appendChild(snowflakeSVG);
}

Nodes displayed as points

Screenshot of a web of nodes drawn by my library
Click to view as SVG


function startup(evt) {

    var svgDocument = evt.target.ownerDocument;
    
    var endPoint = createDataNode(0, 0, 0, []);
    var middleNode = createDataNode(180, 50, 0, [endPoint, endPoint, endPoint, endPoint]);
    var originNode = createDataNode(360, 50, 0, [middleNode, middleNode, middleNode, middleNode]);
    
    var web = createWeb(originNode, createPoint(0, 0), 0);
    var webSVG = web.toSVG(svgDocument);
    webSVG.setAttributeNS(null, 'transform', 'translate(250 250)');
    svgDocument.documentElement.appendChild(webSVG);
}

Download

I've packaged up all the necessary scripts and SVGs into one tiny .zip archive for your hacking pleasure. If you'd like to see what I'm working on next (and possibly help), you can view my Google Code project repository. Everything is licensed under the Apache 2.0 license, so you can use it in a proprietary application, modify it in any way you choose, or pass it to all your friends provided you indicate where it initially came from. If you do anything interesting with it, tell me about it. Happy hacking!

Friday, October 30, 2009

Programming is more than pointers and recursion

I apologize for last week's dry and boring post. This isn't a news blog, and it won't become one. I chose that topic because I was desperate to write about something relevant to programmers and the tech community, not because I wanted to write about it. Now I will only write about topics that interest me, topics that I can offer a unique perspective on. I won't become a me-too blogger.

...and now, for the reason you're reading this.

Today, I read a 2005 post from the venerable software-development blog Joel on Software about the problems with colleges teaching Computer Science through Java. I recommend you read the article before this post, but, to summarize, Spolsky says that because Java doesn't emphasize pointers and recursion, it isn't a suitable language through which to teach Computer Science. Here's why he's wrong.

Programming is more than just solving puzzles

First and foremost, I disagree with his view on the purpose of a CS program. He thinks that the goal of a college's CS program should be to weed out the students who aren't smart enough to succeed as programmers. Furthermore, he recommends that pointers and recursion should be taught as soon as possible to scare off the posers. That's poppycock.

The goal of a CS program should be to teach students how to develop high-quality software. Far too many programmers have no idea how to write readable code, much less create a large, functional system with lots of moving parts. Programming is intrinsically difficult, but teaching students only the most arcane and complex parts of the programming discipline scares away many potentially great programmers.

According to Steve McConnell, author of Code Complete, the best programmers are not necessarily the most intelligent, but the most humble. Someone who understands his mental limitations will use every technique available to simplify his code, reducing its complexity and thereby increasing its quality. Complexity is probably the number-one enemy of software quality.

Pointers and recursion aren't intrinsic to programming

All the CS theory and most of the content on pointers and recursion will never be used by the average CS graduate. Spolsky even says so:

Now, I freely admit that programming with pointers is not needed in 90% of the code written today, and in fact, it's downright dangerous in production code. OK. That's fine. And functional programming is just not used much in practice. Agreed.

He then says that these concepts teach students the mental flexibility to view a problem at several levels of abstraction simultaneously. I think this type of "mental flexibility" might account for some of the bad code recent CS graduates write. A graduate's "mental flexibility" could tempt him to demonstrate his new CS skills by writing overly complex code that functions on multiple levels of abstraction. As I said above, intelligence doesn't correlate strongly with a programming success, but ego certainly correlates with failure.

Please don't misunderstand my point. I believe that some of the most difficult areas of programming are the most important (and interesting.) I look forward to learning about recursion and its power. I plan on taking plenty of CS theory classes, learning about even the most esoteric aspects of computer programming. However, I don't think every student would benefit from this type of information. Because these topics aren't necessary to write great applications, I don't think they should be necessary to graduate from a CS program.

This post may, in fact, be completely off-base and unsupported by the facts. However, I've decided to make this blog more personal by sharing more of my opinions and writing about things I care about. I have been worried about writing content that's relevant to my intended audience, but right now, I simply don't spend enough time writing code and playing with my computer to generate a suitable flow of relevant posts. I'm reclaiming this blog as a tool against my personal battle with obscurity.


Edit: I was sorely mistaken. This post is the misguided rant of a readability zealot. See my current position here.

Friday, August 21, 2009

Help people regain speech

Every year, thousands of people around the world lose their ability to speak. Some are struck dumb by strokes, while others' voices are stolen by degenerative diseases such as ALS or muscular dystrophy. These people can regain their ability to communicate by using speech augmentation software or devices to speak for them. Unfortunately, the obscene prices of both the software and hardware prevent many people from communicating.

I want to solve this problem by developing an open-source speech-augmentation program. My goal is to create a cross-platform speaking program with both a symbol-based and text-based interface. I plan to write the program in Python with an emphasis on flexibility and extensibility. I plan to abstract both the input and output interfaces, allowing the program to be independent of both its text-to-speech engine and its GUI framework.

Consider this post a project announcement and a call to action. If you'd like to help people regain the ability to speak and you have experience with Python, interface design, text-to-speech, or accessibility, send me an email. I need all the help I can get.

Thursday, August 20, 2009

Pygame2 example game finished

Early this summer, when my Google Summer of Code proposal to the Pygame project was rejected, I told the coordinator that I would nonetheless contribute to the project over the summer. I planned on writing examples and tutorials for the Pygame2 multimedia library. Unfortunately, events conspired to prevent me from writing the examples. I had tremendous difficulty installing Pygame2 properly and no time to find the problems: I finally overcame my installation problems only two weeks ago.

Composite screenshot of all four skins Four graphical skins for your gaming pleasure!

However, I spent a great deal of time over the last week writing my first example for Pygame2. It's based on the oldalien.py demo distributed with the original Pygame, but I greatly expanded its scope. I tried to demonstrate as much of the library as I could, but I ended up using only a sliver of the library's functionality. The finished example demonstrates Surface handling, vector drawing with pygame2.sdlext.draw, text rendering with pygame2.sdlttf, image loading with pygame2.sdlimage, and sound effects with pygame2.sdlmixer. It's not an exhaustive demonstration of those concepts, but I think it's a good starting point for exploration of the library.

In addition to showing off the Pygame2 library, I tried to demonstrate best practices. I encapsulated the object instantiation and sprite drawing in external factories, allowing users with incomplete installations of Pygame2 to still see parts of the example. I only have to switch factories to drastically change the look of the game. Most importantly, I expunged the global variables from all the classes. The game still uses a couple long-life variables, but I eliminated the unnecessary ones.

If you'd like to see my uber-example in action, you can get it from its SVN repository or download it as a .tar.gz archive. If you have any trouble with the game, let me know.

Thursday, May 28, 2009

Google Summer of Code application tips

I have been meaning to write about my Google Summer of Code experience since I learned of my rejection, but I've only now found the free time to finally do it. For those who haven't heard about it, the Google Summer of Code is a program in which Google pays students $4500 to work on open source projects over the summer. (More info.) I learned about the Google Summer of Code on March 23, the first day that applications were being accepted. For the 28 days until the winners were announced, I devoted my life to perfecting my proposals, socializing with the mentoring organizations, and fantasizing about the immense heft that "GSoC student" would carry on my application to MIT.

Unfortunately, I simply wasn't good enough. I had only about 1.5 years of programming experience (none with open source projects), I was a freshman at Broward College, and I made several mistakes on my applications.

However, although I couldn't affect my programming experience or my enrolled college, I certainly could've improved my applications. Below, I've compiled a list of tips that I picked up from numerous IRC conversations, mailing list posts, and direct emails to mentoring organizations. Learn from my mistakes and net yourself that $4500 next summer!

Think inside the box

Although most of the Google documentation on the Summer of Code implies that each organization's ideas list is simply a loose guideline, you should write your proposal on a project explicitly listed on your target organization's ideas list. Resist the urge to set yourself apart from the crowd by proposing something new and revolutionary. Mentoring organizations carefully choose only the most useful projects to be listed on their ideas lists; you are unlikely to think up a project more important than the ones they chose.

Use all available tools

On the same day that I learned of my rejection, I stumbled across this invaluable resource page for GSoC applicants. It has a categorized list of mentoring organizations, a search engine for mentoring organizations, and tons more useful info. Even if the information isn't updated for GSoC 2010, it should still give you a good starting point in your search for a mentoring organization.

There's no safety in numbers

No canned applications! Sending out several generalized proposals will only waste the time you could be spending on your serious applications. You should use all your available time writing targeted, high-quality applications to specific organizations; spamming twenty organizations with your resume is simply a waste of your time and theirs.

Be professional

Don't crack any jokes unless you personally know the proposal reviewer at your target organization. When I wrote an application to Sunlight Labs in which I included one irrelevant but humorous fact and several corny lines, the proposal reviewer thought that the entire application was a joke. I promptly assured him that my proposal was in fact serious, but the damage was done.

Do the work

Unless you want a quick rejection, you should comply with all of your target organization's application requirements. If they ask you to fix a bug, you should actually fix one of their bugs, not just make a patch that somebody else suggested. If you can't dive headfirst into the development of your organization's project, you should probably find another organization. Nothing will get you rejected faster than an hole in your proposal.

Choose wisely

Only apply to organizations you know something about. Although the temptation is strong to apply to some of the obscure supercomputing or AI organizations, you can be sure that there's a bored Computer Science grad student ready to put your proposal to shame. If an organization doesn't get enough skilled students for their projects, they will return their slots to Google. However, if you apply to work on a small project you think you can handle, but the organization doesn't have enough slots for you, they might get one of the surplus slots from another organization. You have a much greater chance of success when you shoot for a project at your level.

Start now

From what I've seen, the majority of accepted Google Summer of Code students had participated in their organization before they even knew about the GSoC. The best way to increase the probability of your acceptance is to be involved in the organization before you apply to work with them. Organizations want to give their slots to students who will complete their projects over the summer and stick with them after the money stops. There's no better way to prove your commitment than to be committed, so find a project that interests you and jump in.

Monday, March 23, 2009

DirSlideShow and MultiSlideShow

These two scripts conceal all server-side directory indexing through a JSON interface, allowing you to set the location of the target pictures through the instantiation of one of the slide shows. If you'd like to see how to use DirSlideShow and MultiSlideShow, please check out this no-jargon tutorial.

DirSlideShow

DirSlideShow takes four arguments, which are listed below.

  • newPictureDir:String — The URL of the directory containing the pictures to be displayed.
  • newslideShowID:String — The id of the HTML element to which the slide show (and possibly control buttons) will be appended.
  • newRotateDelay:Number — The time (in milliseconds) until the next picture is displayed automatically. If the user clicks on one of the control buttons, the slide show will stop progressing automatically.
  • newControlButtons:Boolean — A boolean that determines if two buttons are displayed to allow the user can control the progression of the slide show.

Below is DirSlideShow's function signature:


DirSlideShow = function(newPictureDir, newSlideShowID, newRotateDelay, newControlButtons) {

MultiSlideShow

MultiSlideShow takes two arguments:

  • newPictureDir:String — The URL of a directory which contains the picture directories.
  • newContainerID:String — The id of the HTML element to which the thumbnails will be appended.

Below is the function signature of MultiSlideShow:

MultiSlideShow = function(newPictureDir, newContainerID) {

Download

I am releasing the source code of DirSlideShow and MultiSlideShow under the Apache 2.0 license.

DirSlideShow and MultiSlideShow Source Code

Demonstrations

DirSlideShow Demo

MultiSlideShow Demo

Saturday, March 21, 2009

Two Convenient Javascript Slideshows

I've decided to share two of my most useful Javascript "classes": DirSlideShow and MultiSlideShow. These classes encapsulate the necessary server-side directory indexing so that you can use the slide shows through a pure javascript interface. In other words, they're easy to use. If you'd like to see demonstrations of DirSlideShow and MultiSlideShow or download them now to follow along, please visit their project page.

How about a demonstration?

Let's say that you have a bunch of pictures in the folder images/travelpics of your web server, and you'd like to show them off to your visitors. For this task, you should use DirSlideShow. First, you need to link the scripts to the page, like so:

<script type="text/javascript" language="Javascript" src="scripts/Loader.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/DirSlideShow.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/ArraySlideShow.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/addevent.js"> 
</script>

Once you have access to the classes on your page, you need to create a the slide show by passing in the name of the directory that contains the pictures, the HTML element that will contain your slide show, the time between each change of picture, and whether you want the slide show to have controls. It sounds complex, but it's actually very simple:

<script type="text/javascript" language="Javascript"> 
addEvent(window, "load", init, false);
function init() {
var slideShow = new DirSlideShow("images/travelpics", "travelpicsdiv", 5000, true);
}
</script>

As long as you have an element with an id of travelpicsdiv, the script will find it and put a slide show in it containing the pictures of the directory images/travelpics. It's that simple.

What about the other one?

The other script, MultiSlideShow, is more specialized but probably more useful. For this demo, let's assume that you have taken three trips and put the photos in three separate directories: dubai, honolulu, and newyork. Then, you put all three directories into the directory images. Before you could create a MultiSlideShow, you would have to link to the scripts:

<script type="text/javascript" language="Javascript" src="scripts/Loader.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/MultiSlideShow.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/ArraySlideShow.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/addevent.js"> 
</script>

You would now start a MultiSlideShow by passing only two arguments: the name of the enclosing directory, images, and the id of the div to be filled, travelpicsdiv.

<script type="text/javascript" language="Javascript"> 
addEvent(window, "load", init, false);
function init() {
var slideShow = new MultiSlideShow("images/multislideshow", "multislideshowdiv");
}
</script>

Voila! Your div, travelpicsdiv, will now be dynamically populated with the pictures in dubai, honolulu, and newyork. Once again, there's nothing left to do. Almost.

Configuration

The one assumption that these scripts make is the location of the directory-indexing script relative to the page on which the slide show resides. If your page is in the directory www and your scripts are in the directory www/scripts, the setup will work fine right out of the .zip file. However, if you put your html in a directory www/html and your scripts in a directory www/js, you'll need to do a little configuration. Don't worry; it won't hurt a bit.

There are only two variables in one file that need to be configured: dirIndexURL and htmlPageURL, which are both in scripts/Loader.js. dirIndexURL contains the URL of the script dirindex.php relative to the HTML page that contains the slideshow. htmlPageURL contains the URL of the HTML page relative to the script dirindex.php.

Let's go back to our previous example, in which the page resides in www/html and the script resides in www/js. To re-configure the script, you would replace these lines:

// URL of directory-indexing script relative to HTML page
var dirIndexURL = 'scripts/dirindex.php';
 
// URL of HTML page relative to directory-indexing script
var htmlPageURL = '../';
…with these:
// URL of directory-indexing script relative to HTML page
var dirIndexURL = '../js/dirindex.php';
 
// URL of HTML page relative to directory-indexing script
var htmlPageURL = '../html/';
Now, just reset the script tags properly:
<script type="text/javascript" language="Javascript" src="scripts/Loader.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/DirSlideShow.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/ArraySlideShow.js"> 
</script> 
<script type="text/javascript" language="Javascript" src="scripts/addevent.js"> 
</script>

…and set the position of the images relative to the HTML page:

<script type="text/javascript" language="Javascript"> 
addEvent(window, "load", init, false);
function init() {
var slideShow = new DirSlideShow("../images/travelpics", "travelpicsdiv", 5000, true);
}
</script>

And you're done!

I know that there are much flashier slide show scripts available for both Javascript and ActionScript with fancy transitions and flashy picture ribbons. Nevertheless, I'm almost certain that few of those scripts are as convenient, robust, and secure as this one. You can find a full description of these classes' features and usage instructions in their project page.

Thursday, February 5, 2009

WebPattern & ControlPanel

I've finally finished my first visually impressive AS3 project: the WebPattern class. It takes four arrays as arguments: branches, which represents the number of branches originating from each node; branchAngles, which determines the angle between the two farthest branches of a node; branchLengths, which determines the length of the branches originating at a node; and jointWidths, which governs the width of the branches where they connect at a node. If you don't understand my explanation, you can check out a demo.

Here are a couple of warnings before you start fiddling. First, this program is relatively processor intensive, because each new layer of branches dramatically increases processing time. If you want a pattern with five layers, you had better make sure that none of the nodes has more than five branches. This program will kill your computer if you aren't careful.

Second, all of the arrays you pass in as arguments have to be the same length. Otherwise, you'll get silent failure, unless you have the debug Flash plug-in. Also make sure that all of the nodes have at least two branches and none of the other arrays have a zero in them.

WebPattern may be a unique and incredibly fun-to-play-with class, but ControlPanel is a very useful class for demoing classes and apps. That box in the top-right corner that lets you create patterns is an instance of ControlPanel. Creating that panel took only six lines of code: one for instantiation, one for each input field, and one to add it to the stage. It seals away most of the painful interface construction and data management steps.

For example, for this implementation, I had to do only three things to implement the control panel and hook it up to my web pattern drawer. First, I had to construct it:


fields = ['Branches:', 'Branch Angles', 'Branch Lengths:', 'Joint Widths:'];
defaults = ['2, 5, 3','180, 180, 60','50, 50, 50','6, 6, 2']
controlPanel = new ControlPanel('Arial');
for (var i:uint = 0, j:int = fields.length; i < j; i++) {
 controlPanel.addTextInput(fields[i], defaults[i]);
}
addChild(controlPanel);

I only used the arrays to abstract the naming of the fields; you can call it manually if you would like. Next, I added some event listeners:


controlPanel.addEventListener(ControlPanel.SUBMIT, submitListener, false, 0, true);
controlPanel.addEventListener(ControlPanel.CLOSE, closeListener, false, 0, true);

Finally, I created some listening functions. Notice how the submitListener() function only has to retrieve the data from controlPanel with data and access it through the input field names:


private function submitListener(evt:Event):void {
 destroyWebPattern();
 var arguments:Array = [];
 var rawData:Object = controlPanel.data;
 try {
  for (var i:uint = 0, j:int = fields.length; i < j; i++) {
   var fieldData:String = rawData[fields[i]];
   fieldData.replace(' ', '');
   arguments[i] = fieldData.split(',');
  }
  createWebPattern(arguments[0], arguments[1], arguments[2], arguments[3]);
 } catch (e:Error) {
  trace(e);
 }
}
  
private function closeListener(evt:Event):void {
 removeChild(controlPanel);
}

Even if you don't want to analyze that code, the lack of TextField, embedFonts, and defaultFormat should be apparent. Just remember that the ControlPanel relies on embedded fonts; make sure to embed whatever font you'd like it to use and export it for ActionScript.

Check out the demo and the source. I hope you'll have fun with my new toy and new tool.

Monday, January 12, 2009

Are bookmarklets still cool?

I'm by no means an accomplished Javascript programmer, but I'm pretty good at writing small scripts and very lazy when I'm faced with repetitive tasks. So, when I wanted to rip a series of pictures off a website's page (and I had asked permission from the website's owner), I wrote a small Javascript bookmarklet to do it for me.

Just type cut and paste the following code into a bookmark, then click on the bookmark on whichever page has the pictures you want. It will leave you with a page full of image tags you can cut and past onto your own site, provided you got permission from the pictures' owner.

javascript:var htmlDiv = document.createElement('div');var garbageDiv = document.createElement('div');var pageImages = document.images;while (pageImages[0]) {var cleanImage = document.createElement('img');cleanImage.setAttribute('src', pageImages[0].src);htmlDiv.appendChild(cleanImage);garbageDiv.appendChild(pageImages[0]);} var body = document.getElementsByTagName('body')[0];body.style.backgroundColor = '#ffffff';body.innerHTML = '';void(body.appendChild(document.createTextNode(htmlDiv.innerHTML)));

It's a relatively ugly script, but it's easily understandable, nonetheless. It starts by initializing a couple variables: htmlDiv to store the pictures and garbageDiv to hold the pictures that have already been scanned. pageImages just saves me the trouble of typing in document.images over and over again. A simple while loop runs while there is something in the first slot of pageImages. Within the while loop, a new, blank img element called cleanImage is created, given the src of the current picture, and appended to htmlDiv. The current image is then appended to garbageDiv, thus removing it from the page and the pageImages array. Once the loop terminates, the whole page is restyled to have a white background (the website I made it for had a black background) and its contents are replaced by the HTML inside htmlDiv.

If you're wondering, that void() block at the end is necessary because bookmarklets are required to return something. If you didn't have that block there, the last line of code would return true and the only thing left on the screen would be true.

I have at least one more bookmarklet to show off when I again run out of things to say. It's a little more specialized, but it's useful, nonetheless.

Saturday, January 10, 2009

Python Impressions

Why on earth would you care what I think about Python? I mean, really, what can I say about it that someone else hasn't? I'm not the most experienced programmer, so I can't give you an exhaustive analysis, and I'm not clueless about programming, so I can't tell you what it's like to learn programming from Python.

So, instead of giving an outstanding take on Python, I'll give you just a normal programmer's opinion. I'm not remarkable in the world of programming, so my opinion will probably be closer to yours than some coding luminary's. So here it is, Python through the eyes of a smalltime Javascript, ActionScript 3, PHP programmer. Please note, I just started writing Python a couple of days ago, so this evaluation will not be exhaustive.

However, even in that short time, I've noticed a couple things. First of all, I got a whole lot done. Even in the brief time that I've actually been writing scripts with Python, I've managed to replace a sizable amount of PHP code. I've almost finished writing an object-oriented Python include scheme for my websites.

I was going to put a paragraph here about how Python doesn't support private methods and variables, but then I googled "Python private methods" and found out how to make your methods private. You just need to add two underscores before the name of the method. I'm glad that I don't have to leave my programs' private parts exposed, but I'm disappointed that I had to backspace my eloquent and somewhat insinuating "No private methods" rant.

This topic will probably come back up later, when I have more of an opinion on Python. For now, I'm feeling a little too ignorant to continue.

Wednesday, December 17, 2008

Leave the physics to me!

I'm finally "done" with my AS3 game engine now. It doesn't play music, support sound effects, or use character animation at all (okay, maybe a little), but it doesn't try to. I'll give you an example of how it would work.

First, you'd have to download the file. Then, you alter the levels.xml file with to point to the levels' background images and ground profiles. You add the enemies with the <enemy /> tag, the player controlled character with the <fighter /> tag, and the goal with the <goal /> tag. You can alter the position of the fighter, the goal, and the enemies and change the background image and layout of the level without even recompiling the code.

To add a character, you do have to start up flash, but you don't have to do any real coding. Simply make a class for your character in the com.flashgames.bunnyhopper file, set the max speed, jump height, and acceleration through simple variables, and associate the class with a library object. Now, you can add your character to the level by simply altering the levels.xml file.

It's not the most sophisticated game engine, or the most open-ended, but anybody (with flash) can easily reshape the game with a little HTML understanding and little-to-no programming knowledge. Let's see you do that with APE or Box2D!

Play a quick demo or download the source.

Friday, September 5, 2008

Convenient AS3 Positioning Class

I'm sure I'm not the only new-to-AS3 programmer who longed for the convenience of HTML. In HTML, everything you put on the page spreads out and covers the viewing area.

Not so with ActionScript. In ActionScript 3, you must position each object manually by setting its x and y coordinates. It's precise, but it's a pain when you just want all your interface buttons visible. 

Enter Styler 0.1! This convenient class allows you to position objects relative to each other, more like you would with HTML. It's pretty simple to use, and its behavior is pretty easy to predict. You can download it, see some examples, and a try out a demo at my site. I hope it makes your life easier!

Friday, August 29, 2008

ActionScript 3 packages done right

As a somewhat semi-experienced XHTML/CSS programmer, I made several large mistakes when I started object-oriented programming in AS3. There just isn't much documentation on the basics of AS3 packages and package structure, even in instructional books. So here's my take on it, based on hard experience.

You should start your AS3 programming adventure by creating a high-level directory for all your your classes. I called mine 'Classes'. Now, open up Flash and register this directory so that Flash can find it and use the classes in it. In windows, you can do this by going to Edit>Preferences, clicking on ActionScript in the tab on the side, clicking the button that says 'ActionScript 3 Settings...', and clicking the button with the crosshairs on it. In the dialog box that pops up, find your 'Classes' directory and click 'Ok'. Now, Flash can find your classes!

Say that you're creating an AS3 application for somesite.com called Flashy Flash App. The tradition would be to create this file structure in your class directory: com>somesite>flashyflashapp. This way, all the classes for that site will be in one central place, separate from all your other sites' classes. In this file, you would create a document class called FlashyFlashApp.as. Here's how you would start the class:


package com.somesite.flashyflashapp {
 public class FlashyFlashApp {
   /* Lots of code goes here */
 }
}

You should note several key details. First, the file path between package and first bracket is relative to the main class directory. That means, the location of your .fla, flashyflashapp.fla, is completely irrelevant to the package info. Second, note that the class' name exactly matches its filename, including capitalization. If you don't do this, you'll encounter all sorts of nasty errors.

To link the .fla to the document class (the code that starts up the program), type its location into the text box that says 'Document Class' beside it like so:

com.somesite.flashyflashapp.FlashyFlashApp

This, too, is case sensitive, so be very careful with your caps. Now, any code inside the document class, FlashyFlashApp.as, will execute as soon as the program runs.

If you're like me, you've got a big question right now: "What about once I try to put the finished swf on my site? Won't I have to move all those classes and update all those package definitions?" Luckily for you, the answer is no. Unlike CSS, Javascript, or any of the other web technologies I was comfortable using, all of the required code for a Flash swf to run is in the one central swf. The only part of all this work that you will put on your actual web server is the final swf. Unless your script uses one of AS3's loading classes, like Loader or URLRequest (or whatever), you won't have any problems using just that one small swf.

If you've managed to stay interested this long, I commend you. I hope this post will help at least one person avoid some of the mistakes I made. Thanks for reading!