Google Chrome または Safari を使用される事を強くお薦めしますw
他のブラウザでは Javascript の処理が重いです(汗)


2010/08/31

ロールオーバーいろいろ

ちょっとはお役に立ちそうな話もしてみますw

ロールオーバー、すなわちマウスポインターが上に来ると画像が変わるって奴は、誰もがやりたがり(そうか?)あちこちにその手法が書かれてたりするのだけれど、メジャーどころをまとめるとこんな感じ。

【その1:画像再読込】
最も簡単な方法。
マウスが上に乗ったときのコールバック onmouseover と上から外れたときのコールバック onmouseout でそれぞれ違う URL を src 属性につけてやります。

<div>
  <img src="hoge_out.gif" id="rollover">
</div>

みたいなのに対し、こんなスクリプトを用意します。

var img = document.getElementById('rollover');

img.onmouseover = function() {
    img.src = 'hoge_over.gif';
}

img.onmouseout = function() {
    img.src = 'hoge_out.gif';
}

これをやってみた結果がこちら:



こいつの欠点はマウスを乗せた時の画像 hoge_over.gif が、実際にマウスを乗せるまで読み込まれないこと。
従って、マウスを乗せた最初の1回は画像が出るまで時間がかかってしまいます。
(2回目以降はブラウザにキャッシュされてるので早い)

そこであらかじめマウスを乗せたときの画像も読み込んで置くのが望ましいです。いわゆる「先読み」ですね。
最も簡単なのは HTML 側で 幅も高さも1ピクセルの極小画像として表示しておくことです。
つまりこんな感じ。

<div>
  <img src="hoge_out.gif" id="rollover">
  <img src="hoge_over.gif" width=1 height=1>
</div>

実際にはページの一番下とか目立たない場所に表示させておきます。

やだ、こんなのダサい、と思うなら、javascript で先読みさせておくというのもできます。

var imgDummy = new Image;
imgDummy.src = 'hoge_over.gif';

これだとどこにも表示されませんが、読み込みだけは行われてます。

これらの先読み方法は、ブラウザが画像をキャッシュするということを利用してます。実際に先読みした画像はどこにも使用されないんだけど、後で同じ URL を指定されることでブラウザがそのキャッシュを使ってくれるのです。

そうじゃなくて、読み込ませた画像はそのまま使いたいというなんとなく貧乏性な方(俺や!)には、次の方法を。

【その2:片方を非表示にする】
2つの画像をぴったり重ねて置いておいて、片方を非表示にします。
ぴったり重ねるために position: absolute を指定する必要があります。
また、非表示の画像に対してイベントは発生しないので、画像を div の中に配置して、その div に対するイベントを定義することになります。

<div id="rollover">
    <img id="img_over" src="hoge_over.gif">
    <img id="img_out"  src="hoge_out.gif">
</div>

css でいろいろ定義

#rollover {
    position:relative;
    width:   50px;
}

#img_over {
    position:absolute;
    top:     0px;
    left:    0px;
    display: none;
}

#img_out {
    position:absolute;
    top:     0px;
    left:    0px;
}

で、javascript はこんな風。

var div      = document.getElementById('rollover');
var img_out  = document.getElementById('img_out');
var img_over = document.getElementById('img_over');

div.onmouseover = function() {
    img_out.style.display = 'none';
    img_over.style.display = '';
}

div.onmouseout = function() {
    img_out.style.display = '';
    img_over.style.display = 'none';
}

やってみた結果がこちら:






お気付きだと思いますが、display 属性を変更する代わりに z-index を使って、片方の画像をもう片方より上に表示するというのでも構いません。

管理する上で画像ファイルがいくつもあるのはイヤん、という方もいると思います。
ボタン系の画像をまとめてどかんと1枚にできれば読み込みも1回だし管理もしやすいかもしれません。
それが第3の方法。

【その3:背景画像にする】
これはちょっとしたコロンブスの卵です。略してコロたま。略さんでもいいけど。
まず div を用意します。

<div id="rollover"></div>

