蝶と戯れるゲー
game-like sample using Papervision 3d and Tweener
added butterfly motion using perlinNoise
inspired by http://www.25lines.com/finalists/0812/034.txt :)
added texture mapping for butterflies
// forked from takion's Papervision3D Game-like Sample
//game-like sample using Papervision 3d and Tweener
//added butterfly motion using perlinNoise
//inspired by http://www.25lines.com/finalists/0812/034.txt :)
//added texture mapping for butterflies
package {
import caurina.transitions.Tweener;
import flash.display.*;
import flash.events.*;
import flash.geom.Point;
import flash.net.*;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.ui.Keyboard;
import flash.utils.getTimer;
import flash.system.Security;
import flash.system.LoaderContext;
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.core.clipping.FrustumClipping;
import org.papervision3d.lights.PointLight3D;
import org.papervision3d.materials.*;
import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.parsers.DAE;
import org.papervision3d.objects.primitives.*;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;
[SWF(backgroundColor=0x6666FF)]
public class ButterflyWatching extends Sprite
{
//private var container : Sprite;
private var viewport : Viewport3D;
private var scene : Scene3D;
private var camera : Camera3D;
private var rootNode : DisplayObject3D;
private var renderer : BasicRenderEngine;
private var light : PointLight3D;
//for debug
private var frameCount : Number;
private var prevTimer : Number;
private var debugText : Array;
private var numDebugItems : int = 13;
//camera
private var exCamera : Array;
private var cameraStatus : int = 0; // 0: ground, 1:during change, 2:bird-eyes, 3:Look-at-paperPlane, 4:jump
private var maxFar : int = 1000;
//butterfly
private var butterflies : Array;
private var wingMats : Array;
private var bodyMat :BitmapFileMaterial;
private var bmpSheet : BitmapData;
private var perlinPointArr : Array;
private var px1 : Number = 0;
private var numButterflies : int = 4;
private var numKinds : int = 2;
private var butThetaRot : Number = 0;
private var butterflyNoise : int = 10;
private var targetButterfly: int = 0;
//ground field
private var fieldObj : DisplayObject3D;
private var fieldSize : int = 2000;
private var fieldSegment : int = 1;
private var fieldMat : ColorMaterial;
private var fieldLimit : int = fieldSize / 2 - 20;
private var rightKey : Boolean = false;
private var leftKey : Boolean = false;
private var upKey : Boolean = false;
private var downKey : Boolean = false;
private var zKey : Boolean = false;
private var spaceKey : Boolean = false;
private var shiftKey : Boolean = false;
private var charaHeight : int = 50;
private var onJump : Boolean = false;
private var deltaJump : int = 0;
private var powerJump : int = 12;
private var deltaRot : int = 2;
private var deltaMove : int = 7;
public function ButterflyWatching( ):void
{
stage.frameRate = 30;
stage.quality = "LOW";
stage.scaleMode = "noScale";
stage.align = StageAlign.TOP_LEFT;
viewport = new Viewport3D( 0, 0, true );
renderer = new BasicRenderEngine( );
scene = new Scene3D( );
rootNode = new DisplayObject3D( );
light = new PointLight3D( );
addChild( viewport );
scene.addChild( rootNode );
renderer.clipping = new FrustumClipping( FrustumClipping.BOTTOM );
light.y = 2000;
initializeDebugger( );
//create ground field
fieldMat = new ColorMaterial( 0x888800 );
fieldObj = new Plane( fieldMat, fieldSize, fieldSize, fieldSegment, fieldSegment );
fieldObj.rotationX = 90;
rootNode.addChild( fieldObj );
//create tree
for( var i:int = -1; i <= 1; i+=2 )
{
for( var j:int = -1; j <= 1; j+=2 )
{
rootNode.addChild( createTree( i * 400, j * 400 ) );
}
}
rootNode.addChild( createTree( 0, 0 ) );
//create butterfly
butterflies = new Array( );
perlinPointArr = new Array ( );
wingMats = new Array( );
Security.loadPolicyFile("http://takion.ps.land.to/images/crossdomain.xml");
var wing1:BitmapMaterial = new BitmapMaterial();
var wing2:BitmapMaterial = new BitmapMaterial();
imageLoad( wing1, "http://takion.ps.land.to/images/wing1.png" );
imageLoad( wing2, "http://takion.ps.land.to/images/wing2.png" );
wingMats.push( wing1 );
wingMats.push( wing2 );
for( i = 0; i < numKinds; i++ )
{
wingMats[ i ].oneSide = false;
wingMats[ i ].tiled = true;
}
for( i = 0; i < numButterflies; i++ )
{
rootNode.addChild( ( butterflies[ i ] = createButterfly( i % numKinds ) ) );
perlinPointArr[i] = new Point( i * 50 + 100, i * 50 + 100 );
}
bmpSheet = new BitmapData( 40, 40, false, 0 );
//camera setting
camera = new Camera3D(90, 10, maxFar, true);
camera.x = 300;
camera.y = charaHeight;
camera.z = 300;
camera.focus = 10;
camera.zoom = 50;
camera.rotationY = 300 ;
exCamera = new Array();
//fps computing
frameCount = 0;
prevTimer = getTimer();
stage.addEventListener( Event.ENTER_FRAME, loop );
stage.addEventListener( KeyboardEvent.KEY_DOWN, keyDownHandler );
stage.addEventListener( KeyboardEvent.KEY_UP, keyUPHandler );
}
private function initializeDebugger():void
{
debugText = new Array();
var debugTextFormat:TextFormat = new TextFormat();
debugTextFormat.size = 11;
debugTextFormat.color = 0xFFFFFF;
debugTextFormat.font = "Courier New";
for( var i:int = 0; i < numDebugItems; i++ )
{
debugText[ i ] = new TextField();
debugText[ i ].type = "dynamic";
debugText[ i ].width = 150;
debugText[ i ].height = 20;
debugText[ i ].x = 12;
debugText[ i ].y = 8 + 15 * i;
debugText[ i ].defaultTextFormat = debugTextFormat;
//debugText[ i ].text = " --------";
addChild( debugText[i] );
}
}
private function imageLoad( bmpMat:BitmapMaterial, URLs:String ):void
{
var loaderContext:LoaderContext = new LoaderContext ();
loaderContext.checkPolicyFile = true;
var imageLoader:Loader = new Loader();
imageLoader.contentLoaderInfo.addEventListener( Event.COMPLETE,
function( e:Event ):void
{
var loadedBmp:Bitmap = e.target.content as Bitmap;
var bmp : BitmapData = loadedBmp.bitmapData;
bmpMat.texture = bmp;
} );
imageLoader.load( new URLRequest( URLs ), loaderContext );
}
private function createTree( x:int, z:int ):DisplayObject3D
{
var coneMat:FlatShadeMaterial = new FlatShadeMaterial( light, 0xDDDDDD, 0x228b22 );
var coneObj:Cone = new Cone( coneMat, 50, 200, 8, 1 );
coneObj.y = 200;
var trunkMat:FlatShadeMaterial = new FlatShadeMaterial( light, 0xDDDDDD, 0x8b0000 );
trunkMat.oneSide = false;
var trunkObj:Cylinder = new Cylinder( trunkMat, 25, 100 );
trunkObj.y = 50;
var treeObj:DisplayObject3D = new DisplayObject3D( );
treeObj.addChild( coneObj );
treeObj.addChild( trunkObj );
treeObj.x = x;
treeObj.z = z;
return treeObj;
}
private function createButterfly( kind:int ):DisplayObject3D
{
var butMatList: MaterialsList = new MaterialsList( );
butMatList.addMaterial( wingMats[ kind ], "all" );
var bodyMat:BitmapMaterial = new BitmapMaterial();
imageLoad( bodyMat, "http://takion.ps.land.to/images/body.png" );
//var bodyMat:BitmapFileMaterial = new BitmapFileMaterial( ("http://takion.ps.land.to/images/body.png" ) );
bodyMat.tiled = true;
bodyMat.lineAlpha = 0.0;
bodyMat.lineColor = 0xFFFFFF;
var bodyMatList:MaterialsList = new MaterialsList();
bodyMatList.addMaterial( bodyMat, "all" );
var butBody: DAE = new DAE;
var butWingRU: DAE = new DAE;
var butWingRD: DAE = new DAE;
var butWingLU: DAE = new DAE;
var butWingLD: DAE = new DAE;
Security.loadPolicyFile("http://takion.ps.land.to/3dmodel/crossdomain.xml");
butBody.load("http://takion.ps.land.to/3dmodel/body.dae", bodyMatList);
butWingRU.load("http://takion.ps.land.to/3dmodel/wingRU.dae", butMatList);
butWingRD.load("http://takion.ps.land.to/3dmodel/wingRD.dae", butMatList);
butWingLU.load("http://takion.ps.land.to/3dmodel/wingLU.dae", butMatList);
butWingLD.load("http://takion.ps.land.to/3dmodel/wingLD.dae", butMatList);
butWingRU.name = "butWingRU";
butWingRD.name = "butWingRD";
butWingLU.name = "butWingLU";
butWingLD.name = "butWingLD";
butWingRU.x = butWingRD.x = 2;
butWingRU.y = butWingRD.y = 0;
butWingRU.z = butWingRD.z = 10;
butWingLU.x = butWingLD.x = -2;
butWingLU.y = butWingLD.y = 0;
butWingLU.z = butWingLD.z = 10;
var butterflyObj:DisplayObject3D = new DisplayObject3D();
butterflyObj.addChild(butBody);
butterflyObj.addChild(butWingRU);
butterflyObj.addChild(butWingRD);
butterflyObj.addChild(butWingLU);
butterflyObj.addChild(butWingLD);
butterflyObj.scale = 1;
butterflyObj.y = 100;
//butterflyObj.x = Math.random() * 1000 - 500;
//butterflyObj.z = Math.random() * 1000 - 500;
butterflyObj.rotationX = -20;
return butterflyObj;
}
private function keyDownHandler( event:KeyboardEvent ):void
{
switch ( event.keyCode )
{
case Keyboard.RIGHT:
rightKey = true;
break;
case Keyboard.LEFT:
leftKey = true;
break;
case Keyboard.UP:
upKey = true;
break;
case Keyboard.DOWN:
downKey = true;
break;
case 90: // Z key
zKey = true;
break;
case Keyboard.SPACE:
spaceKey = true;
break;
case Keyboard.SHIFT:
shiftKey = true;
break;
default:
break;
}
}
private function keyUPHandler( event:KeyboardEvent ):void
{
switch ( event.keyCode )
{
case Keyboard.RIGHT:
rightKey = false;
break;
case Keyboard.LEFT:
leftKey = false;
break;
case Keyboard.UP:
upKey = false;
break;
case Keyboard.DOWN:
downKey = false;
break;
case 90:
zKey=false;
break;
case Keyboard.SPACE:
spaceKey = false;
break;
case Keyboard.SHIFT:
shiftKey = false;
break;
default:
break;
}
}
private function loop( event:Event ):void
{
butterflyMotion();
controlCamera();
displayDebug();
renderer.renderScene( scene, camera, viewport );
}
private function butterflyMotion():void
{
butThetaRot += Math.PI * 2 / 100;
butterflyNoise = Math.random() * 3 + 3;
//field wandering by perlinNoise
for( var i:int = 0; i < numButterflies; i++ ) // each( var perlinPoint:Point in perlinPointArr )
{
var perlinPoint:Point = perlinPointArr[ i ];
bmpSheet.perlinNoise(20,20,3,6406+i*5,true,true,2|1,false,[new Point(px1+=0.3,0),new Point(-px1/2,0),new Point(0,0)]);
var exPos:Point = new Point( perlinPoint.x, perlinPoint.y );
var rgb24:uint=bmpSheet.getPixel( perlinPoint.x*0.025, perlinPoint.y*0.025);
if(rgb24>0) {
perlinPoint.x+=(128-(rgb24 >> 16))/5;
perlinPoint.y+=(128-((rgb24 ^ (rgb24 >> 16 << 16)) >> 8))/5;
}
perlinPoint.x+=(800-perlinPoint.x) / int( 80 * butterflyNoise );
perlinPoint.y+=(800-perlinPoint.y) / int( 80 * butterflyNoise );
//rotate to the progressing direction
var vecDir:Point = new Point( perlinPoint.x - exPos.x, perlinPoint.y - exPos.y );
var rotAngle:Number = Math.acos( vecDir.y / Math.sqrt( vecDir.x * vecDir.x + vecDir.y * vecDir.y ) ) * 180 / Math.PI;
if( vecDir.x < 0 ) rotAngle = 360 - rotAngle; //because of Z axis direction?
var butterflyObj:DisplayObject3D = butterflies[ i ] as DisplayObject3D;
butterflyObj.x = (perlinPoint.x - 800);
butterflyObj.z = (perlinPoint.y - 800);
butterflyObj.rotationY = rotAngle;
//flap wings
var motionPhase:Number = Math.sin( butThetaRot * 10 + i * Math.PI / 3 ) * 3;
butterflyObj.getChildByName("butWingLU").rotationZ = motionPhase * 30; // (butterflyNoise * 3 + 5);
butterflyObj.getChildByName("butWingLD").rotationZ = motionPhase * 30; //(butterflyNoise * 3 + 5);
butterflyObj.getChildByName("butWingRU").rotationZ = - motionPhase * 30; //(butterflyNoise * 3 + 5);
butterflyObj.getChildByName("butWingRD").rotationZ = - motionPhase * 30; //(butterflyNoise * 3 + 5);
//bound motion
butterflyObj.y += Math.cos( butThetaRot * 5 ) * butterflyNoise;
}
}
private function controlCamera():void
{
if( spaceKey == true )
{
if( cameraStatus == 0 ) // on normal mode
{
camera.far = 2500;
renderer.clipping = new FrustumClipping(FrustumClipping.NEAR);
cameraStatus = 1; // on changing modes
exCamera[0] = camera.x;
exCamera[1] = camera.y;
exCamera[2] = camera.z;
exCamera[3] = camera.rotationX;
exCamera[4] = camera.rotationY;
exCamera[5] = camera.rotationZ;
Tweener.addTween( camera, {x: 0, y:2300, z:0, time:2} );
Tweener.addTween( camera, {rotationX: 90, time:3, onComplete: function():void{cameraStatus = 2} } );
}
else if( cameraStatus == 2 ) // on birds-eye mode
{
camera.far = maxFar;
cameraStatus = 1;
Tweener.addTween( camera, {x: exCamera[0], y:exCamera[1], z:exCamera[2], time:3} );
Tweener.addTween( camera, {rotationX: exCamera[3], time:2, onComplete: function():void
{
cameraStatus = 0;
renderer.clipping = new FrustumClipping(FrustumClipping.BOTTOM);
}} );
exCamera.length = 0;
}
}
if( zKey == true )
{
if( cameraStatus == 0 )
{
exCamera[0] = camera.rotationX;
exCamera[1] = camera.rotationY;
exCamera[2] = camera.rotationZ;
var minimumDis:int = -1;
for( var i:int = 0; i < numButterflies; i ++ )
{
var distance: Number = Point.distance( new Point( camera.x, camera.z ), new Point( butterflies[ i ].x, butterflies[ i ].z ) );
if( minimumDis < 0 || distance < minimumDis )
{
minimumDis = distance;
targetButterfly = i;
}
}
if(minimumDis < maxFar) cameraStatus = 3;
}
if( cameraStatus == 3 ) // on obserbing a butterfly mode
{
if( Point.distance( new Point( camera.x, camera.z ), new Point( butterflies[ targetButterfly ].x, butterflies[ targetButterfly ].z ) ) < maxFar )
{
camera.lookAt( butterflies[ targetButterfly ] );
}
else
{
cameraStatus = 0;
camera.rotationX = exCamera[0];
camera.rotationY = exCamera[1];
camera.rotationZ = exCamera[2];
exCamera.length = 0;
}
}
}
else
{
if( cameraStatus == 3 )
{
cameraStatus = 0;
camera.rotationX = exCamera[0];
camera.rotationY = exCamera[1];
camera.rotationZ = exCamera[2];
exCamera.length = 0;
}
if( rightKey == true )
{
camera.rotationY += deltaRot;
}
else if( leftKey == true )
{
camera.rotationY -= deltaRot;
}
}
if( cameraStatus == 0 )
{
if( camera.x > - fieldLimit && camera.x < fieldLimit && camera.z > - fieldLimit && camera.z < fieldLimit )
{
if( upKey == true )
{
camera.moveForward( deltaMove );
}
else if ( downKey == true )
{
camera.moveBackward( deltaMove );
}
}
}
/*
if( shiftKey == true )
{
cameraStatus = 4;
deltaJump = powerJump;
}
}
if( cameraStatus == 4 ) // on Jump
{
camera.y += deltaJump;
if( deltaJump == -powerJump )
{
cameraStatus = 0;
deltaJump = 0;
}
else
{
deltaJump -= 1;
}
} */
//avoid camera going out of the field
if( camera.x > fieldLimit - 10 )
{
camera.x = fieldLimit - 10;
}
else if( camera.x < - fieldLimit + 10)
{
camera.x = - fieldLimit + 10;
}
else if( camera.z > fieldLimit - 10 )
{
camera.z = fieldLimit - 10;
}
else if( camera.z < - fieldLimit + 10 )
{
camera.z = - fieldLimit + 10;
}
}
private function displayDebug():void
{
frameCount ++;
if ( (getTimer() - prevTimer ) / 1000 >= 0.25 )
{
var fps:Number = frameCount * 1000 / ( getTimer() - prevTimer );
fps = Math.floor( fps * 10 ) / 10;
prevTimer = getTimer();
frameCount = 0;
debugText[ 0 ].text = "FPS : " + fps;
}
debugText[ 1 ].text = "Move : ↑↓";
debugText[ 2 ].text = "Turn : →←";
debugText[ 3 ].text = "Observe : Z";
debugText[ 4 ].text = "Bird-eyes: Space";
/*
debugText[ 5 ].text = "Jump : Shift" ;
debugText[ 7 ].text = "CAMERA_X : " + int( camera.x );
debugText[ 8 ].text = "CAMERA_Y : " + int( camera.y );
debugText[ 9 ].text = "CAMERA_Z : " + int( camera.z );
debugText[ 10 ].text = "ROT_X : " + int( camera.rotationX );
debugText[ 11 ].text = "ROT_Y : " + int( camera.rotationY );
debugText[ 12 ].text = "ROT_Z : " + int( camera.rotationZ );
*/
}
}
}