flash

In Development: Word Attack (prototype)

I have been working on a prototype for a new Flash game, codenamed “Word Attack”. The finished game will eventually be submitted to Word Play- A Flash Game Contest, that is being hosted by Dictionary.com and Mochi Media. Check out the prototype below…

Note: There is no gameplay mechanic revolving around the blocks turning red after they stop moving, this is just something that the Box2D API does to let the developer know that objects are “sleeping” (not being simulated anymore).

As you can see, the player’s goal is to clear every level by creating words with the letters provided (for the prototype I created nine levels). One thing that is worth pointing out is that the player has the choice of completing a level in whatever fashion the player chooses, as long as the player clears out all the letters in the level by typing in valid words. For example, in level seven the letters falling down consist of “c”, “o”, “m”, “p”, “u”, “t”, “e”, and “r”. So the player can complete the level by either typing in “computer”, or by typing in “mop” and then typing in “cuter”.

I plan to expand more on the gameplay by working with a game designer, since it feels like it needs a bit more “fun” in order for it to not just be Scrabble with physics. This is also the first time I have used the Box2D API to develop a Flash game, and I must say, it’s turning out quite well so far :) .

Feel free to comment on the game, I’m also open to suggestions on gameplay or anything in general related to the game.

Final result of Box2D Chapter 1

I mention in my last post that Todd Kerpelman created a set of Box2D video tutorials (http://www.kerp.net/box2d/), I just finished up the first chapter and here is what I came up with…

As you can see it isn’t a whole lot, just a bunch of boxes falling down, but damn does it look good :) .

Here is the source code for the project