css で大きさと背景画像を指定します。
#rollover {
    position:  relative;
    width:     50px;
    height:    50px;
    background:url('hoge.gif');
}

ここで背景画像 hoge.gif は通常の画像とロールオーバー時の画像を並べた1枚の画像として作っておきます。
並べる方向は縦でも横でもいいけど、ここでは横にならべてみました。
こんな画像になります。


これでどうするかというと、ロールオーバー時に背景の表示位置を横にずらしてやるわけです。
つまりイベント発生時に background-position を書き換えてやるのですな。
var div = document.getElementById('rollover');

div.onmouseover = function() {
    div.style.backgroundPosition = '-50px 0px';
}

div.onmouseout = function() {
    div.style.backgroundPosition = '0px 0px';
}
指定するのは画像の左上位置なので、右側の絵を表示するためにマイナスの値を設定しています(背景全体を左にずらしてます)。
やってみたのがこちら:

↑背景なので右クリックしても「画像を保存」のメニューがでません。

ボタンがいっぱいあるなら、全部並べた1枚の画像にして、どの div もそれを背景とし、状況に応じて background-position を変更してやれば良いです。

今製作中のゲームでもこのテクニックを使ってます。
キャラクターが歩くときに、1コマずつ画像ファイルを用意するのが面倒なんで、こんな風に上下左右4方向でそれぞれの方向に3コマ定義した画像ファイルを div の背景にしてます。

div の位置を変更しながら、背景の表示位置も変えてやることでとことこ歩きます。こんな感じ。


他にもいろいろ応用ができそうです。例えば数字を縦にずらずらと書いた背景画像を少しずつずらしていくとスロットマシンになりますね。
もう十分記事が長くなったので書きませんけどw
(2011/01/07追記:この手法には CSSスプライト って名前が付いてたんですね。なるほど。)

2010/08/28

パクパク

この blog は HTML で記述することができる。
まあそんなとこは多いと思うけど。

ってことは javascript 書けるんじゃね? と思ってやってみた。








モンティ・パイソンやなw

継承

プロトタイプチェーンを継承と見立てて派生クラスらしきものを定義する、ということができると分かったので Dragon's eye を作り上げることができたのだが、今になってよく考えたらやり方間違ってたwww

Dragon's eye でやってた継承を作る便利関数はこんなの。

function inherit( funcSubClass, funcSuperClass ) {
    funcSubClass.prototype = new funcSuperClass;
}


まあ! とってもシンプルw
このシンプルさが好きだったってのもあるけど、これっていろいろダメ(^^;;;


で、ちゃんと調べて考えて、こんくらい書かないとダメだと分かった。

function inherit( funcSubClass, funcSuperClass ) {
  var funcTemp = new Function();
  funcTemp.prototype = funcSuperClass.prototype;

  funcSubClass.prototype  = new funcTemp;
    funcSubClass.prototype.constructor  = funcSubClass;

  funcSubClass.prototype.base = function () {
  var funcOrigBase = this.base;
  this.base = funcSuperClass.prototype.base || null;
  funcSuperClass.apply( this, arguments );
  this.base = funcOrigBase;

  if( this.constructor == funcSubClass )
  delete this.base;
  }
}


これを使って、継承を書くとこんな感じ

function BaseHoge() {
        :
        :
}

function DerivedHoge() {
    this.base();
        :
        :
}
inherit( DerivedHoge, BaseHoge );

これなら Dragon's eye での1世代しか継承できないなんちゃって継承ではなく、何世代継承してもちゃんと動く継承が作れる。

にしても。

派生クラスのコンストラクタで親のコンストラクタを明示的に呼び出さないといけない(上のコードで this.base(); の部分)がダサくてヤダ。

暗黙に呼び出されるようにするにはどうしたらええのん?
いろいろ考えてるけどまだ解は見つからずorz


2010/08/26

クラス図

制作を始めてます。
いつ完成するかはわかりません。

とりあえず書きかけのクラス図を貼ってみます。


小さくて読めないのは知ってますww