ダイナミックフォント見本

Akashic Engine で利用できる様々なダイナミックフォントのサンプルです。 スライダーを操作することで文字や背景の色や透過度を変更できます。 環境ごとの表示差異の確認にお使いください。

動かし方

ダウンロードした zip ファイルを解凍して以下のコマンドを実行してください。

npm install
akashic-sandbox .

ソースコード

"use strict";

/**
 * 2次元座標を表すオブジェクト
 *
 * @typedef {Object} Point
 * @property {number} x x座標
 * @property {number} y y座標
 */
/**
 * RGBで表現される色を表すオブジェクト
 *
 * @typedef {Object} Color
 * @property {number} r r値
 * @property {number} g g値
 * @property {number} b b値
 */
/**
 * スライダーの値が変更された際に呼ばれるコールバック関数
 *
 * @callback SliderCallback
 * @param {number} t 変更後の割合
 * @return {void}
 */

/** ランキングアプリのフォントファミリー */
var podiumFontFamilly = [
  "Avenir Next DemiBold",
  "AvenirNext-DemiBold",
  "Avenir Next",
  "Verdana",
  "ヒラギノ角ゴ Pro W6",
  "HiraKakuPro-W6",
  "meiryo",
  "sans-serif"
];

// フォントの描画に使用するフォント
var hintFont = new g.DynamicFont({
  game: g.game,
  fontFamily: g.FontFamily.Serif,
  size: 128
});

/** 描画するフォントの種類 */
var fontSample = [
  {
    name: "SansSerif",
    value: g.FontFamily.SansSerif,
    bold: false
  },
  {
    name: "SansSerif Bold",
    value: g.FontFamily.SansSerif,
    bold: true
  },
  {
    name: "Serif",
    value: g.FontFamily.Serif,
    bold: false
  },
  {
    name: "Serif Bold",
    value: g.FontFamily.Serif,
    bold: true
  },
  {
    name: "Monospace",
    value: g.FontFamily.Monospace,
    bold: false
  },
  {
    name: "Monospace Bold",
    value: g.FontFamily.Monospace,
    bold: true
  },
  {
    name: "ランキングアプリ",
    value: podiumFontFamilly,
    bold: false
  },
  {
    name: "ランキングアプリ Bold",
    value: podiumFontFamilly,
    bold: true
  }
];

/** 表示テキスト */
var text = "パラメータでテキストを変更できますABC123";
/** 文字色1 */
var textColor1 = "#000000";
/** 文字色2 */
var textColor2 = "#ffffff";
/** 背景色1 */
var backColor1 = "#ffffff";
/** 背景色2 */
var backColor2 = "#000000";
/** UIヒント色 */
var hintColor = "crimson";

function main() {
  // セッションパラメータを受け取るためのシーン
  var entry = new g.Scene({ game: g.game });
  entry.loaded.addOnce(function() {
    entry.message.add(function(msg) {
      // セッションパラメータの受け取りを確認
      if (msg.data && msg.data.type === "start" && msg.data.parameters) {
        var param = msg.data.parameters;

        // セッションパラメータから値を受け取る
        if (param.text) text = param.text;
        if (param.textColor1) textColor1 = param.textColor1;
        if (param.textColor2) textColor2 = param.textColor2;
        if (param.backColor1) backColor1 = param.backColor1;
        if (param.backColor2) backColor2 = param.backColor2;
        if (param.hintColor) hintColor = param.hintColor;

        // セッションパラメータの読み込みが完了したらメインシーンに遷移する
        var scene = new g.Scene({
          game: g.game,
          assetIds: ["transparent", "nottransparent"]
        });
        scene.loaded.add(function() {
          scene.append(createBackground(scene));
          scene.append(createFontSample(scene));
        });
        g.game.replaceScene(scene);
      }
    });
  });
  g.game.pushScene(entry);
}

/**
 * 背景を生成する
 *
 * @param {g.Scene} scene 描画対象のシーン
 * @return {g.E} 生成された背景
 */
