いいかげんファイルも増えてきたので、リポジトリに入れることにしました。
ついでに、独自クラスとインクルードファイルの置き場も一緒にリポジトリに入れとりあえずc:\flash\classesに独自クラス、c:\flash\includeにMovieClipの拡張、c:\flash\proj\testにmain.asとtest.flaを置く構成にしました。
MovieClipの拡張はinclude\MovieClipの下に置くことにして、それ以外の拡張と分けられるようにし、Background,Panel,Ball,CursorクラスはPentagoというパッケージに入れました。

  • 構成は以下のとおり。
flash
├ proj
│└ test
│ ├ test.fla
│ └ main.as
├ include
│└ MovieClip
│ ├ drawOval.as
│ ├ drawRect.as
│ ├ fillOval.as
│ └ fillRect.as
├ classes
│└ info
│ └ uebuyahonpo
│  ├ MCMan.as
│  ├ Shape.as
│  ├ Pentago.as
│  └ Pentago
│   ├ Background.as
│   ├ Ball.as
│   ├ Cursor.as
│   └ Panel.as
  • test.flaで、ファイル→パブリッシュ設定→FlashタブのActionScriptのバージョン「設定」ボタン→クラスパスにc:\flash\classesを設定
  • main.asは、
main.as
----
// MovieClipの拡張
#include "c:\flash\include\MovieClip\fillOval.as"
#include "c:\flash\include\MovieClip\fillRect.as"

import info.uebuyahonpo.Pentago;

var game = new Pentago();
Key.addListener(game);
game.start();

findClips(_root,0);

//メインループ
this.onEnterFrame = function () {
}

function findClips(theClip,indentSpaces) {
    var indent = ' ';
    for ( var i=0; i<indentSpaces; i++) {
        indent += ' ';
    }
    for ( var property in theClip ) {
        if (typeof theClip[property] == "movieclip") {
            trace(indent + theClip[property]._name + '(' + property + ')');
            findClips(theClip[property],indentSpaces+4);
        }
    }
}

MovieClipの拡張のインクルードを先ほど移動した先に書き換えています。またロジックをPentagoクラスにまとめ、キーの取得も素直にキーイベントをPentagoクラスで受け取るように変更したのでだいぶすっきりしました。

  • では、Pentagoクラス
Pentago.as
----
import info.uebuyahonpo.MCMan;
import info.uebuyahonpo.Pentago.*;
class info.uebuyahonpo.Pentago {
    private var bg:Background;
    private var panels:Array;
    private var cursors:Array;
    private var turn:Number;

    function Pentago() {
        this.init_bg();                 // 背景
        this.init_panels(this.bg);      // パネル
        this.init_cursors(this.panels); // カーソル

        this.turn = 0;
    }

    public function start() {
        this.now_cursor().visible();
    }

    public function now_cursor():Cursor {
        return this.cursors[this.turn];
    }

    private function init_bg() {
        this.bg = new Background(MCMan.create_movie('bg'));
        this.bg.move(Stage.width/2, Stage.height/2);
        this.bg.draw();
    }

    private function init_panels(bg:Background) {
        this.panels = new Array(4);
        var delta = (Background.p2p+Panel.l)/2;
        for (var i=0;i<4;i++) {
            this.panels[i] = new Panel(MCMan.create_movie('p'));
            this.panels[i].move(
                bg.x() + (Math.floor(i/2)*2-1)*delta,
                bg.y() + (Math.floor(i%2)*2-1)*delta
            );
            this.panels[i].draw();
        }
    }

    private function init_cursors(panels:Array) {
        this.cursors = [
            new Cursor(MCMan.create_movie('cur'),0xff0000),
            new Cursor(MCMan.create_movie('cur'),0x0000ff)
        ];
        for (var i=0;i<2;i++) {
            this.cursors[i].set_panels(panels);
            this.cursors[i].move();
            this.cursors[i].draw();
            this.cursors[i].invisible();
        }
    }

    public function now_panel():Panel {
        return this.panels[this.now_cursor().get_panel_index()];
    }

