Slicing Images in 3D and Adding Interactivity

Intro

One of the things I really hate about slicing up images … is slicing them. It’s just so time intensive in Photoshop, Illustrator, or Gimp and then I never get it right or the site specs change and I have to re-slice (and God forbid re-program). So I’ve developed a method for slicing them programmatically – no more hand made clothes, all made by machine! Let me show you how it works.

Click the image below to see the demo (click on the slices to rotate them, or you can drag them as well):

Split Image and Interactivity

Split Image and Interactivity

Demo

Note: You must use the Flash 10 player. I built this in Gumbo as an ActionScript project.

Source

YouTube Demo


Discussion

In this post we actually handle three important concepts

  1. Slicing an Image
  2. Polymorphism & Encapsulation
  3. Static Properties/Methods & Interactivity

These concepts are key OOP principles briefly discussed below, but are given much more detail in the book. And are essential in understanding PV3D.

Slicing an Image

Slicing an image is pretty easy using copyPixels. You just bring in your image and copy the portion of the image that is your split as shown below:

// loop through all pieces
for(var x:uint=0;x<6;x++) {
for (var y:uint=0;y<4;y++) {

// create new map piece bitmap
var newmapPieceBitmap:Bitmap = new Bitmap(new BitmapData(pieceWidth,pieceHeight));
newmapPieceBitmap.bitmapData.copyPixels(image.bitmapData,new Rectangle(x*pieceWidth,y*pieceHeight,pieceWidth,pieceHeight),new Point(0,0));

// create new sprite and add bitmap data to it
var newmapPiece:Sprite = new Sprite();
newmapPiece.addChild(newmapPieceBitmap);
mapPiece=new MapPiece(newmapPiece,x,y);
DragDropStatic.DragDrop(mapPiece);

// set location
mapPiece.x = x*(pieceWidth+5)+20;
mapPiece.y = y*(pieceHeight+5)+20;
mapPiece.addEventListener(MouseEvent.CLICK,clickmapPiece);

// add to stage
movie.addChild(mapPiece);

}
}

You’ve got to loop twice to get both column and row as you use copyPixels to grab your slice. If you check out Gary Rosenzweig’s book ActionScript 3.0 Game Programming University you’ll find that he uses a similar slicing technique. But in addition to Gary’s approach, we use Polymorphism & Encapsulation typically found in PV3D. Their use is briefly discussed below, but is treated in greater detail in the book.

Polymorphism & Encapsulation

The heart of PV3D is encapsulation and by using polymorphism we can create a MapPiece class that enables us to easily work with the map pieces. Polymorphism is used to grab the map pieces and treat them as instantiated objects as shown in the MapPiece class below:

package objects.primitives
{
import flash.display.Sprite;

public class MapPiece extends Sprite
{
private var mapPiece:Sprite;
private var locX:uint;
private var locY:uint;
private var myXPos:Number;
private var myYPos:Number;

public function MapPiece(mapPiece:Sprite,locX:uint,locY:uint)
{
this.mapPiece=mapPiece;
this.locX=locX;
this.locY=locY;
addChild(mapPiece);
}

Interactivity

Interactivity is accomplished in two ways: (1) by adding a listener, and (2) using Static Properties and Methods.

Listener

The instantiated map piece has a mouse click listener added to each map piece using the code below:

mapPiece.addEventListener(MouseEvent.CLICK,clickmapPiece);

Static Properties and Methods

By creating a static properties and methods class you can create reusable code. This is done for the drag and drop class shown below.

package utils
{
import flash.display.Sprite;
import flash.events.MouseEvent;

public class DragDropStatic
{
public function DragDropStatic()
{

}

public static function DragDrop(mySprite:Sprite):void
{
mySprite.addEventListener(MouseEvent.MOUSE_DOWN, dragMe);
mySprite.addEventListener(MouseEvent.MOUSE_UP, dropMe);
function dragMe(event:MouseEvent):void
{
mySprite.startDrag();
}
function dropMe(event:MouseEvent):void
{
mySprite.stopDrag();

}}}}

Once the class is created then it’s easily executed using

DragDropStatic.DragDrop(mapPiece);

All of this is handled in greater detail in Chapter 6 of the book.

Check out the source code by downloading it from the link above or clicking below.

Wrapper Code

package {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.net.URLRequest;

import gs.TweenLite;
import gs.easing.*;
import org.lively3d.objects.primitives.MapPiece;
import org.lively3d.utils.Utils;
import org.lively3d.utils.DragDropStatic;

public class MapSplitImage extends MovieClip {

private var movie:MovieClip = new MovieClip();
private var movieParent:MovieClip = new MovieClip();

private var myOsc:int=0;
private var image:Bitmap;
private var mapPiece:MapPiece;
// game pieces
private var mapObjects:Array=new Array();

public function MapSplitImage() {
loadBitmap(“test2.jpg”);
}

// get the bitmap from an external source
public function loadBitmap(bitmapFile:String):void {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadingDone);
var request:URLRequest = new URLRequest(bitmapFile);
loader.load(request);
}

private function loadingDone(event:Event):void {
// get loaded data
image = Bitmap(event.target.loader.content);

// compute the width and height of each piece
var pieceWidth:Number = image.width/6;
var pieceHeight:Number = image.height/4;

// loop through all pieces
for(var x:uint=0;x<6;x++) {
for (var y:uint=0;y<4;y++) {

// create new map piece bitmap
var newmapPieceBitmap:Bitmap = new Bitmap(new BitmapData(pieceWidth,pieceHeight));
newmapPieceBitmap.bitmapData.copyPixels(image.bitmapData,new Rectangle(x*pieceWidth,y*pieceHeight,pieceWidth,pieceHeight),new Point(0,0));

// create new sprite and add bitmap data to it
var newmapPiece:Sprite = new Sprite();
newmapPiece.addChild(newmapPieceBitmap);
mapPiece=new MapPiece(newmapPiece,x,y);
DragDropStatic.DragDrop(mapPiece);

// set location
mapPiece.x = x*(pieceWidth+5)+20;
mapPiece.y = y*(pieceHeight+5)+20;
mapPiece.addEventListener(MouseEvent.CLICK,clickmapPiece);

// add to stage
movie.addChild(mapPiece);

}
}

//addListener
movieParent.addChild(movie);
addChild(movieParent);

Utils.centerObject2(movieParent);
Utils.centerObject3(movie, image);

addEventListener(Event.ENTER_FRAME, onEnterFrame);

}

private function clickmapPiece(event:MouseEvent):void {

moveMapPiece(event.currentTarget);

}

// move a piece into the blank space
private function moveMapPiece(mapPiece:Object):void {

TweenLite.to(mapPiece,2,{rotationY:360,z:-100, onComplete:onFinishTween} );
function onFinishTween():void{

mapPiece.rotationY=0;
TweenLite.to(mapPiece,10,{z:0});

}}

private function onEnterFrame(e:Event):void
{
myOsc++;
movieParent.rotationX+=-.1;

movie.x=-(image.width/2)*Math.cos(myOsc/100)/2+-image.width/2;
movie.y=-(image.height/2)*Math.sin(myOsc/100)/2+-image.height/2;

}}}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: