RollCameraController(Simple Easing) [Alternativa3d7.6 TIPS]
RollCameraController
シンプルなイージング(遅延減速)付きです
十字キーで操作
↑↓でCamera上下
←→でCameraが回転
PageUp、 PageDownでZoomIn ZommOut
マウスにも対応しています。
/**
* Copyright narutohyper ( http://wonderfl.net/user/narutohyper )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/fwPU
*/
// forked from narutohyper's Alternativa3D 7.6 Template
package
{
import alternativ7.engine3d.materials.FillMaterial;
import alternativ7.engine3d.materials.TextureMaterial;
import alternativ7.engine3d.loaders.MaterialLoader;
import alternativ7.engine3d.primitives.Plane;
import alternativ7.engine3d.primitives.GeoSphere;
import alternativ7.engine3d.objects.Sprite3D;
import alternativ7.engine3d.controllers.SimpleObjectController
import flash.display.Sprite;
import flash.display.Shape;
import flash.display.BitmapData;
import flash.system.LoaderContext;
import flash.events.Event;
import flash.ui.Keyboard;
/**
*
* Alternativa3D 7.6
*
* RollCameraController
* イージング(遅延減速)付き
*
* @author narutohyper
*/
[SWF(backgroundColor="#000000", frameRate="100", width="800", height="600")]
public class Main extends Sprite
{
public function Main():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event=null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
//AlternativaTemplate作成
var scene:AlternativaTemplate = new AlternativaTemplate(this)
//星パーティクル
var RADIAN:Number = Math.PI / 180;
var stars:Vector.<Sprite3D> = new Vector.<Sprite3D>(500, true);
var circle:Shape = new Shape();
circle.graphics.beginFill(0xFFFFFF);
circle.graphics.drawCircle(25, 25, 25);
var bmd:BitmapData = new BitmapData(50, 50, true, 0);
bmd.draw(circle);
var material:TextureMaterial = new TextureMaterial(bmd);
var angle:Number;
var length:Number;
for (var i:int = 0; i < 500; i++)
{
stars[i] = new Sprite3D(100, 100, material);
scene.container.addChild(stars[i]);
angle = Math.random() * 360 * RADIAN;
length = Math.random() * 100000 + 5000;
stars[i].x = Math.cos(angle) * length;
stars[i].y = Math.sin(angle) * length;
angle = Math.random() * 360 * RADIAN;
length = Math.random() * 100000 + 5000;
stars[i].z = Math.sin(angle) * length;
}
//地球
var earthMaterial:TextureMaterial = new TextureMaterial(null, false, true);
earthMaterial.diffuseMapURL = 'http://assets.wonderfl.net/images/related_images/e/e9/e987/e9876c502c9e9693205335e106de6baa8865c1a6';
var textures:Vector.<TextureMaterial> = new Vector.<TextureMaterial>();
textures[0] = earthMaterial;
var context:LoaderContext = new LoaderContext(true);
var materialLoader:MaterialLoader = new MaterialLoader();
materialLoader.load(textures,context);
var earth:GeoSphere = new GeoSphere(200, 8);
//earth.sorting = Sorting.DYNAMIC_BSP;
earth.setMaterialToAllFaces(earthMaterial);
scene.container.addChild(earth);
scene.cameraController.object = null;
var cameraController:RollCameraController = new RollCameraController(stage, scene.camera, 200);
cameraController.mouseSensitivity = 0;
cameraController.mouseSensitivityX = 1;
cameraController.mouseSensitivityY = 1;
cameraController.unbindAll();
cameraController.accelerate(true);
//Cameraの中心からの距離
cameraController.length(700);
cameraController.minLength = 200;
//イージング設定
//1~数値が高いほど、遅延大でぬるぬる
cameraController.easingSeparator = 30;
//Cameraの初期位置
cameraController.posZ(500,true);
cameraController.angle(0);
//視点の調整
//ただし回転するCameraなので、Z以外は、おかしくなる
cameraController.lookAtPosition(0, 0, 10);
cameraController.minZ = -1000;
cameraController.maxZ = 1000;
cameraController.bindKey(Keyboard.LEFT, SimpleObjectController.ACTION_YAW_LEFT);
cameraController.bindKey(Keyboard.RIGHT,SimpleObjectController.ACTION_YAW_RIGHT);
cameraController.bindKey(Keyboard.DOWN, SimpleObjectController.ACTION_PITCH_DOWN);
cameraController.bindKey(Keyboard.UP, SimpleObjectController.ACTION_PITCH_UP);
cameraController.bindKey(Keyboard.PAGE_UP, RollCameraController.ACTION_ZOOM_IN);
cameraController.bindKey(Keyboard.PAGE_DOWN,RollCameraController.ACTION_ZOOM_OUT);
cameraController.update();
//描画開始
scene.startRendering()
scene.onPreRender = function():void {
cameraController.update();
}
}
}
}
import alternativ7.engine3d.controllers.SimpleObjectController;
import alternativ7.engine3d.core.Object3D;
import flash.display.InteractiveObject;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.geom.Vector3D;
/**
* RollCameraController
*
* @author narutohyper
*/
class RollCameraController extends SimpleObjectController{
public static const ACTION_ZOOM_IN : String="action_zoom_in";
public static const ACTION_ZOOM_OUT : String="action_zoom_out";
/**
* Camera位置の最小高さ(z) 上が+ 初期値は100
*/
public var minZ:Number = 100;
/**
* Camera位置の最大高さ(z) 上が+ 初期値は800
*/
public var maxZ:Number = 800;
/**
* Cameraから、中心までの最小距離
*/
public var minLength:Number = 200;
/**
* Cameraから、中心までの最大距離
*/
public var maxLength:Number = 2000;
private var _easingSeparator:Number = 20;
private var _yawNear:Boolean=false
private var _yawNearAngle:Number
private var _pitchNear:Boolean=false
private var _pitchNearAngle:Number
private var _target:Object3D
private var _pitchDown:Boolean;
private var _pitchUp:Boolean;
private var _yawLeft:Boolean;
private var _yawRight:Boolean;
private var _mouseMove:Boolean;
private var _mouseSensitivityX:Number=1
private var _mouseSensitivityY:Number=1
private var _mouseX:Number;
private var _mouseY:Number;
private var _zoomIn:Boolean;
private var _zoomOut:Boolean;
private var _length:Number = 700;
private var _lastLength:Number = 700;
private var _zoomSpeed:Number = 10;
private var _yawSpeed:Number = 5;
private var _pitchSpeed:Number = 30;
private var _oldAngle:Number;
private var _angle:Number = 90;
private var _lastAngle:Number = _angle;
private var _oldZ:Number;
private var _lastZ:Number;
private var _eventSource:InteractiveObject;
private var _lookAtX:Number=0;
private var _lastLookAtX:Number=_lookAtX;
private var _lookAtY:Number=0;
private var _lastLookAtY:Number=_lookAtY;
private var _lookAtZ:Number=0;
private var _lastLookAtZ:Number=_lookAtZ;
public function RollCameraController(eventSource:InteractiveObject, object:Object3D, speed:Number, speedMultiplier:Number = 3, mouseSensitivityX:Number = 1, mouseSensitivityY:Number = 1) {
_target = object;
_lastZ = _target.z;
_eventSource = eventSource;
super(eventSource, object, speed, speedMultiplier, mouseSensitivity);
eventSource.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
eventSource.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
_eventSource.addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
}
private function onMouseWheel(e:MouseEvent):void
{
_lastLength += e.delta*20;
if (_lastLength < minLength) {
_lastLength=minLength
} else if (_lastLength > maxLength) {
_lastLength=maxLength
}
}
public function onKeyDown(e:KeyboardEvent):void {
for (var key:String in keyBindings) {
if (String(e.keyCode)==key) {
keyBindings[key](true)
}
}
}
public function onKeyUp(e:KeyboardEvent = null):void {
for (var key:String in keyBindings) {
keyBindings[key](false)
}
_yawNear = false
_pitchNear = false;
}
override public function bindKey(keyCode:uint, action:String): void {
switch (action) {
case ACTION_ZOOM_IN:
keyBindings[keyCode] = zoomIn;
break
case ACTION_ZOOM_OUT:
keyBindings[keyCode] = zoomOut;
break
case ACTION_YAW_LEFT:
keyBindings[keyCode] = yawLeft;
break
case ACTION_YAW_RIGHT:
keyBindings[keyCode] = yawRight;
break
case ACTION_PITCH_DOWN:
keyBindings[keyCode] = pitchDown;
break
case ACTION_PITCH_UP:
keyBindings[keyCode] = pitchUp;
break
}
//super.bindKey(keyCode, action)
}
public function pitchDown(value:Boolean):void {
_pitchDown=value
}
public function pitchUp(value:Boolean):void {
_pitchUp=value
}
public function yawLeft(value:Boolean,near:Boolean=false):void {
_yawLeft = value;
_yawNear = near;
}
public function yawRight(value:Boolean,near:Boolean=false):void {
_yawRight = value;
_yawNear = near;
}
public function zoomIn(value:Boolean):void {
_zoomIn = value;
}
public function zoomOut(value:Boolean):void {
_zoomOut = value;
}
override public function update(): void {
var RADIAN:Number = Math.PI / 180;
//CameraZoom制御
if (_zoomIn) {
_lastLength -= _zoomSpeed
} else if (_zoomOut){
_lastLength += _zoomSpeed
}
if (_lastLength < minLength) {
_lastLength=minLength
} else if (_lastLength > maxLength) {
_lastLength=maxLength
}
if (_lastLength - _length) {
_length += (_lastLength - _length) / _easingSeparator;
}
//Camera回転制御
if (_mouseMove) {
_lastAngle = _oldAngle + (_eventSource.mouseX - _mouseX) * _mouseSensitivityX/2
} else if (_yawLeft) {
_lastAngle += _yawSpeed;
} else if (_yawRight) {
_lastAngle -= _yawSpeed;
}
if (_lastAngle-_angle) {
_angle += (_lastAngle - _angle) / _easingSeparator;
}
_target.x = Math.cos(_angle * RADIAN) * _length;
_target.y = Math.sin(_angle * RADIAN) * _length;
//CameraZ位置制御
if (_mouseMove) {
_lastZ = _oldZ + (_eventSource.mouseY - _mouseY) * _mouseSensitivityY * 2
} else if (_pitchDown) {
_lastZ -= _pitchSpeed
} else if (_pitchUp) {
_lastZ += _pitchSpeed
}
if (_lastZ < minZ) {
_lastZ = minZ;
} else if (_lastZ > maxZ) {
_lastZ = maxZ
}
if (_lastZ - _target.z) {
_target.z += (_lastZ - _target.z) / _easingSeparator;
}
//lookAt制御
if (_lastLookAtX - _lookAtX) {
_lookAtX += (_lastLookAtX-_lookAtX) / _easingSeparator;
}
if (_lastLookAtY - _lookAtY) {
_lookAtY += (_lastLookAtY-_lookAtY) / _easingSeparator;
}
if (_lastLookAtZ - _lookAtZ) {
_lookAtZ += (_lastLookAtZ-_lookAtZ) / _easingSeparator;
}
//super.update()
updateObjectTransform()
lookAtXYZ(_lookAtX, _lookAtY, _lookAtZ);
}
override public function startMouseLook():void {
_oldAngle = _lastAngle
_oldZ = _lastZ
_mouseX = _eventSource.mouseX;
_mouseY = _eventSource.mouseY;
_mouseMove = true;
}
override public function stopMouseLook():void {
_mouseMove = false;
}
/**
* Zoomスピード
* 初期値は10(px)
*/
public function set zoomSpeed(value:Number):void
{
_zoomSpeed = value;
}
/**
* 回転スピード
* 初期値は5(度)
*/
public function set yawSpeed(value:Number):void {
_yawSpeed = value*Math.PI/180;
}
/**
* 上下スピード
* 初期値は30(px)
*/
public function set pitchSpeed(value:Number):void
{
_pitchSpeed = value
}
/**
* マウスのX方向の感度
*/
public function set mouseSensitivityX(value:Number):void
{
_mouseSensitivityX = value;
}
/**
* マウスのY方向の感度
*/
public function set mouseSensitivityY(value:Number):void
{
_mouseSensitivityY = value;
}
/**
* イージング時の現在の位置から最後の位置までの分割係数
* フレームレートと相談して使用
* 1~
* 正の整数のみ。0を指定しても1になります。
* 1でイージング無し。数値が高いほど、遅延しぬるぬるします
*/
public function set easingSeparator(value:uint):void
{
if (value) {
_easingSeparator = value;
} else {
_easingSeparator = 1;
}
}
/**
* Cameraの向く方向
* mode=trueで、イージングしないで変更
* lookAtやlookAtXYZとの併用は不可
*/
public function lookAtPosition(x:Number, y:Number, z:Number,mode:Boolean=false):void {
if (mode)
{
_lookAtX = x
_lookAtY = y
_lookAtZ = z
}
_lastLookAtX = x
_lastLookAtY = y
_lastLookAtZ = z
}
/**
* Cameraの初期位置
* value=0で、正面から中央方向(lookAtPosition)を見る
* mode=trueで、イージングしないで変更
*/
public function angle(value:Number,mode:Boolean=false):void
{
if (mode)
{
_angle = value+90;
}
_lastAngle = value+90;
}
/**
* Cameraから、targetObjectまでの距離
* mode=trueで、イージングしないで変更
*/
public function length(value:Number,mode:Boolean=false):void
{
if (mode)
{
_length = value;
}
_lastLength = value;
}
/**
* Cameraの高さ
* mode=trueで、イージングしないで変更
*/
public function posZ(value:Number,mode:Boolean=false):void
{
if (mode)
{
_target.z = value;
}
_lastZ = value;
}
}
/**
* BasicTemplate for Alternativa3D 7.6
* Alternativa3D 7.6を扱いやすくするためのテンプレートです
* @author narutohyper & clockmaker
*
*/
import alternativ7.engine3d.containers.BSPContainer;
import alternativ7.engine3d.containers.ConflictContainer;
import alternativ7.engine3d.containers.DistanceSortContainer;
import alternativ7.engine3d.containers.KDContainer;
import alternativ7.engine3d.containers.LODContainer;
import alternativ7.engine3d.controllers.SimpleObjectController;
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.Object3DContainer;
import alternativ7.engine3d.core.View;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
class AlternativaTemplate extends Sprite
{
/**
* 子オブジェクトを最適な方法でソートするコンテナ
* (ConflictContainer)
*/
public static const CONFLICT:String = 'conflict';
/**
* 子オブジェクトをBSP(バイナリ空間分割法)によってソートするコンテナ
* (BSPContainer)
*/
public static const BSP:String = 'bsp';
/**
* 子オブジェクトをカメラからのZ値でソートするコンテナ
* (DistanceSortContainer)
*/
public static const ZSORT:String = 'zsort';
/**
* KDツリー(http://ja.wikipedia.org/wiki/Kd%E6%9C%A8)によってソートするコンテナ
* (KDContainer)
*/
public static const KD:String = 'kd';
/**
* detalizationと子オブジェクトの距離でソートするコンテナ(詳細は調査中)
* (LODContainer)
*/
public static const LOD:String = 'lod';
/**
* 3dオブジェクト格納するコンテナインスタンス。
*/
public var container:Object3DContainer;
/**
* ビューインスタンスです。
*/
public var view:View
/**
* カメラインスタンスです。
*/
public var camera:Camera3D;
/**
* カメラコントローラーです。
*/
public var cameraController:SimpleObjectController
private var _mc:DisplayObjectContainer
private var _viewWidth:int;
private var _viewHeight:int;
private var _scaleToStage:Boolean;
private var _containerType:String
/**
* 新しい Alternativa3DTemplate インスタンスを作成します。
* @param mc
* @param containerType
* @param viewWidth
* @param viewHeight
* @param scaleToStage
*/
public function AlternativaTemplate(mc:DisplayObjectContainer,containerType:String=CONFLICT,viewWidth:int=640, viewHeight:int=480, scaleToStage:Boolean = true)
{
_mc = mc
_mc.addChild(this)
_containerType = containerType
_viewWidth = viewWidth;
_viewHeight = viewHeight;
_scaleToStage = scaleToStage;
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
/**
* 初期化されたときに実行されるイベントです。
* 初期化時に実行したい処理をオーバーライドして記述します。
*/
protected function atInit():void {}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング前に実行したい処理をオーバーライドして記述します。
*/
protected function atPreRender():void {}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング前に実行したい処理をオーバーライドして記述します。
*/
private var _onPreRender:Function = function():void{};
public function get onPreRender():Function { return _onPreRender; }
public function set onPreRender(value:Function):void
{
_onPreRender = value;
}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング後に実行したい処理をオーバーライドして記述します。
*/
protected function atPostRender():void {}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング後に実行したい処理を記述します。
*/
private var _onPostRender:Function = function():void{};
public function get onPostRender():Function { return _onPostRender; }
public function set onPostRender(value:Function):void
{
_onPostRender = value;
}
/**
* レンダリングを開始します。
*/
public function startRendering():void
{
addEventListener(Event.ENTER_FRAME, onRenderTick);
}
/**
* レンダリングを停止します。
*/
public function stopRendering():void
{
removeEventListener(Event.ENTER_FRAME, onRenderTick);
}
/**
* シングルレンダリング(レンダリングを一回だけ)を実行します。
*/
public function singleRender():void
{
onRenderTick();
}
/**
* @private
*/
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.HIGH;
//Root objectの作成
if (_containerType == CONFLICT) {
container = new ConflictContainer();
} else if (_containerType == BSP) {
container = new BSPContainer();
} else if (_containerType == ZSORT) {
container = new DistanceSortContainer();
} else if (_containerType == KD) {
container = new KDContainer();
} else if (_containerType == LOD) {
container = new LODContainer();
}
//Viewの作成
view = new View(stage.stageWidth, stage.stageHeight);
_mc.addChild(view);
//cameraの作成
camera = new Camera3D();
camera.view = view;
camera.x = 0;
camera.y = -500;
camera.z = 0;
container.addChild(camera);
// Camera controller
cameraController = new SimpleObjectController(stage, camera, 10);
cameraController.mouseSensitivity = 0
cameraController.unbindAll()
cameraController.lookAtXYZ(0, 0, 0)
onResize();
stage.addEventListener(Event.RESIZE, onResize);
atInit();
}
/**
* @private
*/
private function onResize(e:Event = null):void
{
if (_scaleToStage)
{
view.width = stage.stageWidth;
view.height = stage.stageHeight;
}
else
{
view.width = _viewWidth;
view.height = _viewHeight;
}
}
/**
* @private
*/
private function onRenderTick(e:Event = null):void
{
atPreRender();
_onPreRender()
cameraController.update();
camera.render();
atPostRender();
_onPostRender();
}
}