[Stage3D] Feathersでシーン遷移! (5) ~ScreenNavigator, ScrollContainer~

Flash Player 11 から採用された Stage3D を学習するよ。 :bouzu:
Starling FrameworkFeathers でシーン遷移を試しちゃうんだからね。 :girl:

starling_feathers_screen35

:caution: 要 Flash Player 11.8 以上

遷移は、ScreenSlidingPushTransitionManager (カスタムクラス) で。

This movie requires Flash Player 11.8.0

Main.as
package {

  import flash.display.Sprite;
  import flash.display.StageScaleMode;
  import flash.display.StageAlign;

  import starling.core.Starling;

  [SWF(backgroundColor="#FFFFFF", width="600", height="800", frameRate="60")]

  public class Main extends Sprite {
    // プロパティ
    private static var bw:uint = 600;
    private static var bh:uint = 800;
    private var starling:Starling;

    // コンストラクタ
    public function Main() {
      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;
      init();
    }

    // メソッド
    private function init():void {
      mouseEnabled = false;
      mouseChildren = false;
      starling = new Starling(MainView, stage, null, null);
      starling.enableErrorChecking = true;
      starling.start();
      resize();
      stage.addEventListener(Event.RESIZE, resize, false, 0, true);
    }
    private function resize(evt:Event = null):void {
      var sw:uint = stage.stageWidth;
      var sh:uint = stage.stageHeight;
      var scale:Number = Math.min(sw/bw, sh/bh);
      var vw:Number = bw*scale;
      var vh:Number = bh*scale;
      var vx:int = int((sw – vw)/2);
      var vy:int = int((sh – vh)/2);
      starling.viewPort = new Rectangle(vx, vy, vw, vh);
    }
  }

}



import starling.core.Starling;
import starling.display.Sprite;
import starling.events.Event;
import starling.animation.Transitions;

import feathers.controls.ScreenNavigator;
import feathers.controls.ScreenNavigatorItem;
import feathers.system.DeviceCapabilities;
import feathers.themes.MetalWorksMobileTheme;

import feathers.screens.HomeScreen;
import feathers.screens.Content1Screen;
import feathers.screens.Content2Screen;
import feathers.screens.Content3Screen;

import feathers.motion.transitions.ScreenSlidingPushTransitionManager;

internal class MainView extends Sprite {
  // プロパティ
  private static var bw:uint = 600;
  private static var bh:uint = 800;
  private var navigator:ScreenNavigator;
  private var transition:ScreenSlidingPushTransitionManager;
  private static const HOME:String = "home";
  private static const CONTENT1:String = "content1";
  private static const CONTENT2:String = "content2";
  private static const CONTENT3:String = "content3";

  // コンストラクタ
  public function MainView() {
    addEventListener(Event.ADDED_TO_STAGE, init);
    addEventListener(Event.REMOVED_FROM_STAGE, remove);
  }

  // メソッド
  private function init(evt:Event):void {
    removeEventListener(Event.ADDED_TO_STAGE, init);
    DeviceCapabilities.dpi = 174;
    var theme:MetalWorksMobileTheme = new MetalWorksMobileTheme();
    navigator = new ScreenNavigator();
    addChild(navigator);

    navigator.addScreen(HOME, new ScreenNavigatorItem(new HomeScreen(), {onNext1: CONTENT1, onNext2: CONTENT2, onNext3: CONTENT3}));
    navigator.addScreen(CONTENT1, new ScreenNavigatorItem(new Content1Screen(), {onBack: HOME}));
    navigator.addScreen(CONTENT2, new ScreenNavigatorItem(new Content2Screen(), {onBack: HOME}));
    navigator.addScreen(CONTENT3, new ScreenNavigatorItem(new Content3Screen(), {onBack: HOME}));
    navigator.showScreen(HOME);

    transition = new ScreenSlidingPushTransitionManager(navigator);
    transition.duration = 0.4;
    transition.ease = Transitions.EASE_OUT;

  }
  private function remove(evt:Event):void {
    removeEventListener(Event.REMOVED_FROM_STAGE, remove);
  }
  override public function dispose():void {
    removeEventListener(Event.ADDED_TO_STAGE, init);
    removeEventListener(Event.REMOVED_FROM_STAGE, remove);
    super.dispose();
  }

}

