プログラマのためのFlash遊び方

第3回お絵かきしながら学ぶ ActionScript 3.0(後編)

前編では基本的な図形描画の方法を習得しました。後編では応用例としてWeb 2.0風バッジを描画します。

超クールなWeb 2.0風バッジを描く

次のようなバッジをActionScript 3.0のソースコードだけで描画します。

今回描く、Web2.0風バッジ

ちょっと長いですが、ソースコードはこうなります。

package {
  import flash.display.Sprite;                    
  import flash.geom.Matrix;                       
  import flash.geom.Point;                        (1)
  import flash.filters.DropShadowFilter;          
  import flash.text.TextField;                    

  public class Web2Badge extends Sprite {         
    // インスタンス変数を宣言
    private const LINE_COLOR:uint = 0xffffff;     
    private const BODY_COLOR1:uint = 0xffff66;    
    private const BODY_COLOR2:uint = 0xffcc00;    
    private const CORNER:int = 12;                (2)
    private const RADIUS1:Number = 26;            
    private const RADIUS2:Number = 22;            
    private const TEXT:String = "BETA";           

    // コンストラクタ
    public function Web2Badge() {
      // バッジの小さいほうの直径
      var d:Number = Math.min(RADIUS1, RADIUS2) * 2;

      // Spriteを作成
      var s:Sprite = new Sprite();
      s.graphics.lineStyle(1, LINE_COLOR);

      // グラデーションの範囲と方向をMatrixオブジェクトに格納
      // (d×dの範囲を-45°の方向に)
      var matrix:Matrix = new Matrix();
      matrix.createGradientBox(d, d, -Math.PI / 4);

      // グラデーションの情報を指定
      s.graphics.beginGradientFill(
        "linear",                    // 線状のグラデーション
        [BODY_COLOR1, BODY_COLOR2],  // 色
        [1, 1],                      // 透明度
        [0, 255],                    // 色の位置
        matrix);                     // 範囲と角度

      // 星型の描画
      var angle:Number = 2 * Math.PI / CORNER;
      var p1:Point, p2:Point;
      s.graphics.moveTo(RADIUS1, 0);
      for(var i:int = 0; i < CORNER; i++) {
        p1 = Point.polar(RADIUS2, angle * (i + 0.5));
        p2 = Point.polar(RADIUS1, angle * (i + 1));
        s.graphics.lineTo(p1.x, p1.y);
        s.graphics.lineTo(p2.x, p2.y);
      }
      s.graphics.endFill();

      // 影をつける
      s.filters = [new DropShadowFilter(4, 45, 0, 0.5)];

      // 中に表示するテキストを作成
      var size:int = d / TEXT.length;
      var text:TextField = new TextField();
      text.htmlText = '<font size="' + size + '" color="#ffffff&quot>'
        + '<b>' + TEXT + '</font></b>';
      text.x = -text.textWidth / 2;
      text.y = -text.textHeight / 2;
      text.filters = [new DropShadowFilter(1, 45, 0, 0.8)];
      s.addChild(text);

      // (100, 100) に表示
      s.x = s.y = 100;
      addChild(s);
    }
  }
}

ソースコードをWeb2Badge.asというファイル名で保存して、mxmlcでコンパイルしましょう。

mxmlc Web2Badge.as

Web2Badge.swfが出力されます。このファイルを表示すると、最初にお見せしたバッジが表示されます。

ソースコードを見ていこう

では、ソースコードを順番に見ていきましょう。

冒頭(1)のimport文は利用するクラスを列挙しています。前回はimportするクラスはSpriteだけでしたが、今回は一気に増えましたね。それぞれのクラスの意味は順次説明していきます。

(2)では、クラスで使用するパラメータをインスタンス変数を宣言しています。privateなインスタンス変数ですので、クラスの中の全てのメソッドから参照できる変数となります。

インスタンス変数は次のようにして宣言します。

インスタンス変数の宣言