    public function onKeyUp() {
        switch( Key.getCode() ){
        case 49: // '1'
            this.now_panel().left();
            break;
        case 50: // '2'
            this.now_cursor().up();
            break;
        case 51: // '3'
            this.now_panel().right();
            break;
        case 52: // '4'
            this.now_cursor().left();
            break;
        case 53: // '5'
        case Key.ENTER:
            if ( this.now_panel().put_ball(
                this.now_cursor().x_in_panel(),
                this.now_cursor().y_in_panel(),
                this.now_cursor().get_color(),
                this.now_cursor().x(),
                this.now_cursor().y()
            )){
                this.turn_end();
            }
            break;
        case 54: // '6'
            this.now_cursor().right();
            break;
        case 56: // '8'
            this.now_cursor().down();
            break;
        case Key.UP:
            this.now_cursor().upleft();
            break;
        case Key.DOWN:
            this.now_cursor().downright();
            break;
        }
    }

    public function turn_end() {
        this.now_cursor().invisible();
        this.turn = (this.turn+1)%2; /* ターン交代 */
        this.now_cursor().visible();
    }
}

2,4,6,8でカーソル移動して、5でそのカーソル色のボールを置きます。すでにボールがある場合は置けません。1,3でそのカーソルの置いているパネルを回転させます。(実験機能)上下決定キーでもカーソルが動くようにもしました。

  • BackgroundとBallはパッケージを追加しただけなので割愛して、Panelクラスをば、
Panel.as
----
import info.uebuyahonpo.Shape;
import info.uebuyahonpo.MCMan;
import info.uebuyahonpo.Pentago.Ball;
import info.uebuyahonpo.Pentago.Cursor;
class info.uebuyahonpo.Pentago.Panel extends Shape {
    public static var l:Number   = 76;
    public static var r:Number   =  1;
    public static var hr:Number  =  6;
    public static var h2h:Number = 10; /* 穴間距離 */
    private var hcolor:Number;
    private var balls:Array;
    private var rotind:Number;

    function Panel(mc:MovieClip,c:Number,hc:Number) {
        this.canvas = mc;
        if ( c == undefined ) {
            this.color  = 0xffffff;
        }
        else {
            this.color  = c;
        }
        if ( hc == undefined ) {
            this.hcolor = 0xcccccc;
        }
        else {
            this.hcolor = hc;
        }
        balls    = new Array(3);
        balls[0] = new Array(3);
        balls[1] = new Array(3);
        balls[2] = new Array(3);
        rotind   = 0;
    }

    public function draw() {
        this.canvas.fillRect(
            this.color, -(Panel.l/2), -(Panel.l/2),
            Panel.l, Panel.l, Panel.r
        );
        for (var i=0;i<3;i++) {
            for (var j=0;j<3;j++) {
                this.canvas.fillOval(
                    this.hcolor,
                    Panel.get_coordinate(i),
                    Panel.get_coordinate(j),
                    Panel.hr
                );
            }
        }
    }

    public static function get_coordinate(index:Number):Number {
        return (2*Panel.hr + Panel.h2h) * (index - 1);
    }

    public function get_ball_index(x:Number,y:Number):Object {
        var ret = new Object;
        switch( Math.floor(this.rotind/6) ) {
            case 0:
                ret.x = x;
                ret.y = y;
                break;
            case 1:
                ret.x = y;
                ret.y = 2-x;
                break;
            case 2:
                ret.x = 2-x;
                ret.y = 2-y;
                break;
            case 3:
                ret.x = 2-y;
                ret.y = x;
                break;
            default:
                return undefined;
        }
        return ret;
    }

    public function put_ball(i:Number,j:Number,c:Number,x:Number,y:Number):Boolean{
        var ind = this.get_ball_index(i,j);
        if ( balls[ind.x][ind.y] != undefined ) { //既にボールが置いてある
            return false;
        }
        balls[ind.x][ind.y] = new Ball(MCMan.create_movie('b'),c);
        balls[ind.x][ind.y].move(x,y);
        balls[ind.x][ind.y].draw();
        return true;
    }

    public function left() {
        this.rotind = (this.rotind + 23) % 24;
        this.rotation(this.rotind * 15);
    }

    public function right() {
        this.rotind = (this.rotind + 1) % 24;
        this.rotation(this.rotind * 15);
    }