HomeScreen.as (feathers.screens.HomeScreen.as)
package feathers.screens {

  import flash.utils.Dictionary;
  import starling.display.Sprite;
  import starling.display.Quad;
  import starling.events.Event;
  import starling.events.Touch;
  import starling.events.TouchEvent;
  import starling.events.TouchPhase;

  import feathers.controls.Screen;
  import feathers.controls.ScrollContainer;
  import feathers.layout.VerticalLayout;
  import feathers.events.FeathersEventType;

  import org.osflash.signals.Signal;
  import org.osflash.signals.ISignal;


  public class HomeScreen extends Screen {
    // プロパティ
    private static var bw:uint = 600;
    private static var bh:uint = 800;
    private static var offset:uint = 35;
    protected var _onNext1:Signal = new Signal(HomeScreen);
    protected var _onNext2:Signal = new Signal(HomeScreen);
    protected var _onNext3:Signal = new Signal(HomeScreen);
    private var dictionary:Dictionary;
    private var container:ScrollContainer;
    private var scrolling:Boolean = false;

    // コンストラクタ
    public function Screen1() {
    }

    // メソッド
    override protected function initialize():void {
      var container:ScrollContainer = new ScrollContainer();
      addChild(container);

      container.width = bw;
      container.height = 740;
      container.y = offset;
      container.addEventListener(FeathersEventType.SCROLL_START, scroll);
      container.addEventListener(FeathersEventType.SCROLL_COMPLETE, scrolled);

      var layout:VerticalLayout = new VerticalLayout();
      layout.horizontalAlign = VerticalLayout.HORIZONTAL_ALIGN_CENTER;

      container.layout = layout;
      var content1:Sprite = new Sprite();
      container.addChild(content1);
      var paper1:Quad = new Quad(bw, 200, 0x66CCFF);
      content1.addChild(paper1);
      content1.flatten();
      content1.touchGroup = true;
      content1.addEventListener(TouchEvent.TOUCH, touch);
      var content2:Sprite = new Sprite();
      container.addChild(content2);
      var paper2:Quad = new Quad(bw, 400, 0x66CC00);
      content2.addChild(paper2);
      content2.flatten();
      content2.touchGroup = true;
      content2.addEventListener(TouchEvent.TOUCH, touch);
      var content3:Sprite = new Sprite();
      container.addChild(content3);
      var paper3:Quad = new Quad(bw, 600, 0xCCCC00);
      content3.addChild(paper3);
      content3.flatten();
      content3.touchGroup = true;
      content3.addEventListener(TouchEvent.TOUCH, touch);
      dictionary = new Dictionary(true);
      dictionary[content1] = _onNext1;
      dictionary[content2] = _onNext2;
      dictionary[content3] = _onNext3;
    }
    override protected function draw():void {
    }
    private function scroll(evt:Event):void {
      scrolling = true;
    }
    private function scrolled(evt:Event):void {
      scrolling = false;
    }
    private function touch(evt:TouchEvent):void {
      var touch:Touch = evt.getTouch(this, TouchPhase.ENDED);
      if (touch) {
        if (!scrolling) {
          var _onPage:ISignal = dictionary[evt.target];
          _onPage.dispatch(this);
        }
      }
    }
    public function get onNext1():ISignal {
      return _onNext1;
    }
    public function get onNext2():ISignal {
      return _onNext2;
    }
    public function get onNext3():ISignal {
      return _onNext3;
    }

  }

}

