2009年11月28日

Google BloggerにFC2拍手を組み込む方法

新Bloggerでの拍手の追加方法が見つからなかったので、書いてみます。

手順を説明します。
  1. FC2拍手に登録します。
  2. Blogger のカスタマイズから
    [レイアウト] -> [HTMLの編集]を開きます。
    [ウィジェットのテンプレートを展開]にチェックを入れます。
  3. <div class="post-footer">
    の前後あたりが良いと思いますが
    <!-- FC2拍手ここから -->
    <a expr:href='"http://clap.fc2.com/post/~ユーザ名~/
    ?url=" + data:post.url 
    + "&amp;title=" + data:blog.title 
    + ":" + data:post.title' 
    target='_blank' title='拍手する by FC2'>
    <img alt='拍手する' expr:src=
    '"http://clap.fc2.com/images/button/white/~ユーザ名~
    ?url=" + data:post.url' style='border:none;'/>
    </a>
    <!-- FC2拍手ここまで -->
    を挿入します。
    ~ユーザ名~の部分はFC2拍手のユーザ名を入れます。
    whiteの部分はgreenなどと変えられます。
  4. これを保存してブログの表示を確認してできあがりです。
参考:
何個目だブログ(名称未設定24のコピー16) BloggerにFC2拍手を組み込む
BloggerでFC2拍手を使う
クリボウの Blogger 入門: Blogger に「翻訳」リンク
レイアウト データ タグ - Blogger ヘルプ

何個目だブログさんとコードが異なっているのは、
新Bloggerではデータタグ<$~~$>が使えないためです。

ちなみに↓の拍手はCSSでfloat: right;を指定してます。

2009年11月24日

JavaAppletゲーム

戦術シミュレーションゲーム風JavaAppletを更新しました。
文化祭があったのでとりあえず多少見栄え良くしようと手を加えてみましたが
大して変わりませんね。
展示もしましたがプレイしてくれる人は一人もいませんでした。

敵のタイプを2種類配置してみました。
移動+攻撃範囲に入ると移動して攻撃しようとするのと、
攻撃されるか攻撃範囲に入るまでアクティブにならないタイプです。

ゲームデザインはどこから手をつければいいんでしょうかね。
シナリオか、世界観か、キャラクターか・・・
文才およびシナリオ構成力が絶望的なので
できればストーリーの比重が極小になる方向でなんとかしたいですが・・・。

2009年11月21日

女の子と鎌


他所で指摘もらいました。胴長いらしいです。
未だに理解できてませんが、1ヶ月もすれば納得できるのでしょう・・・。

pixivに上げましたが初動閲覧数2でした。
30分経った現在でも3です。
サムネが表示されない障害のせいか、
かつてないほど下手クソということですね。
どうせ大した評価は貰えなかったと思って諦めます。

p.s.
と思ったら評価してくれる人やブクマしてくれる人がいて涙が出そうでした。
お気にしてくれる人もいて感激でした。

2009年11月8日

透過BufferedImage作成

Javaの透過BufferedImageによる描画について書いてみようと思います。
SRPGの戦闘システム風JavaAppletの描画で用いました。

今までは特に工夫せずに毎回一から線とか四角で描画していましたが、
毎回同じことをするのは無駄だと思ったので、少しいじりました。
まずメニューとかマップとかのオブジェクトごとに
java.awt.image.BufferedImageインスタンスを持っておいて、
最初か変更のあったときだけそれに描画しておいて、
そのBufferedImageを毎回スクリーンに描画するって寸法です。
ペイントソフトでいうレイヤーみたいなもんですね。

で、まぁ、このBufferedImageが不透明度100%で初期化されるので、
これを透明な状態で初期化しなければなりません。
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2D = img.createGraphics();
g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
Rectangle2D.Double rect = new Rectangle2D.Double(0,0,img.getHeight(),img.getHeight());
g2D.fill(rect);
g2D.setPaintMode();
コードはこんな感じになります。width, heightには幅と高さを入れてください。
http://www.ibm.com/developerworks/jp/java/library/j-begjava-index/#c
こちらを参考にしました。といっても最後にsetPaintMode()しただけですが。
こうしてGraphicsオブジェクトを初期化したあとは普通に描画していくだけです。

ちなみに
http://www.ne.jp/asahi/hishidama/home/tech/java/image.html#画像を加工する
こちらではBufferedImage.setRGB()で透明度を指定しているようですが、
気が向いたら処理時間を比べてみようと思います。

2009年11月3日

ヘックスなシミュレーションゲーム

以前公開したSRPGの戦闘システム風JavaAppletを更新しました。
描画周りと敵AIに手を加えました。

ヘックスのアルゴリズムの実装について書いてみようと思います。
結構苦労したので・・・。

ヘックスの座標系:
特に考えずに決めてしまったので、ちょっと後悔してます。
基本的には
□ □ □ □
 □ □ □ □
□ □ □ □
 □ □ □ □