function createBackground(scene) {
  var bg = new g.E({ scene: scene });

  var background = new g.FilledRect({
    scene: scene,
    width: g.game.width,
    height: g.game.height,
    cssColor: backColor1
  });
  bg.append(background);

  bg.append(
    new g.Label({
      scene: scene,
      font: hintFont,
      text: "背景",
      fontSize: 40,
      textColor: hintColor,
      x: 20,
      y: 20
    })
  );

  // 背景色変更スライダー
  var colorPer = new g.Label({
    scene: scene,
    font: hintFont,
    text: "0%",
    fontSize: 24,
    textColor: hintColor,
    x: 550,
    y: 10,
    anchorX: 1.0,
    anchorY: 0.0
  });
  bg.append(colorPer);
  bg.append(
    new g.FilledRect({
      scene: scene,
      x: 110,
      y: 10,
      width: 30,
      height: 30,
      cssColor: backColor1
    })
  );
  bg.append(
    new g.FilledRect({
      scene: scene,
      x: 460,
      y: 10,
      width: 30,
      height: 30,
      cssColor: backColor2
    })
  );
  bg.append(
    createSlider(scene, { x: 150, y: 10 }, function(t) {
      background.show();

      background.cssColor = color2tag(lerpColor(tag2color(backColor1), tag2color(backColor2), t));
      background.modified();

      colorPer.text = Math.floor(t * 100) + "%";
      colorPer.invalidate();
    })
  );

  // 背景透過度変更スライダー
  var transPer = new g.Label({
    scene: scene,
    font: hintFont,
    text: "100%",
    fontSize: 24,
    textColor: hintColor,
    x: 550,
    y: 40,
    anchorX: 1.0,
    anchorY: 0.0
  });
  bg.append(transPer);
  bg.append(
    new g.Sprite({
      scene: scene,
      src: scene.assets["nottransparent"],
      x: 110,
      y: 40
    })
  );
  bg.append(
    new g.Sprite({
      scene: scene,
      src: scene.assets["transparent"],
      x: 460,
      y: 40
    })
  );
  bg.append(
    createSlider(scene, { x: 150, y: 40 }, function(t) {
      background.opacity = 1 - t;
      background.modified();

      transPer.text = Math.floor((1 - t) * 100) + "%";
      transPer.invalidate();
    })
  );

  return bg;
}

/**
 * フォントサンプルを生成する
 *
 * @param {g.Scene} scene 描画対象のシーン
 * @return {g.E} 生成されたフォントサンプル
 */
function createFontSample(scene) {
  var samples = new g.E({ scene: scene });

  var seqY = 80;
  var sampleLabels = [];
  for (var i = 0; i < fontSample.length; ++i) {
    var sample = new g.E({ scene: scene });

    var fontLabel = new g.Label({
      scene: scene,
      font: hintFont,
      text: fontSample[i].name,
      fontSize: 24,
      textColor: hintColor,
      x: 20,
      y: seqY
    });

    sample.append(fontLabel);
    seqY += fontLabel.height - 5;

    var textFont = new g.DynamicFont({
      game: g.game,
      fontFamily: fontSample[i].value,
      size: 128,
      fontWeight: fontSample[i].bold ? g.FontWeight.Bold : g.FontWeight.Normal
    });

    var label = new g.Label({
      scene: scene,
      font: textFont,
      text: text,
      fontSize: 48,
      textColor: textColor1,
      x: 20,
      y: seqY
    });

    sample.append(label);
    seqY += label.height + 8;

    sampleLabels.push(label);

    samples.append(sample);
  }

  samples.append(
    new g.Label({
      scene: scene,
      font: hintFont,
      text: "文字",
      fontSize: 40,
      textColor: hintColor,
      x: 570,
      y: 20
    })
  );

  // 文字色変更スライダー

  var colorPer = new g.Label({
    scene: scene,
    font: hintFont,
    text: "0%",
    fontSize: 24,
    textColor: hintColor,
    x: 1100,
    y: 10,
    anchorX: 1.0,
    anchorY: 0.0
  });
  samples.append(colorPer);
  samples.append(
    new g.FilledRect({
      scene: scene,
      x: 660,
      y: 10,
      width: 30,
      height: 30,
      cssColor: textColor1
    })
  );
  samples.append(
    new g.FilledRect({
      scene: scene,
      x: 1010,
      y: 10,
      width: 30,
      height: 30,
      cssColor: textColor2
    })
  );
  samples.append(
    createSlider(scene, { x: 700, y: 10 }, function(t) {
      for (var i = 0; i < sampleLabels.length; ++i) {
        sampleLabels[i].textColor = color2tag(lerpColor(tag2color(textColor1), tag2color(textColor2), t));
        sampleLabels[i].invalidate();
      }

      colorPer.text = Math.floor(t * 100) + "%";
      colorPer.invalidate();
    })
  );

  // 文字透過度変更スライダー

  var transPer = new g.Label({
    scene: scene,
    font: hintFont,
    text: "100%",
    fontSize: 24,
    textColor: hintColor,
    x: 1100,
    y: 40,
    anchorX: 1.0,
    anchorY: 0.0
  });
  samples.append(transPer);
  samples.append(
    new g.Sprite({
      scene: scene,
      src: scene.assets["nottransparent"],
      x: 660,
      y: 40
    })
  );
  samples.append(
    new g.Sprite({
      scene: scene,
      src: scene.assets["transparent"],
      x: 1010,
      y: 40
    })
  );
  samples.append(
    createSlider(scene, { x: 700, y: 40 }, function(t) {
      for (var i = 0; i < sampleLabels.length; ++i) {
        sampleLabels[i].opacity = 1 - t;
        sampleLabels[i].invalidate();
      }

      transPer.text = Math.floor((1 - t) * 100) + "%";
      transPer.invalidate();
    })
  );

  return samples;
}

