Страницы

понедельник, 7 января 2013 г.

Nape - камера в игре

      Очень часто в играх необходимо реализовать так называемую - камеру. Камера фокусируется на главном герое, и при перемещении главного героя он остается по центру игрового экрана, а весь мир передвигается относительно героя.
      В Nape при Debug отрисовке можно использовать при обновлении экрана:

camera_x = hero.position.x - stage.width/2;
camera_y = hero.position.y - stage.height/2;

debug.transform = Mat23.translation( -camera_x, -camera_y);

      Таким образом мы получаем смещенную отрисовку относительно координат hero, который всегда находится по центру экрана.

      Модифицируем наш пример с машинкой:


package
{ 
    import flash.display.Sprite;
    import flash.display.DisplayObject;
    import flash.events.Event;
    import flash.events.KeyboardEvent; //клавиатурные события
    import nape.callbacks.BodyCallback;
    import nape.constraint.DistanceJoint;
    import nape.phys.Compound;
    import nape.phys.Material;
    import nape.callbacks.CbType;
    import nape.callbacks.CbEvent;
    import nape.callbacks.BodyListener;
  
    import nape.geom.Vec2;
    import nape.phys.Body;
    import nape.phys.BodyType;
    import nape.shape.Circle;
    import nape.shape.Polygon;
    import nape.space.Space;
    import nape.util.BitmapDebug;
    import nape.util.Debug;
    import nape.shape.Shape;
    import nape.geom.Mat23;
 
    public class Main extends Sprite
    {
        private var space:Space;
        private var debug:Debug;
  
        private var wheel_front:Body;
        private var wheel_rear:Body;
        private var cabin:Body;
  
        //Ограничение для колес
        private var wheel_f_joint:DistanceJoint;
        private var wheel_r_joint:DistanceJoint;
        private var cabin_front_joint:DistanceJoint;
        private var cabin_rear_joint:DistanceJoint;

        // Объединения
        private var car:Compound;
 
        // Обратные вызовы
        private var cbCarType:CbType;
  
        //Камера
        private var camera_x:Number = 0;
        private var camera_y:Number = 0;
  
        //Кузов
        [Embed(source="../assets/cabin.png")]
        private var Cabin:Class;
  
        //Колеса
        [Embed(source="../assets/wheel.png")]
        private var Wheel:Class;
  
        public function Main():void
        {
            super();
 
            if (stage != null) {
                initialise(null);
            }
            else {
                addEventListener(Event.ADDED_TO_STAGE, initialise);
            }
        }
 
        private function initialise(ev:Event):void
        {
            if (ev != null) {
                removeEventListener(Event.ADDED_TO_STAGE, initialise);
            }
 
            var gravity:Vec2 = Vec2.weak(0, 400);
            space = new Space(gravity);
 
            debug = new BitmapDebug(stage.stageWidth, stage.stageHeight,
                stage.color);
   
            //Рисуем Ограничения
            debug.drawConstraints = true;
            addChild(debug.display);
   
            setUp();
            
            // Обработчик клавиатуры
            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
            stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
        }
 
        private function setUp():void
        {
            var w:int = stage.stageWidth;
            var h:int = stage.stageHeight;
   
            //Устанавливаем границы мира
            var border:Body = new Body(BodyType.STATIC);
            border.shapes.add(new Polygon(Polygon.rect(0, 0, w*4, -1)));
            border.shapes.add(new Polygon(Polygon.rect(0, h*3, w*4, 1)));
            border.shapes.add(new Polygon(Polygon.rect(0, 0, -1, h*3)));
            border.shapes.add(new Polygon(Polygon.rect(w*4, 0, 1, h*3)));
            border.space = space;
   
            // Статическая земля   
            var floor:Body = new Body(BodyType.STATIC);
            floor.shapes.add(new Polygon(Polygon.regular(220, 100, 6, 0, false),
                Material.rubber()));
            floor.position.setxy(1420, 1800);
            floor.space = space;
   
            // Объединение - машина
            car = new Compound();
      
            // Колесо переднее
            wheel_front = new Body(BodyType.DYNAMIC);
            wheel_front.position.setxy(290, 106);
            var wheel_frontShape:Shape = new Circle(28, null, Material.rubber());
            wheel_frontShape.body = wheel_front; 
            //wheel_front.angularVel = 20;
            wheel_front.compound = car;
   
            // Колесо заднее
            wheel_rear = new Body(BodyType.DYNAMIC);
            wheel_rear.position.setxy(200, 106);
            var wheel_rearShape:Shape = new Circle(28, null, Material.rubber());
            wheel_rearShape.body = wheel_rear;  
            //wheel_rear.angularVel = 20;
            wheel_rear.compound = car;
   
            // Кузов
            var cabinIso:BitmapDataIso = new BitmapDataIso((new Cabin()).bitmapData, 0x80);
            cabin = IsoBody.run(cabinIso, cabinIso.bounds);
            cabin.mass = 10;
            cabin.position.setxy(245, 70);
            cabin.compound = car;
   
            //Ограничение для колес (держит межколесное расстояние)
            wheel_f_joint = new DistanceJoint(wheel_front, cabin, wheel_front.localCOM,
                cabin.localCOM, 88, 88);
            wheel_f_joint.compound = car;
            wheel_r_joint = new DistanceJoint(wheel_rear, cabin, wheel_rear.localCOM,
                cabin.localCOM, 80, 80);
            wheel_r_joint.compound = car;
   
            //Передний амортизатор
            cabin_front_joint = new DistanceJoint(wheel_front, cabin,
            wheel_front.localCOM, cabin.worldPointToLocal(Vec2.weak(cabin.position.x + 70,
                cabin.position.y)), 52, 55);
            cabin_front_joint.compound = car;
   
            //Задний амортизатор
            cabin_rear_joint = new DistanceJoint(wheel_rear, cabin,
            wheel_rear.localCOM, cabin.worldPointToLocal(Vec2.weak(cabin.position.x - 62,
                cabin.position.y)), 52, 55);
            cabin_rear_joint.compound = car;
   
            //Выводим машинку со всеми ограничениями
            car.space = space;
   
            //Обратный вызов для переднего колеса
            cbCarType = new CbType();
            wheel_front.cbTypes.add(cbCarType);
            wheel_front.space.listeners.add(new BodyListener(CbEvent.SLEEP, cbCarType,
                carSleepHandler));
        }
  
        private function carSleepHandler(cb:BodyCallback):void 
        {
            //Как только засыпает - едем!
            var impulse:Vec2  = Vec2.get(10, 0);
            impulse.length   = 3200;
            cabin.applyImpulse(impulse);
        }
 
        private function enterFrameHandler(ev:Event):void 
        {
            space.step(1 / stage.frameRate);
   
            //Фокус на машину, центрируем
            camera_x = cabin.position.x - stage.width/2;
            camera_y = cabin.position.y - stage.height/2;
   
            debug.clear();
            debug.transform = Mat23.translation( -camera_x, -camera_y);
            debug.draw(space);
            debug.flush();
        }
  
        private function keyDownHandler(e:KeyboardEvent):void
        {
            if (e.keyCode == 37)
            { // влево
                car.rotate(wheel_rear.worldCOM, -0.5);
            }
            if (e.keyCode == 39)
            { // вправо
                car.rotate(wheel_front.worldCOM, 0.5);
            }
            if (e.keyCode == 40)
            { // вниз
                wheel_front.angularVel -= 3;
                wheel_rear.angularVel -= 3;
                if ((wheel_front.angularVel < -30) || (wheel_rear.angularVel < -30))
                {
                     wheel_front.angularVel = -30;
                     wheel_rear.angularVel = -30;
                }
            }
            if (e.keyCode == 38)
            { // вверх
                wheel_front.angularVel += 3;
                wheel_rear.angularVel += 3;
                if ((wheel_front.angularVel > 30) || (wheel_rear.angularVel > 30))
                {
                    wheel_front.angularVel = 30;
                    wheel_rear.angularVel = 30;
                }
            }
        }
    }
}

      В примере пространство Nape увеличено, чтобы можно было посмотреть работу камеры. Управление машинкой: вверх/вниз - увеличение/уменьшение скорости, влево/вправо - кувырки.
      Поиграть можно тут