属性にはprivate・public・internal・protectedなどのアクセス制御属性を指定できます。static属性を追加で指定すると、インスタンスではなく、クラスに所属する変数(クラス変数)となります。

インスタンス変数の宣言には、varもしくはconstキーワードを利用します。varを利用すると、実行中に何度でも値を書き換えられます。constで宣言すると、あとで値を変更できなくなります。定数と言ってもよいでしょう。ここでは、動的に値を変更する必要がないので、constで宣言しています。

バッジ本体の描画

グラデーションを定義する

まずはバッジの背景を描画するところを見ていきましょう。背景にはうっすらとグラデーションがかかっています。

前回ご説明したbeginFill()メソッドは単色でしか塗れませんでしたが、beginGradientFill()メソッドを使えば複雑なグラデーションで描画できます。

  // グラデーションの範囲と方向を Matrix オブジェクトに格納
  // (d×dの範囲を-45°の方向に)
  var matrix:Matrix = new Matrix();
  matrix.createGradientBox(d, d, -Math.PI / 4);

  // グラデーションの情報を指定
  s.graphics.beginGradientFill(
      "linear",                    // 線状のグラデーション
      [BODY_COLOR1, BODY_COLOR2],  // 色
      [1, 1],                      // 透明度
      [0, 255],                    // 色の位置
      matrix);                     // 範囲と角度

最初に、createGradientFill()メソッドに渡すためのMatrixオブジェクトを作成しています。createGradientBox()メソッドを利用して、グラデーションの範囲と角度を設定しています。変数dはバッジの直径を表します。

次に、beginGradientFill()メソッドにグラデーションのパラメータを与えています。引数の数が多くて複雑ですが、コメントを見れば意味は把握できるでしょう。BODY_COLOR1とBODY_COLOR2はソースコードの先頭で定義しているグラデーションの開始色と終了色です。

星型を描画する

星を描画するところのソースを見てみましょう。

  // 星型の描画
  var angle:Number = 2 * Math.PI / CORNER;
  var p1:Point, p2:Point;
  s.graphics.moveTo(RADIUS1, 0);
  for(var i:int = 0; i < CORNER; i++) {
    p1 = Point.polar(RADIUS2, angle * (i + 0.5));
    p2 = Point.polar(RADIUS1, angle * (i + 1));
    s.graphics.lineTo(p1.x, p1.y);
    s.graphics.lineTo(p2.x, p2.y);
  }
  s.graphics.endFill();

for文を利用していますね。CORNERの回数だけループを回しています。

点の座標計算にはPointクラスのstaticなメソッドpolar()を利用しています。

polar( 原点からの距離:Number, ラジアンで表した角度:Number ):Point

polar()メソッドは、原点からの距離と角度を渡すと、その座標のX座標、Y座標が格納されたPointオブジェクトを返します。

2つの円(半径RADIUS1と半径RADIUS2)の円周上の点を、順番に結んでいるのがお分かりいただけるでしょうか。

2つの円(半径RADIUS1と半径RADIUS2)の円周上の点を、順番に結んでいる

影をつけるには

バッジにはうっすらと影がついています。影をつけるにはDropShadowFilterクラスを用います。

  // 影をつける
  s.filters = [new DropShadowFilter(4, 45, 0, 0.5)];

DropShadowFilter のコンストラクタに渡しているパラメータは、それぞれ、距離・角度・色・透明度です。

フィルタを指定するには、Spriteクラスの filtersプロパティに配列の形で指定します。上のコードを丁寧に書くと、次のようになります。

  // フィルタを作成
  var filter:DropShadowFilter= new DropShadowFilter(4, 45, 0, 0.5);
  // 配列を作成
  var array:Array = [];
  // 配列にfilterを追加
  array.push(filter);
  // s のfiltersプロパティにarrayを指定
  s.filters = array;

配列で指定しているところからも分かる通り、複数のフィルタを同時に指定できます。利用できるフィルタの一覧は、Flex3リファレンスガイドのflash.filtersパッケージをご覧ください。