Content1Screen.as (feathers.screens.Content1Screen.as)
package feathers.screens {

  import starling.display.Quad;
  import starling.events.Touch;
  import starling.events.TouchEvent;
  import starling.events.TouchPhase;

  import feathers.controls.Screen;
  import org.osflash.signals.Signal;
  import org.osflash.signals.ISignal;


  public class Content1Screen extends Screen {
    // プロパティ
    private static var bw:uint = 600;
    private static var bh:uint = 800;
    private static var offset:uint = 35;
    protected var _onBack:Signal = new Signal(Content1Screen);

    // コンストラクタ
    public function Content1Screen() {
    }

    // メソッド
    override protected function initialize():void {
      var back:Sprite = new Sprite();
      addChild(back);
      back.y = offset;
      var paper:Quad = new Quad(bw, 740, 0x3399FF);
      back.addChild(paper);
      back.flatten();
      touchGroup = true;
      addEventListener(TouchEvent.TOUCH, touch);
    }
    override protected function draw():void {
    }
    private function touch(evt:TouchEvent):void {
      var touch:Touch = evt.getTouch(this, TouchPhase.BEGAN);
      if (touch) {
        _onBack.dispatch(this);
      }
    }
    public function get onBack():ISignal {
      return _onBack;
    }

  }

}

Content2Screen.as (feathers.screens.Content2Screen.as)
package feathers.screens {

  import starling.display.Quad;
  import starling.events.Touch;
  import starling.events.TouchEvent;
  import starling.events.TouchPhase;

  import feathers.controls.Screen;
  import org.osflash.signals.Signal;
  import org.osflash.signals.ISignal;


  public class Content2Screen extends Screen {
    // プロパティ
    private static var bw:uint = 600;
    private static var bh:uint = 800;
    private static var offset:uint = 35;
    protected var _onBack:Signal = new Signal(Content2Screen);

    // コンストラクタ
    public function Content2Screen() {
    }

    // メソッド
    override protected function initialize():void {
      var back:Sprite = new Sprite();
      addChild(back);
      back.y = offset;
      var paper:Quad = new Quad(bw, 740, 0x339900);
      back.addChild(paper);
      back.flatten();
      touchGroup = true;
      addEventListener(TouchEvent.TOUCH, touch);
    }
    override protected function draw():void {
    }
    private function touch(evt:TouchEvent):void {
      var touch:Touch = evt.getTouch(this, TouchPhase.BEGAN);
      if (touch) {
        _onBack.dispatch(this);
      }
    }
    public function get onBack():ISignal {
      return _onBack;
    }

  }

}

Content3Screen.as (feathers.screens.Content3Screen.as)
package feathers.screens {

  import starling.display.Quad;
  import starling.events.Touch;
  import starling.events.TouchEvent;
  import starling.events.TouchPhase;

  import feathers.controls.Screen;
  import org.osflash.signals.Signal;
  import org.osflash.signals.ISignal;


  public class Content3Screen extends Screen {
    // プロパティ
    private static var bw:uint = 600;
    private static var bh:uint = 800;
    private static var offset:uint = 35;
    protected var _onBack:Signal = new Signal(Content3Screen);

    // コンストラクタ
    public function Content3Screen() {
    }

    // メソッド
    override protected function initialize():void {
      var back:Sprite = new Sprite();
      addChild(back);
      back.y = offset;
      var paper:Quad = new Quad(bw, 740, 0x999900);
      back.addChild(paper);
      back.flatten();
      touchGroup = true;
      addEventListener(TouchEvent.TOUCH, touch);
    }
    override protected function draw():void {
    }
    private function touch(evt:TouchEvent):void {
      var touch:Touch = evt.getTouch(this, TouchPhase.BEGAN);
      if (touch) {
        _onBack.dispatch(this);
      }
    }
    public function get onBack():ISignal {
      return _onBack;
    }

  }

}

