forked from: 降り注ぐ雪
papervision3Dのparticleで雪を表現
// forked from takion's 降り注ぐ雪
//papervision3Dのparticleで雪を表現
package {
import caurina.transitions.Tweener;
import flash.display.*;
import flash.events.*;
import flash.net.*;
import flash.system.LoaderContext;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.ui.Keyboard;
import flash.utils.getTimer;
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.core.clipping.FrustumClipping;
import org.papervision3d.core.geom.renderables.Particle;
import org.papervision3d.lights.PointLight3D;
import org.papervision3d.materials.*;
import org.papervision3d.materials.special.ParticleMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.*;
import org.papervision3d.objects.special.ParticleField;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;
[SWF(backgroundColor=0x000000)]
public class SnowPouring 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-up
private var maxFar : int = 1000;
private var bmpSheet : BitmapData;
private var particleMat : ParticleMaterial;
private var particleField : ParticleField;
private var pFieldHeight : int;
private var numParticles : int;
private var theta : Number = 0;
private var windOffset : Array;
//ground field
private var fieldObj : DisplayObject3D;
private var fieldSize : int = 2000;
private var fieldSegment : int = 5;
private var fieldMat : BitmapMaterial;
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 SnowPouring( ):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
bmpSheet = new BitmapData( 40, 40, false, 0 );
bmpSheet.perlinNoise(20,20,3,7,true,true,2,false);
bmpSheet.lock();
for( var i:int = 0; i < 40; i++ )
{
for( var j:int = 0; j < 40; j++ )
{
if( bmpSheet.getPixel( i, j ) > 0x007700 )
{
bmpSheet.setPixel( i, j, bmpSheet.getPixel( i, j ) + 0xFF00FF );
}
}
}
bmpSheet.unlock();
fieldMat = new BitmapMaterial( bmpSheet );
fieldObj = new Plane( fieldMat, fieldSize, fieldSize, fieldSegment, fieldSegment );
fieldObj.rotationX = 90;
rootNode.addChild( fieldObj );
/* create particles */
pFieldHeight = 250;
numParticles = 1000;
particleMat = new ParticleMaterial( 0xFFFFFF, 1, ParticleMaterial.SHAPE_CIRCLE );
particleField = new ParticleField( particleMat, numParticles, 8, fieldSize, pFieldHeight, fieldSize);
for( i = 0; i < numParticles; i++ )
{
Particle(particleField.particles[i]).size = Math.random() * 10 + 1;
}
particleField.y = pFieldHeight / 2;
rootNode.addChild( particleField );
windOffset = new Array( 3 ); //wind offset
windOffset[0] = 3;
windOffset[1] = 5;
windOffset[2] = 0;
//camera setting
camera = new Camera3D(90, 10, maxFar, true);
camera.x = 0;
camera.y = charaHeight;
camera.z = 0;
camera.focus = 10;
camera.zoom = 50;
camera.rotationY = 210 ;
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 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 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 Keyboard.SPACE:
spaceKey = false;
break;
case Keyboard.SHIFT:
shiftKey = false;
break;
default:
break;
}
}
private function loop( event:Event ):void
{
pouringParticles();
controlCamera();
displayDebug();
renderer.renderScene( scene, camera, viewport );
}
//雪の動き
private function pouringParticles():void
{
theta += Math.PI * 2 / 100;
for( var iString:String in particleField.geometry.vertices )
{
var i:int = int( iString );
particleField.particles[i].y -= ( Particle( particleField.particles[ i ] ).size / 1.5 + windOffset[2] );
particleField.particles[i].x += ( Math.sin( theta + i ) * 3 + windOffset[0] );
particleField.particles[i].z += ( Math.cos( theta + i ) * 3 + windOffset[1] );
if( particleField.particles[i].y < - pFieldHeight / 2 )
{
particleField.particles[i].y = pFieldHeight;
}
particleField.particles[i].x = (particleField.particles[i].x + fieldSize/2 ) % fieldSize - fieldSize/2;
particleField.particles[i].z = (particleField.particles[i].z + fieldSize/2 ) % fieldSize - fieldSize/2;
}
}
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( 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 )
{
if( cameraStatus == 0 )
{
cameraStatus = 1;
exCamera[0] = camera.rotationX;
exCamera[1] = camera.rotationY;
exCamera[2] = camera.rotationZ;
Tweener.addTween( camera, {rotationX: -40, time:1, onComplete: function():void
{
cameraStatus = 3;
//renderer.clipping = new FrustumClipping(FrustumClipping.BOTTOM);
}} );
}
else if( cameraStatus == 3 )
{
cameraStatus = 1;
Tweener.addTween( camera, {rotationX: exCamera[0], time:1, onComplete: function():void
{
cameraStatus = 0;
//renderer.clipping = new FrustumClipping(FrustumClipping.BOTTOM);
}} );
exCamera.length = 0;
}
}
//avoid camera going out of the field
if( camera.x > fieldLimit - deltaMove )
{
camera.x = fieldLimit - deltaMove;
}
else if( camera.x < - fieldLimit + deltaMove)
{
camera.x = - fieldLimit + deltaMove;
}
else if( camera.z > fieldLimit - deltaMove )
{
camera.z = fieldLimit - deltaMove;
}
else if( camera.z < - fieldLimit + deltaMove )
{
camera.z = - fieldLimit + deltaMove;
}
}
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 = "Bird-eyes: Space";
debugText[ 4 ].text = "Loop-up : Shift" ;
}
}
}