package  
{
	import Box2D.Collision.b2AABB;
	import Box2D.Collision.Shapes.b2PolygonDef;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Dynamics.b2World;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;
	import fl.controls.Button;
	import flash.events.MouseEvent;
	
	/**
	 * Final result of Todd Kerpelman's chapter 1 box2d video tutorial
	 * (http://www.kerp.net/box2d/).
	 * The code here is pretty much line for line from Kerpelman's tutorial
	 * I added a small modification so the simulation may be restarted when
	 * the user clicks the restart button in the top left of the screen.
	 * @author Edgar Miranda
	 */
	public class HelloBoxWorld extends MovieClip
	{
		
		protected var _world:b2World;
		
		// Ratio of pixels to meters
		public static const RATIO:Number = 40;
		
		// Number of frames until we launch another crate
		private var _nextCrateIn: int;
		
		// Button to restart simulation
		public var restartButton: Button;
		
		public function HelloBoxWorld() 
		{
			// 1. Set up the world
			setupWorld();
			// 2. Creating walls and floor
			createWallsAndFloor();
			
			setupDebugDraw();
			
			_nextCrateIn = 0;
			
			addEventListener(Event.ENTER_FRAME, newFrameEvent);
			
			// Put the restart button on the top most index 
			// so it isn't covered by the falling crates
			addChild(restartButton);
			
			// Event listener in order to restart 
			// simulation when the restart button is pressed
			restartButton.addEventListener(MouseEvent.CLICK, onRestartButtonClick)
		}
		
		private function onRestartButtonClick(e: MouseEvent): void {
			
			// Remember that the world counts as one body so you
			// want to remove bodies until there is only one body left
			while (_world.GetBodyCount() > 1) {
				_world.DestroyBody(_world.GetBodyList());
			}
			
			// recreate the walls again
			createWallsAndFloor();
			
			// set to default value
			_nextCrateIn = 0;
		}
		
		private function setupDebugDraw():void
		{
			var spriteToDrawOn:Sprite = new Sprite();
			addChild(spriteToDrawOn);
			
			var artistForHire:b2DebugDraw = new b2DebugDraw();
			artistForHire.m_sprite = spriteToDrawOn;
			artistForHire.m_drawScale = RATIO;
			artistForHire.SetFlags(b2DebugDraw.e_shapeBit);
			artistForHire.m_lineThickness = 2.0;
			artistForHire.m_fillAlpha = 0.6;
			
			_world.SetDebugDraw(artistForHire);
		}
		
		private function newFrameEvent(e:Event):void 
		{
			_world.Step( 1.0 / 30, 10);
			
			// Every few frames, until a certain numer of crates have been added
			if (_nextCrateIn-- <= 0 && _world.m_bodyCount < 80) {
				
				// add a random create to the world
				addARandomCrate();
				_nextCrateIn = 1;	
			}
			
			//trace("Falling crate is at", _fallingCrate.GetPosition().x, ",", _fallingCrate.GetPosition().y);
		}
		
		private function addARandomCrate():void
		{
			// Add a falling block to the world.
			var fallingCrateDef:b2PolygonDef = new b2PolygonDef();
			fallingCrateDef.SetAsBox(randomInt(5, 40) / RATIO, randomInt(5, 40) / RATIO);
			fallingCrateDef.friction = 0.8;
			fallingCrateDef.restitution = 0.3;
			fallingCrateDef.density = 0.7;
			
			// Set it to, 250, -30
			var fallingBodyDef:b2BodyDef = new b2BodyDef();
			fallingBodyDef.position.Set(randomInt(15, 530) / RATIO, randomInt(-100, -10) / RATIO);
			fallingBodyDef.angle = randomInt(0,360) * Math.PI / 180;
			
			var fallingCrate:b2Body = _world.CreateBody(fallingBodyDef);
			fallingCrate.CreateShape(fallingCrateDef);
			fallingCrate.SetMassFromShapes();
			
			
		}
		
		// Return a random number between lowVal and highVal, INCLUSIVE
		private function randomInt(lowVal:int, highVal:int): int
		{
			if (lowVal <= highVal) {
				return (lowVal + Math.floor(Math.random() * (highVal - lowVal + 1)));
			}else 
			{
				throw(new Error("OMG! Wrong values passed to randomInt!!"));
			}			
		}
		
		private function createWallsAndFloor():void
		{
			// Create the shape (polygon) definition
			var bigLongShapeDef: b2PolygonDef = new b2PolygonDef();
			bigLongShapeDef.vertexCount = 4;
			b2Vec2(bigLongShapeDef.vertices[0]).Set(0 / RATIO, 0 / RATIO);
			b2Vec2(bigLongShapeDef.vertices[1]).Set(550 / RATIO, 0 / RATIO);
			b2Vec2(bigLongShapeDef.vertices[2]).Set(550 / RATIO, 10 / RATIO);
			b2Vec2(bigLongShapeDef.vertices[3]).Set(0 / RATIO, 10 / RATIO);
			bigLongShapeDef.friction = 0.5;
			bigLongShapeDef.restitution = 0.3;
			bigLongShapeDef.density = 0.0;
			
			// Create the body definition
			var floorBodyDef:b2BodyDef = new b2BodyDef();
			floorBodyDef.position.Set(0 / RATIO, 390 / RATIO);
			
			// Create the body
			var floorBody:b2Body = _world.CreateBody(floorBodyDef);
			
			// Create the shape
			floorBody.CreateShape(bigLongShapeDef);
			floorBody.SetMassFromShapes();
			
			var tallSkinnyShape:b2PolygonDef = new b2PolygonDef();
			tallSkinnyShape.SetAsBox( 5 / RATIO, 195 / RATIO);
			tallSkinnyShape.friction = .5;
			tallSkinnyShape.restitution = 0.3;
			tallSkinnyShape.density = 0.0;
			
			var wallBodyDef:b2BodyDef = new b2BodyDef();
			wallBodyDef.position.Set(5 / RATIO, 195 / RATIO);
			
			var leftWall:b2Body = _world.CreateBody(wallBodyDef);
			leftWall.CreateShape(tallSkinnyShape);
			leftWall.SetMassFromShapes();
			
			wallBodyDef.position.Set(545 / RATIO, 195 / RATIO);
			var rightWall:b2Body = _world.CreateBody(wallBodyDef);
			rightWall.CreateShape(tallSkinnyShape);
			rightWall.SetMassFromShapes();
			
			//trace("My world now has", _world.m_bodyCount, "bodies in it! Wow!");
		}
		
		private function setupWorld():void
		{
			// 1. Set up the size of the universe
			var universeSize:b2AABB = new b2AABB();
			universeSize.lowerBound.Set( -3000 / RATIO, -3000 / RATIO);
			universeSize.upperBound.Set( 3000 / RATIO, 3000 / RATIO);			
			
			// 2. Define gravity
			var gravity: b2Vec2 = new b2Vec2(0, 9.8);
			
			// 3. Ignore sleeping objects
			var ignoreSleeping:Boolean = true;
			
			_world = new b2World(universeSize, gravity, ignoreSleeping);
			
			//trace("My world has", _world.GetBodyCount(), "bodies in it!");
		}
		
	}
	
}