テキストを配置

文字列の表示はTextFieldクラスを利用します。

  var text:TextField = new TextField();
  var size:int = d / TEXT.length;                 --(1)
  text.htmlText = '<font size="' + size + '" color='#ffffff'>'
    + '<b>' + TEXT + '</font></b>';               --(2)
  text.x = -text.textWidth / 2;                   
  text.y = -text.textHeight / 2;                  (3)
  text.filters = [new DropShadowFilter(1, 45, 0, 0.8)];
  s.addChild(text);

座標計算を行っているところが少し複雑でしょうか。

  • (1) バッジの直径に合わせて、フォントサイズを決定している。
  • (2) TextFieldクラスのhtmlTextプロパティを利用して、HTMLの形式で文字サイズと色を設定する。
  • (3) (2)で作成した文字列のサイズを取得して、原点を中心に文字が表示されるように位置を調整する。

ちょっとした修正でいろんなバッジを

以上でソースコードの読解は完了です。ここからは、サンプルのソースコードを改造して遊んでみましょう。

Web2Badgeクラスの先頭では、描画に利用するパラメータをまとめて定義しています。これらのパラメータを修正して再コンパイルすれば、いろいろなバリエーションを試すことができます。

例えば、次のように修正してみましょう。

    private const LINE_COLOR:uint = 0x7FCE3D;
    private const BODY_COLOR1:uint = 0xCDEEB7;
    private const BODY_COLOR2:uint = 0x74CA31;
    private const CORNER:int = 8;
    private const RADIUS1:Number = 26;
    private const RADIUS2:Number = 18;
    private const TEXT:String = "SALE";

角の数が少なく、2つの半径の差が大きいため、大胆な感じになりました。

角の数が少なくなった

曲線で結ぶ

今度は描画処理も修正してみましょう。lineTo()で直線を引いている箇所を、curveTo()に変更してみます。curveTo()はベジェ曲線を描くメソッドでしたね。

  s.graphics.moveTo(RADIUS1, 0);
  for(var i:int = 0; i < CORNER; i++) {
    p1 = Point.polar(RADIUS2, angle * (i + 0.5));
    p2 = Point.polar(RADIUS1, angle * (i + 1));
    s.graphics.curveTo(p1.x, p1.y, p2.x, p2.y);
  }
  s.graphics.endFill();

RADIUS1とRADIUS2のどちらが大きいかによって、雲のようなバッジと爆発したバッジが切り替わります。

RADIUS1とRADIUS2の大小によって、バッジのイメージが替わる
左の例:
    private const LINE_COLOR:uint = 0xAEAFB1;
    private const BODY_COLOR1:uint = 0xAEAFB1;
    private const BODY_COLOR2:uint = 0x2B2B2B;
    private const CORNER:int = 10;
    private const RADIUS1:Number = 20;
    private const RADIUS2:Number = 26;
    private const TEXT:String = "BETA";
右の例:
    private const LINE_COLOR:uint = 0xffffff;
    private const BODY_COLOR1:uint = 0xFFDAED;
    private const BODY_COLOR2:uint = 0xFD037F;
    private const CORNER:int = 16;
    private const RADIUS1:Number = 26;
    private const RADIUS2:Number = 18;
    private const TEXT:String = "SALE";

パラメータを修正するだけで、がらっと見た目も変わるところが面白いですね。

まとめ

Flashはもともとデザイナーが使うものだっただけに、描画関連のクラスが充実いています。プログラムでの描画は面倒なことも多いですが、あとからのパラメータ調整を柔軟に行えるというメリットもあります。

ActionScriptを使っての描画に興味を持った方は、私のブログの記事AS3でiPhone風ボタンを描画AS3でRSSアイコンを描画なども併せて読んでみると面白いかもしれません。

次回は、マウスに反応するようなインタラクティブなFlashを作ってみましょう。

おすすめ記事

記事・ニュース一覧