    public function rotation(deg:Number) {
        this.canvas._rotation = deg;
        var rad = -deg/180*Math.PI; //回転方向が_rotationと逆?
        var cos = Math.cos(rad);
        var sin = Math.sin(rad);
        for (var i=0;i<3;i++) {
            for (var j=0;j<3;j++) {
                if ( balls[i][j] != undefined ) {
                    var orgx = Panel.get_coordinate(i);
                    var orgy = Panel.get_coordinate(j);
                    var newx =   orgx*cos + orgy*sin + this.x();
                    var newy = - orgx*sin + orgy*cos + this.y();
                    balls[i][j].move(newx,newy);
                }
            }
        }
    }
}

Ballの生成をmainからこいつに移してます。回転操作も追加しました。そういえば、MovieClip._rotationは時計回りを正にするけど、三角関数の引数とは逆になっているのかな?_rotation/180*Math.PIをそのまま使うと逆回転してしまった。変換行列が間違っているのだろうか?

  • そして、Cursorクラス
Cursor.as
----
import info.uebuyahonpo.Shape;
import info.uebuyahonpo.Pentago.Panel;
class info.uebuyahonpo.Pentago.Cursor extends Shape {
    public static var size:Number      = 12;
    public static var thickness:Number =  1;
    private var x_ind:Number;
    private var y_ind:Number;
    private var panels:Array;

    function Cursor(mc:MovieClip,c:Number) {
        this.canvas = mc;
        if ( c == undefined ) {
            this.color  = 0xff0000;
        }
        else {
            this.color  = c;
        }
        this.x_ind = 0;
        this.y_ind = 0;
    }

    public function draw() {
        this.canvas.lineStyle(Cursor.thickness,this.color);
        var s = Cursor.size/2;
        var l = Cursor.size/3;
        this.canvas.moveTo(-s  ,-s  );
        this.canvas.lineTo(-s  ,-s+l);
        this.canvas.moveTo(-s  , s-l);
        this.canvas.lineTo(-s  , s  );

        this.canvas.lineTo(-s+l, s  );
        this.canvas.moveTo( s-l, s  );
        this.canvas.lineTo( s  , s  );

        this.canvas.lineTo( s  , s-l);
        this.canvas.moveTo( s  ,-s+l);
        this.canvas.lineTo( s  ,-s  );

        this.canvas.lineTo( s-l,-s  );
        this.canvas.moveTo(-s+l,-s  );
        this.canvas.lineTo(-s  ,-s  );
    }

    public function up() {
        this.y_ind = (this.y_ind + 5) % 6;
        this.move();
    }

    public function down() {
        this.y_ind = (this.y_ind + 1) % 6;
        this.move();
    }

    public function right() {
        this.x_ind = (this.x_ind + 1) % 6;
        this.move();
    }

    public function left() {
        this.x_ind = (this.x_ind + 5) % 6;
        this.move();
    }

    public function upleft() {
        var y = this.y_ind;
        this.up();
        if ( y < this.y_ind ) {
            this.left();
        }
        this.move();
    }

    public function downright() {
        var y = this.y_ind;
        this.down();
        if ( y > this.y_ind ) {
            this.right();
        }
        this.move();
    }

    public function set_panels(pa:Array) {
        this.panels = pa;
    }

    public function get_panel_index() {
        return Math.floor(this.x_ind/3)*2 + Math.floor(this.y_ind/3);
    }

    public function x_in_panel() {
        return x_ind%3;
    }

    public function y_in_panel() {
        return y_ind%3;
    }

    public function move() {
        var pind = this.get_panel_index();
        var x    = this.panels[pind].x();
        var y    = this.panels[pind].y();
        var hx   = Panel.get_coordinate(this.x_in_panel());
        var hy   = Panel.get_coordinate(this.y_in_panel());
        super.move(x+hx,y+hy);
    }

    public function get_color():Number {
        return this.color;
    }
}

変更点は上下キーのサポートです。

次は、ペンタゴゲームの状態管理をしたり、判定ロジックを入れて遊べるようにしたり、タイトル画面やヘルプ画面などをいれてゲーム全体の管理を入れたりしたい。