/**
 * スライダーを生成する
 *
 * @param {g.Scene} scene 描画対象のシーン
 * @param {Point} position 描画座標
 * @param {SliderCallback} callback スライダー変更時のコールバック関数
 * @return {g.E} 生成されたスライダー
 */
function createSlider(scene, position, callback) {
  var slider = new g.E({ scene: scene, x: position.x, y: position.y });

  var back_back = new g.FilledRect({
    scene: scene,
    width: 300,
    height: 30,
    cssColor: "black"
  });
  slider.append(back_back);
  var back_front = new g.FilledRect({
    scene: scene,
    x: 5,
    y: 5,
    width: 300 - 10,
    height: 30 - 10,
    cssColor: "white"
  });
  slider.append(back_front);
  var handle = new g.FilledRect({
    scene: scene,
    width: 10,
    height: 30,
    cssColor: hintColor,
    touchable: true
  });
  slider.append(handle);

  var handlePositionX = handle.x;
  handle.pointDown.add(function() {
    handlePositionX = handle.x;
  });
  handle.pointMove.add(function(e) {
    var mousePosX = handlePositionX + e.startDelta.x;
    var maxX = back_back.width - handle.width;

    handle.x = Math.max(0, Math.min(mousePosX, maxX));
    handle.modified();

    callback(handle.x / maxX);
  });

  return slider;
}

/**
 * 2つの色を線形補間する
 *
 * @param {Color} color1 基本色
 * @param {Color} color2 補間色
 * @param {number} t 補間係数
 * @return {Color} 2色を補間↓た色オブジェクト
 */
function lerpColor(color1, color2, t) {
  return {
    r: color1.r * (1 - t) + color2.r * t,
    g: color1.g * (1 - t) + color2.g * t,
    b: color1.b * (1 - t) + color2.b * t
  };
}

/**
 * 色オブジェクトからCSSカラータグを作成する
 *
 * @param {Color} color 色オブジェクト
 * @return {string} CSSカラータグ
 */
function color2tag(color) {
  return (
    "#" +
    ("00" + Math.floor(color.r).toString(16)).slice(-2) +
    ("00" + Math.floor(color.g).toString(16)).slice(-2) +
    ("00" + Math.floor(color.b).toString(16)).slice(-2)
  );
}

/**
 * CSSカラータグから色オブジェクトを作成する
 *
 * @param {string} color CSSカラータグ
 * @return {Color} 色オブジェクト
 */
function tag2color(color) {
  return {
    r: parseInt(color.slice(1, 3), 16),
    g: parseInt(color.slice(3, 5), 16),
    b: parseInt(color.slice(5, 7), 16)
  };
}

module.exports = main;

© DWANGO Co., Ltd.