You can get the Zip file containing all the project resources (source code, FLA, FlashDevelop project file) by clicking the link below.

Box2dChapter1_EdgarMirandadotnet.zip

My next goal is to finish up chapter 2, which is a bit longer then chapter 1 (50 lessons instead of 22). I’m currently on chapter 2 lesson 4, and I’m aiming to do around 5-10 lessons a day. I find it it’s easier to learn if I do about an hour or so of lessons each day instead of doing the whole batch in a day or two, there is also so much I can take of just watching video tutorials all day :) .

Look out for my final result for chapter 2!

Post Image

Old Box2dFlashAS3 video tutorial

So a while ago (almost a year ago) I got bored one night and decided to make a beginner video tutorial on using the Box2DFlashAS3 physics engine, you can find the tutorial at the following … http://shah-soft.com/~warhell/box2d/Box2DFlash%20HelloWorld.html. Since that time, Todd Kerpelman (kerp.net) has created an extensive set of video tutorials for Box2DFlashAS3. If you’re interested in learning how to use this great Flash physics engine I highly recommend checking out videos, you can find them at… http://www.kerp.net/box2d/. Be sure to check out chapter 1.2, he gives me a shout out for creating the original beginner video tutorial :) .

Post Image

Flash Game Summit re-cap and my in development Facebook game (Grid[z])

I spent my Monday attending the first annual Flash Game Summit in San Francisco (http://www.flashgamingsummit.com/), the first conference specifically for flash games. I really enjoyed all the sessions, particularly the last one on making Flash Games for social networks. Bret Terrill from Zynga (http://zynga.com/) talked about how some developers are making thousands of dollars a day putting games on social networks like Myspace and Facebook by taking advantage of the social aspects that those networks bring to flash games.

Here are some of the main points I took away from Terrill’s talk

  • Developers are making $10k-$30k a day.
  • Zynga current takes in revenue from the following: 30%  ads, 30%  microtransactions, 30%  Super rewards (e.g. sign up for Netflix and get 10,000 gold). There was no mention of the missing 10%.
  • Zynga is willing to consider buying a Facebook game application if it has 200,000 daily active users or more.
  • If you are going to put your flash game up on a social network, don’t just embed it as an application! Incorporate social aspects into it.
  • Most games shouldn’t have real-time multiplayer (unless it’s a game like poker), try to incorporate a style of play similar to e-mail chess .
  • If you do decide to incorporate real-time multiplayer, make sure the user is able to play with strangers and not just their friends.
  • The platform is social, people log in 4-6 times a day to play a game for 5 minutes each time.
  • Status is important, let the user be on stage, ranking vs. friends.
  • Gender: Competition vs cooperation, a grooming game makes for a cooperation experience.
  • Recipient loop (Gifts): You send a gift to a friend, they send you a gift back to you and to their other friends. Good example of this is Little Green Patch (http://apps.facebook.com/greentrees).

This has given me great motivation to work on my current project Grid[z]. I been putting in a lot of work into it for the past couple of weeks, and I think it’s almost up to the point were my partner (http://www.parrisstudios.com/) and I have a leader board and a fully functional game. It’s currently being testing by friends and I plan to have it up ASAP and hopefully get my taste of Facebook success.

Check out the Grid[z] beta on Facebook: http://apps.facebook.com/gridzzz/.

Resume is up and I’m off to the Flash Game Summit

My resume is now up!

I will be attending the 1st annual Flash Game Summit (http://www.flashgamingsummit.com/). Finally something that is geared towards the flash game dev community! Can’t wait to mingle with all the developers!