開発環境 Apache Flex SDK 4.12.1
FlashDevelop 4.6.2.5
実行環境 Microsoft Windows 8.1 (64bit)
プロジェクトの種類 ActionScript 3/AS3 Project
プロジェクト名 FlightSim2

作りかけ。


Main.as
package 
{
    import com.adobe.utils.*;
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.display3D.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.text.*;
    import flash.ui.Keyboard;
    import mx.utils.StringUtil;
 
    public class Main extends Sprite 
    {
        private var context3D:Context3D;
        private var vertexBuffer:VertexBuffer3D;
        private var indexBuffer:IndexBuffer3D;
 
        private var vertexData:Vector.<Number> = new Vector.<Number>;
        private var indexData:Vector.<uint> = new Vector.<uint>;
        private var numVertices:int = 0;
 
        private var projectionTransform:PerspectiveMatrix3D;
        private var viewTransform:Matrix3D;
 
        private var cameraPos:Vector3D = new Vector3D(0, 200, 0);
        private var cameraFront:Vector3D = new Vector3D(0, 0, 1);
        private var cameraUp:Vector3D = new Vector3D(0, 1, 0);
        private var velocity:Number = 0; // 速度
 
        private var roll:Number = 0;
        private var pitch:Number = 0;
        private var yaw:Number = 0;
        private var throttle:Number = 0; // 推力
 
        private const throttleMax:Number = 0.03;
 
        private var textFormat:TextFormat = new TextFormat(null, 20, 0xffffff);
        private var tfParams:TextField;
        private var tfThrottle:TextField;
        private var tfVelocity:TextField;
        private var sprite:Sprite = new Sprite;
 
        private const barX:Number = 200;
        private const barWidth:Number = 550;
        private const barHeight:Number = 25;
 
        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);
            // entry point
 
            stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreate);
            stage.stage3Ds[0].requestContext3D();
 
            addEventListener(Event.ENTER_FRAME, onRender);
 
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
            stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
 
            tfParams = addTextField(0, 0);
            tfThrottle = addTextField(50, 500);
            tfVelocity = addTextField(50, 550);
 
            var g:Graphics = graphics;
            g.lineStyle(1, 0xffffff);
            g.drawRect(barX, 500, barWidth, barHeight);
            g.drawRect(barX, 550, barWidth, barHeight);
            for (var i:int = 0; i < 250; i += 50) 
            {
                var x:Number = barX + barWidth * i / 250;
                g.moveTo(x, 550);
                g.lineTo(x, 550 + barHeight);
            }
 
            addChild(sprite);
        }
 
        private function addTextField(x:Number, y:Number):TextField
        {
            var tf:TextField = new TextField;
            tf.defaultTextFormat = textFormat;
            tf.autoSize = TextFieldAutoSize.LEFT;
            tf.x = x;
            tf.y = y;
            addChild(tf);
            return tf;
        }
 
        private function onContext3DCreate(e:Event):void 
        {
            context3D = stage.stage3Ds[0].context3D;
            context3D.configureBackBuffer(800, 600, 2);
            context3D.setCulling(Context3DTriangleFace.BACK);
 
            generateSurface();
            generateCloud(-1000, 500, -1000, 100, 100, 100);
            generateCloud(1000, 500, -1000, 100, 100, 100);
            generateCloud(1000, 500, 1000, 100, 100, 100);
            generateCloud(-1000, 500, 1000, 100, 100, 100);
 
            // vertexBuffer
            vertexBuffer = context3D.createVertexBuffer(numVertices, 6);
            vertexBuffer.uploadFromVector(vertexData, 0, numVertices);
 
            // indexBuffer
            indexBuffer = context3D.createIndexBuffer(indexData.length);
            indexBuffer.uploadFromVector(indexData, 0, indexData.length);
 
            // program
            var vertexProgram:AGALMiniAssembler = new AGALMiniAssembler;
            vertexProgram.assemble(Context3DProgramType.VERTEX,
                "m44 op va0 vc0\n" +
                "mov v0 va1"
            );
            var fragmentProgram:AGALMiniAssembler = new AGALMiniAssembler;
            fragmentProgram.assemble(Context3DProgramType.FRAGMENT,
                "mov oc v0"
            );
            var program:Program3D = context3D.createProgram();
            program.upload(vertexProgram.agalcode, fragmentProgram.agalcode);
 
            //
            context3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
            context3D.setVertexBufferAt(1, vertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_3);
            context3D.setProgram(program);
 
            //
            viewTransform = new Matrix3D;
            projectionTransform = new PerspectiveMatrix3D;
            projectionTransform.perspectiveFieldOfViewLH(45 * Math.PI / 180, 800 / 600, 1, 5000);
        }
 
        private function generateSurface():void 
        {
            const vertices:Vector.<Number> = Vector.<Number>([
            //  x, y, z, r, g, b,
                0, 0, 0, 0, 0, 0,
                0, 0, 1, 0, 0.5, 0.5,
                1, 0, 1, 0, 1, 1,
                1, 0, 0, 0, 0.5, 0.5,
            ]);
            const indices:Vector.<uint> = Vector.<uint>([
                0, 1, 2, 2, 3, 0,
            ]);
 
            for (var z:int = -10; z < 10; z++) 
            {
                var green:Number = (0 <= z) ? 1 : 0;
                var blue:Number = (0 <= z) ? 0 : 1;
                for (var x:int = -10; x < 10; x++) 
                {
                    for (var i:int = 0; i < 4; i++) 
                    {
                        var base:int = i * 6;
                        vertexData.push((vertices[base + 0] + x) * 100);
                        vertexData.push(vertices[base + 1]);
                        vertexData.push((vertices[base + 2] + z) * 100);
                        vertexData.push(vertices[base + 3]);
                        vertexData.push(vertices[base + 4] * green);
                        vertexData.push(vertices[base + 5] * blue);
                    }
                    for (i = 0; i < indices.length; i++) 
                    {
                        indexData.push(numVertices + indices[i]);
                    }
                    numVertices += 4;
                }
            }
        }
 
        private function generateCloud(
            x0:Number, y0:Number, z0:Number, x1:Number, y1:Number, z1:Number):void 
        {
            const vertices:Vector.<Number> = Vector.<Number>([
            //  x, y, z, r, g, b,
                0, 0, 0, 0.5, 0.5, 0.5,
                1, 0, 0, 0.5, 0.5, 0.5,
                1, 0, 1, 0.5, 0.5, 0.5,
                0, 0, 1, 0.5, 0.5, 0.5,
                0, 1, 0, 1, 1, 1,
                1, 1, 0, 1, 1, 1,
                1, 1, 1, 1, 1, 1,
                0, 1, 1, 1, 1, 1,
            ]);
            const indices:Vector.<uint> = Vector.<uint>([
                0, 4, 5, 5, 1, 0, // -z
                1, 5, 6, 6, 2, 1, // +x
                2, 6, 7, 7, 3, 2, // +z
                3, 7, 4, 4, 0, 3, // -x
                0, 1, 2, 2, 3, 0, // -y
                4, 7, 6, 6, 5, 4, // +y
            ]);
 
            for (var i:int = 0; i < 8; i++) 
            {
                var base:int = i * 6;
                vertexData.push(x0 + vertices[base + 0] * x1);
                vertexData.push(y0 + vertices[base + 1] * y1);
                vertexData.push(z0 + vertices[base + 2] * z1);
                vertexData.push(vertices[base + 3]);
                vertexData.push(vertices[base + 4]);
                vertexData.push(vertices[base + 5]);
            }
            for (i = 0; i < indices.length; i++) 
            {
                indexData.push(numVertices + indices[i]);
            }
            numVertices += 8;
        }
 
        private function onRender(e:Event):void 
        {
            if (!context3D) return;
 
            context3D.clear(0.39, 0.58, 0.93);
            updateViewMatrix();
 
            var m:Matrix3D = new Matrix3D;
            m.append(viewTransform);
            m.append(projectionTransform);
 
            context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m, true);
            context3D.drawTriangles(indexBuffer);
            context3D.present();
        }
 
        private function updateViewMatrix():void 
        {
            // update
            var m:Matrix3D = new Matrix3D;
 
            var cameraCross:Vector3D;
            cameraCross = cameraFront.crossProduct(cameraUp);
 
            m.identity();
            m.prependRotation(yaw, cameraUp);
            cameraFront = m.transformVector(cameraFront);
            cameraCross = m.transformVector(cameraCross);
 
            m.identity();
            m.prependRotation(pitch, cameraCross);
            cameraFront = m.transformVector(cameraFront);
            cameraUp = m.transformVector(cameraUp);
 
            m.identity();
            m.prependRotation(roll, cameraFront);
            cameraCross = m.transformVector(cameraCross);
            cameraUp = m.transformVector(cameraUp);
 
            //
            var drag:Number; // 抗力
            drag = velocity * velocity * 0.01;
            velocity += (throttle - drag) * 0.5;
 
            var forward:Vector3D = new Vector3D;
            forward.copyFrom(cameraFront);
            forward.scaleBy(velocity);
            cameraPos = cameraPos.add(forward);
 
            // transform
            var cameraTransform:Matrix3D = new Matrix3D;
            cameraTransform = lookAt(cameraPos, cameraPos.subtract(cameraFront), cameraUp);
 
            viewTransform.copyFrom(cameraTransform);
            //viewTransform.invert();
 
            displayParams(drag);
 
        }
 
        private function displayParams(drag:Number):void 
        {
            var camPitch:Number = degrees(Math.asin(cameraFront.y));
            var camYaw:Number = degrees(Math.atan2(cameraFront.x, cameraFront.z));
            if (camYaw < 0) camYaw += 360;
 
            var camCross:Vector3D = Vector3D.X_AXIS;
            var camUp:Vector3D = Vector3D.Y_AXIS;
            var m:Matrix3D = new Matrix3D;
 
            m.identity();
            m.prependRotation(camYaw, Vector3D.Y_AXIS);
            camCross = m.transformVector(camCross);
 
            m.identity();
            m.prependRotation(-camPitch, camCross);
            camUp = m.transformVector(camUp);
 
            var camRoll:Number = degrees(Math.acos(clamp(camUp.dotProduct(cameraUp), -1, 1)));
            if (camCross.dotProduct(cameraUp) < 0) camRoll = -camRoll;
 
            tfParams.text = StringUtil.substitute(
                "Pos:{0} {1} {2}\nPitch:{3} Yaw:{4} Roll:{5}\nDrag:{6}",
                cameraPos.x.toFixed(0), cameraPos.y.toFixed(0), cameraPos.z.toFixed(0),
                camPitch.toFixed(0), camYaw.toFixed(0), camRoll.toFixed(0),
                drag.toFixed(3));
            tfThrottle.text = StringUtil.substitute("Throttle:{0}", throttle.toFixed(3));
            tfVelocity.text = StringUtil.substitute("Velocity:{0}km/h", (velocity * 108).toFixed(0));
 
            //
            var g:Graphics = sprite.graphics;
            g.clear();
 
            g.beginFill(0xffffff, 0.75);
            g.drawRect(barX, 500, barWidth * throttle / throttleMax, barHeight);
            g.endFill();
 
            g.beginFill(0xffff00, 0.75);
            g.drawRect(barX, 550, barWidth * (velocity * 108) / 250, barHeight);
            g.endFill();
        }
 
        private function onKeyDown(e:KeyboardEvent):void 
        {
            switch (e.keyCode) 
            {
                case Keyboard.LEFT: // aileron
                    roll = 1;
                    break;
                case Keyboard.RIGHT:
                    roll = -1;
                    break;
                case Keyboard.UP: // elevator
                    pitch = -1;
                    break;
                case Keyboard.DOWN:
                    pitch = 1;
                    break;
                case Keyboard.Z: // rudder
                    yaw = -1;
                    break;
                case Keyboard.X:
                    yaw = 1;
                    break;
                case Keyboard.Q: // throttle
                    throttle = Math.min(throttle + 0.001, throttleMax);
                    break;
                case Keyboard.A:
                    throttle = Math.max(throttle - 0.001, 0);
                    break;
            }
        }
 
        private function onKeyUp(e:KeyboardEvent):void 
        {
            switch (e.keyCode) 
            {
                case Keyboard.LEFT:
                case Keyboard.RIGHT:
                    roll = 0;
                    break;
                case Keyboard.UP:
                case Keyboard.DOWN:
                    pitch = 0;
                    break;
                case Keyboard.Z:
                case Keyboard.X:
                    yaw = 0;
                    break;
            }
        }
 
        private function lookAt(eye:Vector3D, at:Vector3D, up:Vector3D):Matrix3D
        {
            var m:Vector.<Number> = new Vector.<Number>(16);
 
            // z軸 = eye - at
            at.x = eye.x - at.x;
            at.y = eye.y - at.y;
            at.z = eye.z - at.z;
            m[2] = at.x / at.length;
            m[6] = at.y / at.length;
            m[10] = at.z / at.length;
 
            // x軸 = up × z軸
            at.x = up.y * m[10] - up.z * m[6];
            at.y = up.z * m[2] - up.x * m[10];
            at.z = up.x * m[6] - up.y * m[2];
            m[0] = at.x / at.length;
            m[4] = at.y / at.length;
            m[8] = at.z / at.length;
 
            // y軸 = z軸 × x軸
            m[1] = m[6] * m[8] - m[10] * m[4];
            m[5] = m[10] * m[0] - m[2] * m[8];
            m[9] = m[2] * m[4] - m[6] * m[0];
 
            // 平行移動
            m[12] = -(eye.x * m[0] + eye.y * m[4] + eye.z * m[8]);
            m[13] = -(eye.x * m[1] + eye.y * m[5] + eye.z * m[9]);
            m[14] = -(eye.x * m[2] + eye.y * m[6] + eye.z * m[10]);
 
            m[3] = m[7] = m[11] = 0;
            m[15] = 1;
 
            var matrix:Matrix3D = new Matrix3D;
            matrix.rawData = m;
            return matrix;
        }
 
        private function degrees(x:Number):Number
        {
            return x * 180 / Math.PI;
        }
 
        private function clamp(x:Number, min:Number, max:Number):Number
        {
            if (x <= min) return min;
            if (max <= x) return max;
            return x;
        }
    }
 
}
 
最終更新:2014年07月23日 10:15