ScreenSlidingPushTransitionManager.as (feathers.motion.transitions.ScreenSlidingPushTransitionManager.as)
package feathers.motion.transitions {

  import flash.utils.getQualifiedClassName;
  import starling.animation.Transitions;
  import starling.animation.Tween;
  import starling.core.Starling;
  import starling.display.DisplayObject;

  import feathers.controls.IScreen;
  import feathers.controls.ScreenNavigator;


  public class ScreenSlidingPushTransitionManager {
    // プロパティ
    protected var navigator:ScreenNavigator;
    protected var _stack:Vector.<String> = new <String>[];
    protected var _deactiveTransition:Tween;
    protected var _activeTransition:Tween;
    protected var _savedOtherTarget:DisplayObject;
    protected var _savedCompleteHandler:Function;
    public var duration:Number = 0.25;
    public var delay:Number = 0.1;
    public var ease:Object = Transitions.EASE_OUT;
    public var skipNextTransition:Boolean = false;

    // コンストラクタ
    public function ScreenSlidingPushTransitionManager(navi:ScreenNavigator, quickStackScreenClass:Class = null, quickStackScreenID:String = null) {
      if (!navi) {
        throw new ArgumentError("ScreenNavigator cannot be null.");
      }
      navigator = navi;
      var quickStack:String;
      if (quickStackScreenClass) {
        quickStack = getQualifiedClassName(quickStackScreenClass);
      }
      if (quickStack && quickStackScreenID) {
        quickStack += "~" + quickStackScreenID;
      }
      if (quickStack) {
        _stack.push(quickStack);
      }
      navigator.transition = onTransition;
    }

    // メソッド
    public function clearStack():void {
      _stack.length = 0;
    }
    protected function onTransition(oldScreen:DisplayObject, newScreen:DisplayObject, onComplete:Function):void {
      if (_activeTransition) {
        _savedOtherTarget = null;
        Starling.juggler.remove(_deactiveTransition);
        Starling.juggler.remove(_activeTransition);
        _deactiveTransition = null;
        _activeTransition = null;
      }
      if (!oldScreen || !newScreen || skipNextTransition) {
        skipNextTransition = false;
        _savedCompleteHandler = null;
        if (newScreen) {
          newScreen.x = 0;
        }
        if (oldScreen) {
          oldScreen.x = 0;
        }
        if (onComplete != null) {
          onComplete();
        }
        return;
      }
      _savedCompleteHandler = onComplete;
      var newScreenClassAndID:String = getQualifiedClassName(newScreen);
      if (newScreen is IScreen) {
        newScreenClassAndID += "~" + IScreen(newScreen).screenID;
      }
      var stackIndex:int = _stack.indexOf(newScreenClassAndID);
      var oldTargetPosition:int;
      var newTargetPosition:int;
      var oldDuration:Number;
      var newDuration:Number;
      if (stackIndex < 0) {
        var oldScreenClassAndID:String = getQualifiedClassName(oldScreen);
        if (oldScreen is IScreen) {
          oldScreenClassAndID += "~" + IScreen(oldScreen).screenID;
        }
        _stack.push(oldScreenClassAndID);
        _savedOtherTarget = newScreen;
        oldScreen.x = 0;
        newScreen.x = navigator.width;
        oldTargetPosition = – navigator.width*0.25;
        newTargetPosition = 0;
        oldDuration = duration*0.75;
        newDuration = duration;
        //navigator.addChild(oldScreen);
        //navigator.addChild(newScreen);

      } else {
        _stack.length = stackIndex;
        _savedOtherTarget = oldScreen;
        oldScreen.x = 0;
        newScreen.x = – navigator.width*0.25;
        oldTargetPosition = navigator.width;
        newTargetPosition = 0;
        oldDuration = duration;
        newDuration = duration*0.75;
        navigator.addChild(newScreen);
        navigator.addChild(oldScreen);
      }
      _deactiveTransition = new Tween(oldScreen, oldDuration, ease);
      _deactiveTransition.animate("x", oldTargetPosition);
      _deactiveTransition.delay = delay;
      _activeTransition = new Tween(newScreen, newDuration, ease);
      _activeTransition.animate("x", newTargetPosition);
      _activeTransition.delay = delay;
      if (stackIndex < 0) {
        _activeTransition.onComplete = activeTransition_onComplete;        
      } else {
        _deactiveTransition.onComplete = deactiveTransition_onComplete;
      }
      Starling.juggler.add(_deactiveTransition);
      Starling.juggler.add(_activeTransition);
    }
    protected function deactiveTransition_onComplete():void {
      _deactiveTransition = null;
      _savedOtherTarget = null;
      if (_savedCompleteHandler != null) {
        _savedCompleteHandler();
      }
    }
    protected function activeTransition_onComplete():void {
      _activeTransition = null;
      _savedOtherTarget = null;
      if (_savedCompleteHandler != null) {
        _savedCompleteHandler();
      }
    }

  }

}