kagamihogeの日記

kagamihogeの日記です。

yui-frameworks でライフゲームつくって思ったこととか

yui-frameworks でライフゲームつくったというかつくりなおしたというか。ソースの一部とコレ作ることで得られた知見などについてテキトーにメモ。

XXXView

あまり深く突っ込まれると困る実行画面の様子。mxml のソースは省略。

XXXAction

public class LifegameAction
{
    public var helper:LifegameHelper;
    
    public var logic:LifegameLogic;

    public function onApplicationStartHandler( event:FrameworkEvent ):void{
        trace("onApplicationStartHandler");
    }

    public function onAssembleCompleteHandler( event:FrameworkEvent ):void{
        trace("onAssembleCompleteHandler");
        helper.startUp();
        helper.init();
        logic.init(
            helper.width, helper.height, 
            helper.dotWidth, helper.dotHeight,
            helper.speedRate, helper.initRate,
            helper.drawLifegameCanvas);
    }
    
    public function lifegameCanvasMouseDownHandler(event:MouseEvent):void {
        var x:int = helper.mouseDownX;
        var y:int = helper.mouseDownY;
        logic.flipCell(x, y, helper.drawCell);
    }
    
    public function startButtonClickHandler(event:MouseEvent):void {
        logic.start();
        helper.clickStartButton();
    }
    
    public function stopButtonClickHandler(event:MouseEvent):void {
        logic.stop();
        helper.clickStopButton();
    }
    
    public function resetButtonClickHandler(event:MouseEvent):void {
        stopButtonClickHandler(event);
        helper.init();
        logic.init(
            helper.width, helper.height, 
            helper.dotWidth, helper.dotHeight,
            helper.speedRate, helper.initRate,
            helper.drawLifegameCanvas);
    }
    
    public function speedRateChangeHandler(event:SliderEvent):void {
        logic.changeSpeedRate(helper.speedRate);
    }
}

イベントもらって XXXLogic のロジック呼び出すか、XXXHelper にビュー周りのお世話お願いするか、のどっちかですね。XXXAction はこんな感じに、誰かに何かを任せる、って構図になるかと思います。

XXXLogic

public class LifegameLogic
{
    private var lifegame:Lifegame;
    
    private var gameSpeed:Timer;
    
    private var updateLifegame:Function;
    
    public function LifegameLogic()
    {
    }
    
    public function init(
        width:int, height:int, 
        dotWidth:int, dotHeight:int,
        speedRate:Number, initRate:int,
        updateLifegame:Function):void {
        this.lifegame = new Lifegame(width, height, initRate);
        this.gameSpeed = new Timer(speedRate);
        this.gameSpeed.addEventListener(TimerEvent.TIMER,delayHandler);
        this.updateLifegame = updateLifegame;
        
        updateLifegame.call(updateLifegame, lifegame);
    }

    private function delayHandler(evt:TimerEvent):void{
        lifegame.tick();
        updateLifegame.call(updateLifegame, lifegame);
    }
    
    public function start():void {
        gameSpeed.start();
    }
    
    public function stop():void {
        gameSpeed.stop();
    }
    
    public function changeSpeedRate(value:Number):void {
        gameSpeed.delay = value;
    }
    
    public function flipCell(x:int, y:int, updateLifegameCell:Function):void {
        if (lifegame.isContain(x, y)) {
            lifegame.flipCell(x, y);
            updateLifegameCell.call(updateLifegameCell, lifegame.getCell(x, y), x, y);
        }
    }
}

lifegame.tick() でライフゲームが次の状態に遷移、updateLifegame でビューに変更を通知して描画をやってもらう、ってのが大きな流れですかね。ライフゲームの核となるコードはめんどいんで載せてないけど、ロジックがここにくるんですよーってことは伝わるかな、と思います。

XXXHelper

public class LifegameHelper
{
    private const INCLEMENT_VALUE:int = 10;
    
    public var view:LifegameView;
    
    private var drawer:LifegameDrawer;
    
    public function startUp():void {
        var data:Array = new Array();
        var i:int = INCLEMENT_VALUE;
        for (i=INCLEMENT_VALUE; i<71; i+=INCLEMENT_VALUE) {
            data.push(i);
        }
        view.heightSelect.dataProvider = data;
        view.widthSelect.dataProvider = data;
        
        view.dotHeightSelect.dataProvider = [2, 3, 4, 5, 20];
        view.dotWidthSelect.dataProvider = [2, 3, 4, 5, 20];
        
        view.stopButton.enabled = false;
        view.dotHeightSelect.selectedIndex = 1;
        view.dotWidthSelect.selectedIndex = 1;
        view.heightSelect.selectedIndex = 2;
        view.widthSelect.selectedIndex = 2;
    }
    
    public function init():void { 
        view.lifegameCanvas.graphics.clear();
        drawer = new LifegameDrawer(
            view.lifegameCanvas.graphics, width, height, dotWidth, dotHeight);
        drawer.drawDrid();
    }
    
    public function clickStartButton():void {
        view.startButton.enabled = false;
        view.stopButton.enabled = true;
    }
    
    public function clickStopButton():void {
        view.startButton.enabled = true;
        view.stopButton.enabled = false;
    }
    
    public function drawLifegameCanvas(lifegame:Lifegame):void {
        view.lifegameCanvas.graphics.clear();
        drawer.drawDrid();
        lifegame.traverse(drawCell);
    }
    
    public function drawCell(cell:Cell, x:int, y:int):void {
        drawer.drawCell(cell, x, y);
    }
    
    public function get mouseDownX():int {
        return drawer.convertLocalXToCoordinate(view.lifegameCanvas.contentMouseX);
    }
    
    public function get mouseDownY():int {
        return drawer.convertLocalYToCoordinate(view.lifegameCanvas.contentMouseY);
    }

    public function get width():int {
        return view.widthSelect.selectedItem as int;
    }
    
    public function get height():int {
        return view.heightSelect.selectedItem as int;
    }

    public function get dotWidth():int {
        return view.dotWidthSelect.selectedItem as int;
    }
    
    public function get dotHeight():int {
        return view.dotHeightSelect.selectedItem as int;
    }
    
    public function get speedRate():Number {
        return view.speedRate.value;
    }
    
    public function get initRate():int {
        return view.initRate.value as int;
    }
}

見た目のお世話です。Canvas に対する描画のコードはココには載せないけど、まぁ雰囲気は伝わるかなーと。

XXXAction 側にどーやってデータ渡すのかは迷ったけど、とりあえず get ステートメントにしときました。実際にはデータ変換とか validation が絡むからもっとややこしくなりそう。