こんな感じのギザギザなx座標を使ってます。
カーソルの移動とかはこの座標系がいいですね。

距離を考えるときには
□ □ □ □
 □ □ □
□ □ □ □
 □ □ □
こんなのですね。
縦方向基準な座標系とでもいうのでしょうか。
距離についての詳細は下記。

□ □ □ □
 □ □ □ □
  □ □ □ □
   □ □ □ □
多分最も一般的なのがこれだと思うんですが、
結局使わずに終わってしまいました。
一応言い訳しておくと、
座標系の実装は隠すようになってるから何でもいいんです。
今更変えるのは面倒なんです・・・。意味ないし・・・。

2ヘックス間の距離:
http://blogs.wankuma.com/izmktr/archive/2009/06/26/176657.aspx

こちらのブログを参考にしました。天才だと思います。
見つけるのに苦労しました。検索結果のもっと上のほうに出てきてもいいのに・・・。

射線:
障害物の向こう側に攻撃が届かないシステムについて。
点と線分の距離から、
障害物のあるヘックスの中心からの距離が一定以下ならそいつに阻まれます。
http://www.deqnotes.net/acmicpc/2d_geometry/lines
こちらを参考に点と線分の距離を求めてます。

以下ソース引用
private static int obstacleHeight = 4; // 障害物の高さ
private static int unitHeight = 2; // ユニットの高さ
/* 
 * 攻撃者の座標はcurrentとして設定済。
 * 目標の座標targetと射程Range(水平方向と高さ方向の射程。min, maxは水平方向の射程)から、
 * 攻撃可能か否かbooleanを返す。
 */
public boolean raySearch(Coord<Integer> target, Range range) {
 if(!searchFloat(target.x, target.y, range)) // range内にtargetがいなければ偽
  return false;
 
 int hexSize = 128; // 理論上は1でもいいが、大きい方が誤差が出にくい?
 double r = hexSize/2 * 1.732/2 * 1.2; // hexsizeを覆う円の半径。これに射線が触れるか判定する。
 
 Coord<Double> currentC = getCoordByHex(current.x, current.y, hexSize); // ヘックス座標から実座標を取得。
 Coord<Double> targetC = getCoordByHex(target.x, target.y, hexSize);
 
 double thetaL = Math.atan2(targetC.y - currentC.y, targetC.x - currentC.x); // 射線の角度
 
 for(int y = 0; y < map.length; y++)
  for(int x = 0; x < map[y].length; x++) { // マップ上のヘックス全てについて、
   if((target.x == x && target.y == y)
     || (current.x == x && current.y == y)
     || distanse(current.x, current.y, x, y) > range.max) // 自分か目標か射程外なら障害物になり得ない
    continue;
   
   Coord<Double> barC = getCoordByHex(x, y, hexSize); // 今チェックするヘックスの実座標
   
   int offsetH = 0;
   if(map[y][x] <= OBSTACLE) // 障害物なら
    offsetH = obstacleHeight;
   
   int difH = height[target.y][target.x] - height[current.y][current.x]; // 自分と目標の高さの差
   int h = height[y][x]  + offsetH - unitHeight; // ユニットの高さの分、当たりやすくなる
   if((barC.x - currentC.x) * difH / (targetC.x - currentC.x) + height[current.y][current.x] > h
     || (barC.y - currentC.y) * difH / (targetC.y - currentC.y) + height[current.y][current.x] > h) // このヘックスが、xかy方向に高さで邪魔にならなければ、次。
   continue;
   
   // 以降、図形の問題をごにょごにょ
   double theta = Math.atan2(barC.y - currentC.y, barC.x - currentC.x) - thetaL;
   
   if(Math.cos(theta) < 0 || Math.cos(thetaL - Math.atan2(targetC.y - barC.y, targetC.x - barC.x)) < 0)
    continue;
   
   if(Math.hypot(barC.x - currentC.x, barC.y - currentC.y) * Math.abs(Math.sin(theta)) < r)
    return false;
  }
 return true;
}

汚いコードだと思いますがすいません。
この関数は引数のtarget座標に攻撃が届くか否かを返します。
Coordは座標(x,y)を持つクラスです。

current:攻撃者の座標としてすでにセットされてます。
hexSize:ただの係数なので1でも何でもいいんですが、
計算する上である程度の大きさがあったほうがいいです。
後で位置関係をatan2に突っ込むのですが、そこがうまくいかなくなります。
r:ヘックスを覆う円の半径です。√3/2が六角形の半径です。
大きめにしないと隣り合った障害物の隙間を通り抜けてしまいます。
getCoordByHex():はヘックス座標系から実際の画面上(?)の座標を返します。

まず、距離が射程range外もしくはマップ外であればはじきます。
でもって、マップのすべてのヘックスについて
障害物でないか、射程外か、自分自身かターゲットでなければ、
上で引用した点と線分の距離を用いて判定しています。

後半になるほど面倒になって説明が雑になってますが許してください・・・。