package { import flash.display.*; import flash.events.*; import flash.geom.Matrix; import flash.geom.Point; import flash.geom.Rectangle; import flash.text.TextField; import flash.text.TextFormat; import flash.utils.getTimer; import flash.ui.Keyboard; //Papervision3Dのインポート import org.papervision3d.cameras.*; import org.papervision3d.render.BasicRenderEngine; import org.papervision3d.scenes.Scene3D; import org.papervision3d.view.Viewport3D; import org.papervision3d.core.*; import org.papervision3d.objects.primitives.Plane; import org.papervision3d.objects.parsers.Collada; import org.papervision3d.materials.*; import org.papervision3d.materials.special.CompositeMaterial; [SWF(backgroundColor=0x000000)] public class Main extends Sprite { // _______________________________________________________________________ // 変数宣言 /*システム系------------------------------------*/ //キー入力フラグ private var keyPressSpace:Boolean; private var keyPressB:Boolean; private var keyPressDown:Boolean; private var keyPressLeft:Boolean; private var keyPressRight:Boolean; //デバッグ用 private var debugText:Array; private var frameCount:Number; private var prevTimer:Number; /*挙動エンジン----------------------------------*/ //自機設定 private var myPositionX:Number; private var myPositionY:Number; private var myDirection:Number; //挙動パラメータ private var myMaxSpeed:Number; private var myCurrentSpeed:Number; private var myMaxAccel:Number; private var myCurrentAccel:Number; private var frontGravity:Number; private var sideGravity:Number; /*描画系----------------------------------------*/ //テクスチャ private var fieldBitmap:Bitmap; private var floorFarBitmapData:BitmapData; private var floorMiddleBitmapData:BitmapData; private var floorNearBitmapData:BitmapData; //コースと描画範囲 private var fieldWidth:Number; private var fieldHeight:Number; private var floorFarWidth:Number; private var floorFarHeight:Number; private var floorMiddleWidth:Number; private var floorMiddleHeight:Number; private var floorNearWidth:Number; private var floorNearHeight:Number; //2D描画 private var viewContainer:Sprite; private var viewContainerWidth:Number; private var viewContainerHeight:Number; private var skyBitmap:Bitmap; private var fieldShape:Shape; private var fogSprite:Sprite; private var carInsideBitmap:Bitmap; //Papervision3D private var scene:Scene3D; private var scene2:Scene3D; private var viewport:Viewport3D; private var viewport2:Viewport3D; private var camera:FrustumCamera3D; private var camera2:FrustumCamera3D; private var renderer:BasicRenderEngine; private var renderer2:BasicRenderEngine; private var floorFarPlane:Plane; private var floorMiddlePlane:Plane; private var floorNearPlane:Plane; private var courseObjects:Collada; private var floorFarMaterial:BitmapMaterial; private var floorMiddleMaterial:BitmapMaterial; private var floorNearMaterial:BitmapMaterial; // _______________________________________________________________________ // コンストラクタ public function Main() { initializeFlash(); initializeGame(); initialize3D(); initialize2D(); } private function initializeFlash():void { stage.frameRate = 30; //stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.quality = StageQuality.LOW; } private function initializeGame():void { //描画設定 fieldWidth = 2000; //あれ、使ってない? fieldHeight = 1500; floorFarWidth = 480; floorFarHeight = 330; floorMiddleWidth = 180; floorMiddleHeight = 60; floorNearWidth = 90; floorNearHeight = 30; myPositionX = 0; myPositionY = 0; myDirection = 0; //右向き //挙動パラメータ myMaxSpeed = 100; myCurrentSpeed = 0; myMaxAccel = 1; myCurrentAccel = 0; frontGravity = 0; sideGravity = 0; //キー入力フラグ keyPressSpace = false; keyPressB = false; keyPressDown = false; keyPressLeft = false; keyPressRight = false; //FPS算出用 frameCount = 0; prevTimer = getTimer(); //視界描画範囲の設定 viewContainer = new Sprite(); viewContainerWidth = 720; viewContainerHeight = 430; viewContainer.x = stage.stageWidth / 2; viewContainer.y = stage.stageHeight / 2 + 10; //背景の作成 addChild(viewContainer); skyBitmap = new Bitmap(); skyBitmap.bitmapData = new skySample(0, 0); skyBitmap.x = -viewContainerWidth / 2; skyBitmap.y = -viewContainerHeight / 2; viewContainer.addChild(skyBitmap); fieldShape = new Shape(); var fieldGraphics:Graphics = fieldShape.graphics; fieldGraphics.beginFill(0xa2c47d); fieldGraphics.drawRect(0, 218, viewContainerWidth, viewContainerHeight - 218); //165 fieldGraphics.endFill(); fieldShape.x = -viewContainerWidth / 2; fieldShape.y = -viewContainerHeight / 2; viewContainer.addChild(fieldShape); //イベントリスナ addEventListener(Event.ENTER_FRAME, onEnterFrame); stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler); stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler); } private function initialize2D():void { //デバッグ表示 debugText = new Array(); var debugTextFormat = new TextFormat(); debugTextFormat.size = 11; debugTextFormat.color = 0x000000; debugTextFormat.font = "Courier New"; for (var i:int = 0; i < 13; 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]); } //自機の描画 carInsideBitmap = new Bitmap(); carInsideBitmap.bitmapData = new carInside(0, 0); carInsideBitmap.x = 0; carInsideBitmap.y = 0; addChild(carInsideBitmap); } private function initialize3D():void { //2Dフォグ fogSprite = new Sprite(); var fogShape = new Shape(); //グラデーション範囲をコントロールできなかったため二重構造 var gradientGrapics:Graphics = fogShape.graphics; var gradientMatrix:Matrix = new Matrix(); var gradientColors:Array = new Array(0xddeeee, 0xddeeee, 0xddeeee, 0xddeeee); var gradientAlphas:Array = new Array(0.5, 0.3, 0.1, 0); var gradientRatios:Array = new Array(0, 25, 70, 127); gradientMatrix.createGradientBox(viewContainerWidth, viewContainerHeight - 218, Math.PI / 2, 0, 0); gradientGrapics.beginGradientFill(GradientType.LINEAR, gradientColors, gradientAlphas, gradientRatios, gradientMatrix); gradientGrapics.drawRect(0, 0, viewContainerWidth, viewContainerHeight - 218); gradientGrapics.endFill(); fogShape.y = 218; fogSprite.addChild(fogShape); fogSprite.x = -viewContainerWidth / 2; fogSprite.y = -viewContainerHeight / 2; //ビューポート設定 viewport = new Viewport3D(viewContainerWidth, viewContainerHeight, false); viewport.x = -viewContainerWidth / 2; viewport.y = -viewContainerHeight / 2; viewport2 = new Viewport3D(viewContainerWidth, viewContainerHeight, false); viewport2.x = -viewContainerWidth / 2; viewport2.y = -viewContainerHeight / 2; //描画 viewContainer.addChild(viewport); viewContainer.addChild(fogSprite); viewContainer.addChild(viewport2); //レンダー設定 renderer = new BasicRenderEngine(); renderer2 = new BasicRenderEngine(); //カメラ設定 camera = new FrustumCamera3D(viewport, 55, 10, 16000); camera.y = 250; camera.z = -400; camera2 = new FrustumCamera3D(viewport2, 55, 10, 30000); camera2.y = 250; camera2.z = -400; //シーン設定 scene = new Scene3D(); scene2 = new Scene3D(); //フィールド生成 fieldBitmap = new Bitmap(); fieldBitmap.bitmapData = new course01(0, 0); //ビットマップデータの取得 var floorFarRect:Rectangle = new Rectangle( -floorFarWidth / 2, -(floorFarHeight + floorMiddleHeight + floorNearHeight), floorFarWidth, floorFarHeight); var floorMiddleRect:Rectangle = new Rectangle( -floorMiddleWidth / 2, -(floorMiddleHeight + floorNearHeight), floorMiddleWidth, floorMiddleHeight); var floorNearRect:Rectangle = new Rectangle( -floorNearWidth / 2, -floorNearHeight, floorNearWidth, floorNearHeight); floorFarBitmapData = getFloorBitmapData(myPositionX, myPositionY, myDirection, floorFarRect); floorMiddleBitmapData = getFloorBitmapData(myPositionX, myPositionY, myDirection, floorMiddleRect); floorNearBitmapData = getFloorBitmapData(myPositionX, myPositionY, myDirection, floorNearRect); //マテリアル設定 var colorMat:ColorMaterial = new ColorMaterial( 0x006699, 1 ); var wireMat:WireframeMaterial = new WireframeMaterial( 0x0099cc ); var compoMaterial:CompositeMaterial = new CompositeMaterial(); compoMaterial.addMaterial(colorMat); compoMaterial.addMaterial(wireMat); floorFarMaterial = new BitmapMaterial(floorFarBitmapData); floorMiddleMaterial = new BitmapMaterial(floorMiddleBitmapData); floorNearMaterial = new BitmapMaterial(floorNearBitmapData); //Plane作成 var farPlaneWidth:Number = 16000; var farPlaneHeight:Number = 11000; var middlePlaneWidth:Number = 6000; var middlePlaneHeight:Number = 2000; var nearPlaneWidth:Number = 3000; var nearPlaneHeight:Number = 1000; var farPlaneSegmentW:Number = 17; var farPlaneSegmentH:Number = 11; var middlePlaneSegmentW:Number = 15; var middlePlaneSegmentH:Number = 5; var nearPlaneSegmentW:Number = 18; var nearPlaneSegmentH:Number = 6; /* floorFarPlane = new Plane(compoMaterial, farPlaneWidth, farPlaneHeight, farPlaneSegmentW, farPlaneSegmentH); floorMiddlePlane = new Plane(compoMaterial, middlePlaneWidth, middlePlaneHeight, middlePlaneSegmentW, middlePlaneSegmentH); floorNearPlane = new Plane(compoMaterial, nearPlaneWidth, nearPlaneHeight, nearPlaneSegmentW, nearPlaneSegmentH); */ floorFarPlane = new Plane(floorFarMaterial, farPlaneWidth, farPlaneHeight, farPlaneSegmentW, farPlaneSegmentH); floorMiddlePlane = new Plane(floorMiddleMaterial, middlePlaneWidth, middlePlaneHeight, middlePlaneSegmentW, middlePlaneSegmentH); floorNearPlane = new Plane(floorNearMaterial, nearPlaneWidth, nearPlaneHeight, nearPlaneSegmentW, nearPlaneSegmentH); floorFarPlane.rotationX = -90; floorMiddlePlane.rotationX = -90; floorNearPlane.rotationX = -90; floorFarPlane.z = nearPlaneHeight + middlePlaneHeight + farPlaneHeight / 2; floorMiddlePlane.z = nearPlaneHeight + middlePlaneHeight / 2; floorNearPlane.z = nearPlaneHeight / 2; //3Dモデル作成 courseObjects = new Collada("courseModel01a.dae"); courseObjects.x = 35100; courseObjects.z = 46200; courseObjects.rotationY = -90; courseObjects.scale = 1/3; //3D登録 scene.addChild(floorFarPlane); scene.addChild(floorMiddlePlane); scene.addChild(floorNearPlane); scene2.addChild(courseObjects); } private function getFloorBitmapData(x:Number, y:Number, th:Number, rect:Rectangle):BitmapData { /* 概要 : 引数を元にテクスチャとして使用すべき範囲を切り取ったビットマップデータを返す * x, y : 描画基準となるキャラクタの座標 * th : 描画基準となるキャラクタの視点向き * rect : キャラクタ位置を基準に、どの範囲をテクスチャとして切り取るか * */ var returnBitmapData:BitmapData = new BitmapData(rect.width, rect.height, false, 0xa2c47d); var captureBitmapData:BitmapData = new BitmapData(rect.width, rect.height, false, 0xa2c47d); var trimRectangle:Rectangle = new Rectangle(0, 0, rect.width, rect.height); var trimMatrix:Matrix = new Matrix(); var rotateRadian:Number; var translateX:Number; var translateY:Number; //座標の回転移動 rotateRadian = -(th - (-Math.PI/2)); // -π/2の向き(上)を基準にする translateX = x * Math.cos(rotateRadian) - y * Math.sin(rotateRadian); translateY = y * Math.cos(rotateRadian) + x * Math.sin(rotateRadian); trimMatrix.rotate(rotateRadian); trimMatrix.translate( -(translateX + rect.x), -(translateY - 5 + rect.y)); //描画範囲をキャプチャ captureBitmapData.draw(fieldBitmap, trimMatrix, null, null, trimRectangle, false); returnBitmapData = captureBitmapData; return returnBitmapData; } private function onEnterFrame(event:Event):void { //挙動処理 moveMyCar(); //3Dカメラ移動(未実装) moveCamera(); //3D更新 renderer.renderScene(scene, camera, viewport); renderer2.renderScene(scene2, camera2, viewport2); //デバッグ表示 renderDebug(); } private function keyDownHandler(event:KeyboardEvent):void { if (event.keyCode == Keyboard.SPACE) { keyPressSpace = true; } if (event.keyCode == 66) //[B] { keyPressB = true; } if (event.keyCode == Keyboard.DOWN) { keyPressDown = true; } if (event.keyCode == Keyboard.LEFT) { keyPressLeft = true; } if (event.keyCode == Keyboard.RIGHT) { keyPressRight = true; } } private function keyUpHandler(event:KeyboardEvent):void { if (event.keyCode == Keyboard.SPACE) { keyPressSpace = false; } if (event.keyCode == 66) //[B] { keyPressB = false; } if (event.keyCode == Keyboard.DOWN) { keyPressDown = false; } if (event.keyCode == Keyboard.LEFT) { keyPressLeft = false; } if (event.keyCode == Keyboard.RIGHT) { keyPressRight = false; } } private function moveMyCar():void { if (keyPressSpace) { //前進加速 myCurrentAccel = myMaxAccel * 0.2 + myMaxAccel * (myMaxSpeed - myCurrentSpeed) / myMaxSpeed * 0.8; } else if (keyPressDown) { //後退加速 myCurrentAccel = -myMaxAccel * 0.7; } else { //自然減速(前進中) if (myCurrentSpeed > myMaxAccel * 0.4) { myCurrentAccel = -myMaxAccel * 0.4; } //自然減速(後退中) else if (myCurrentSpeed < -myMaxAccel * 0.4) { myCurrentAccel = myMaxAccel * 0.4; } //停止 else { myCurrentAccel = 0; myCurrentSpeed = 0; } } //旋回 if (keyPressLeft || keyPressRight) { //旋回による加速度低下 if (!keyPressB && myCurrentSpeed > myMaxSpeed * 0.3) { myCurrentAccel -= myMaxAccel * 0.3 * (myCurrentSpeed / myMaxSpeed); if (myCurrentAccel < -myMaxAccel) { myCurrentAccel = -myMaxAccel; } } //現在速度と現在加速度による係数 var speedCoefficient:Number = (myMaxSpeed - Math.abs(myCurrentSpeed)) / myMaxSpeed; var accelCoefficient:Number; if (myCurrentSpeed > 0) { accelCoefficient = (myMaxAccel - myCurrentAccel) / (2 * myMaxAccel); } else if (myCurrentSpeed < 0) { accelCoefficient = (myMaxAccel + myCurrentAccel) / (2 * myMaxAccel); } else { accelCoefficient = 0; } } var deltaDirection:Number = 0; //左旋回 if (keyPressLeft) { if (myCurrentSpeed != 0) { deltaDirection = -(0.2 + 1 * speedCoefficient + 1 * accelCoefficient) / 180 * Math.PI; } } //右旋回 if (keyPressRight) { if (myCurrentSpeed != 0) { deltaDirection = +(0.2 + 1 * speedCoefficient + 1 * accelCoefficient) / 180 * Math.PI; } } //ブレーキによる減速は旋回に影響を与えない if (keyPressB) { //ブレーキ減速(前進中) if (myCurrentSpeed > myMaxAccel * 1) { myCurrentAccel -= myMaxAccel * 1; } //ブレーキ減速(後退中) else if (myCurrentSpeed < -myMaxAccel * 1) { myCurrentAccel += myMaxAccel * 1; } //停止 else { myCurrentAccel = 0; myCurrentSpeed = 0; } } //加速処理 myCurrentSpeed += myCurrentAccel; //旋回処理 myDirection += deltaDirection; //速度補正 if (myCurrentSpeed > myMaxSpeed) { myCurrentSpeed = myMaxSpeed; } if (myCurrentSpeed < -myMaxSpeed * 0.3) { myCurrentSpeed = -myMaxSpeed * 0.3; } //角度補正 if (myDirection >= 2 * Math.PI) { myDirection -= 2 * Math.PI; } if (myDirection < 0) { myDirection += 2 * Math.PI; } //移動 myPositionX += 6 * (myCurrentSpeed / myMaxSpeed) * Math.cos(myDirection); myPositionY += 6 * (myCurrentSpeed / myMaxSpeed) * Math.sin(myDirection); //カメラ移動(暫定) camera2.z += (12000 / 360) * 6 * (myCurrentSpeed / myMaxSpeed) * Math.cos(myDirection); camera2.x += (12000 / 360) * 6 * (myCurrentSpeed / myMaxSpeed) * Math.sin(myDirection); //camera2.rotationY += deltaDirection * 180 / Math.PI; camera2.yaw(deltaDirection * 180 / Math.PI); //FrustumCamera3Dはrotation系の代入が反映されないため //荷重動作 sideGravity += ((deltaDirection * 180 / Math.PI) * 1.8 - sideGravity) / 8; frontGravity += ( -myCurrentAccel * 18 - frontGravity) / 8; viewContainer.rotation = sideGravity; viewContainer.y = stage.stageHeight / 2 - 20 - frontGravity; //3D描画更新 //ビットマップデータの取得 var floorFarRect:Rectangle = new Rectangle( -floorFarWidth / 2, -(floorFarHeight + floorMiddleHeight + floorNearHeight), floorFarWidth, floorFarHeight); var floorMiddleRect:Rectangle = new Rectangle( -floorMiddleWidth / 2, -(floorMiddleHeight + floorNearHeight), floorMiddleWidth, floorMiddleHeight); var floorNearRect:Rectangle = new Rectangle( -floorNearWidth / 2, -floorNearHeight, floorNearWidth, floorNearHeight); floorFarBitmapData = getFloorBitmapData(myPositionX, myPositionY, myDirection, floorFarRect); floorMiddleBitmapData = getFloorBitmapData(myPositionX, myPositionY, myDirection, floorMiddleRect); floorNearBitmapData = getFloorBitmapData(myPositionX, myPositionY, myDirection, floorNearRect); //マテリアル更新 floorFarMaterial.bitmap = floorFarBitmapData; floorMiddleMaterial.bitmap = floorMiddleBitmapData; floorNearMaterial.bitmap = floorNearBitmapData; floorFarMaterial.updateBitmap(); floorMiddleMaterial.updateBitmap(); floorNearMaterial.updateBitmap(); } function moveCamera():void { } function renderDebug():void { //FPS算出 frameCount += 1; if ((getTimer() - prevTimer) / 1000 >= 0.25) { var fps:Number = frameCount * 1000 / (getTimer() - prevTimer); fps = Math.floor(fps * 10) / 10; prevTimer = getTimer(); frameCount = 0; //FPS表示 debugText[0].text = "FPS : " + fps; } //デバッグ表示 debugText[2].text = "SPEED : " + Math.floor(myCurrentSpeed); debugText[3].text = "ACCEL : " + Math.floor(myCurrentAccel * 100); debugText[4].text = "FRONT_G : " + Math.floor(frontGravity * 2); debugText[5].text = "SIDE_G : " + Math.floor(sideGravity * 10); debugText[7].text = "MY_X : " + Math.floor(myPositionX); debugText[8].text = "MY_Y : " + Math.floor(myPositionY); debugText[9].text = "MY_DIREC : " + Math.floor(myDirection * 180 / Math.PI); debugText[11].text = "CAMERA_Y : " + camera.y; debugText[12].text = "CAMERA_Z : " + camera.z; } } }