これは、マイナー言語 Advent Calendar 2014の記事であり、拙作記事「Flappy Birdを作る」シリーズ3作目でもあります。かつてのMacintoshに無償同梱されていたHyperCardを使ってFlappy Bird風ゲームを作りながら、スクリプト言語HyperTalkを紹介します。
HyperCard(HyperTalk)とは
HyperCardは"ハイパーテキストを実現した最初の商用ソフトウェア"です(HyperCard(Wikipedia))。HyperTalkはその上で動いたスクリプト言語です。
コンピューターの歴史上におけるHyperCardの存在意義、立ち位置についてはこの記事をどうぞ。実際の使用感について、あえて雑なたとえで説明すると、
PowerPoint + ペイントツール + スクリプト言語(HyperTalk)
といった感じです。PowerPointにおいてのスライドのように、1画面ごとの「カード」の連なりが1ファイル(「スタック」と呼ばれます)を構成しています。カードにはペイントツールで絵を描けますし、文字を表示する「フィールド」やクリックしたら別のカードに飛ばせる「ボタン」を配置することもできます。さらに、HyperTalkを使ってボタンに別のカードに遷移する以外の振る舞いを与えることもできます。
ゲーム開発環境としてのHyperCard
Wikipediaでも紹介されていますが、Cyan社のゲーム『MYST』はHyperCardで作られました。『MYST』は3Dグラフィックで作られた無人島を探索するアドベンチャーゲームです。発表当時の一般的なパソコンではリアルタイム・レンダリング不能な高精細な3D世界を、場面場面の止め絵を遷移させる手法で表現していました。Cyan社は80年代から同様の手法で『The Manhole』、『Cosmic Osmo and the Worlds Beyond the Mackerel』、『Spelunx』といった子供向けのアドベンチャーゲームを発表していました。これら作品群の、白黒ドットパターンを駆使したグラフィック表現には眼を見張るものがあります。(以下の動画だと、『Spelunx』が鮮明でわかりやすいと思います。)
場面遷移によるゲームブック的なアドベンチャーゲームは、HyperCardではスクリプトなしで制作できます。カードに場面場面の絵を描き、クリック可能な箇所に透明なボタンを配置します。ボタンにはほかのカードへ遷移をマウス操作のみで設定できます。
次に、Flappy Birdのような2Dゲームを作ることを考えてみます。アドベンチャーゲームとちがって、飛んだり跳ねたりするキャラクターが必要です。スプライトの代わりのゲームオブジェクトとして、ボタンが使用できます。ボタンには32x32ピクセルのアイコンを設定できます。アイコンはスクリプトで変更可能で、アニメーションさせることができます。スコアなどの表示にはフィールドが利用できます。カードに描いた絵をゲームの背景として利用できます。さらに、複数カード間でボタン・フィールド・背景を共有できる、「バックグラウンド」という概念も存在します。
Flappy Birdを作る
本題に入ります。Flappy Birdゲームの構成の仕方については、拙作記事(Sprite KitでFlappy Birdを作る)をご参考ください。今回はHyperCardなので、鳥の代わりにスタックのアイコンを飛ばせてみます。以下のような仕上がりになりました:
ソース
ゲーム全体のスクリプトです。右下の「Play」ボタン内に仕込みます。クリックしたらゲームを開始し、ゲームオーバーになったら停止します。
on mouseUp
-- initialization
put 0 into vy
put 1.5 into ay
put -10 into impact
put -8 into pillar_vx
put 0 into count
put false into mouse_down
put 16 into interval
put 5 into pmax
put 2 into w
put false into game_over
repeat with i = 2 to pmax
hide btn i
set rect of btn i to 0,0,0,0
end repeat
put 0 into card field 1
set loc of btn "stack" to 100,10
repeat
-- pillar
if game_over is not true then
if count mod interval is 0 then
repeat with i = 2 to pmax
if visible of btn i is false then
show btn i
if random(10) > 5 then
set rect of btn i to 512,160,512+32,288
else
set rect of btn i to 512,0,512+32,128
end if
exit repeat
end if
end repeat
end if
repeat with i = 2 to pmax
if visible of btn i is true then
if item 1 of loc of btn i < -32 then
hide btn i
put card field 1 + 1 into card field 1
play "boing" "a"
else
get loc of btn i
put item 1 of it + pillar_vx into item 1 of it
set loc of btn i to it
end if
end if
end repeat
end if
-- user input
if game_over is not true then
if the mouse is down then
if mouse_down is not true then
put true into mouse_down
put impact into vy
end if
else
put false into mouse_down
end if
end if
-- gravity
put vy + ay into vy
get loc of btn "stack"
put item 2 of it + trunc(vy) into item 2 of it
set loc of btn "stack" to it
-- collision
repeat with i = 1 to pmax
put left of btn "stack" into l
put top of btn "stack" into t
put right of btn "stack" into r
put bottom of btn "stack" into b
repeat with j = 1 to 4
if j is 1 then
get l&","&t
else if j is 2 then
get r&","&t
else if j is 3 then
get r&","&b
else if j is 4 then
get l&","&b
end if
if it is within rect of btn i then
if game_over then
if i is 1 then
exit mouseUp
end if
else
play "boing"
put true into game_over
put 0 into vy
end if
end if
end repeat
end repeat
wait w
put (count + 1) mod 360 into count
end repeat
end mouseUp
舞台・登場人物
今回はカード1枚のみを使用しました。画面下部のパターンで塗ってあるところが地面です。今回は、前進を表現する地面のスクロールは省略しました。その他、以下の部品を用意しました。
名前 | 種類 | 番号 | 役割 |
---|---|---|---|
- | ボタン | 1 | 地面の衝突判定用 |
- | ボタン | 2 | 柱 |
- | ボタン | 3 | 柱 |
- | ボタン | 4 | 柱 |
- | ボタン | 5 | 柱 |
"Play" | ボタン | 6 | ゲーム開始ボタン |
"stack" | ボタン | 7 | 鳥 |
- | フィールド | 1 | スコア表示 |
ボタンやフィールドは、新しく作られたものほど番号が大きくなります。番号が大きいほど前面に表示されるので、鳥は最大番号にしました。地面の衝突判定用の1番のボタンは透明です。2〜5の柱のボタンには土管の絵を割り当てたいですが、32x32ピクセル以上の画像は表示できないので(※)、妥協策としてただの四角いボタンにしました。
※ResEditというユーティリティを用いてスタックにPICTリソースを埋め込み、ボタンに貼り付けて表示する方法も裏ワザ的に存在します。(参考: HyperCardのスピードアップ)
シナリオ
ゲームループの概要をBASIC風に書くと、以下のようになります:
10 初期化
20 ループ開始
30 柱を作る
40 柱を動かす
50 柱が画面外に行ったら+1点
60 マウスクリックされたら鳥を跳ね上げる
70 鳥に重力をかける
80 衝突判定。ぶつかっていたらループを抜ける
90 20に戻る
処理の一部をかいつまんで説明します。
鳥に重力をかける
下記が鳥に重力を与える箇所です。HyperTalkの文の区切りは改行です。
-- gravity
put vy + ay into vy
get loc of btn "stack"
put item 2 of it + trunc(vy) into item 2 of it
set loc of btn "stack" to it
1行目
"--"はコメント行を意味します。
2行目
HyperTalkは英語に近い文法と言われています。変数への代入には=演算子ではなく、put〜intoを使います。vyは鳥のY方向速度、ayはY方向重力加速度です。put vy + ay into vy
で毎フレームの重力加速度加算をしています。日本語で書くと、vy+ayをvyに入れろ
といったところでしょうか。
3行目
さらに英語らしい要素として"it"があります。get loc of btn "stack"
は何をしているのでしょうか。"loc"はボタンのプロパティである"location"の省略形、"btn"は"button"の省略形で、略さずに書けばget the location of button "stack"
となります。"stack"という名前のボタンの位置を得よ
といったところですが、「得て」どうするのでしょうか。この文は、得た値を暗黙的に"it"という変数に代入します。続く2行で、このitを使ってボタンの変位を行います。
4,5行目
ボタンの位置(location)は、X座標とY座標のカンマ区切りデータで表されます。カンマ区切りデータは「アイテムリスト」と呼ばれ、各要素には"item"キーワードでアクセスできます。3行目で「得た」ボタンの位置情報はX座標,Y座標
形式になっているので、item 2 of it
でY座標を取り出せます。これにY方向速度を加算してさらにitに入れなおしています。座標は整数である必要があるのでtrunc()
でキャストしています。5行目の"set"キーワードで、ボタンの位置を変更しています。
衝突判定
HyperCardには衝突判定に使える"is within"キーワードがあります。これは、2次元の点が矩形領域に入っているかどうかを判定します。ボタンのプロパティ"location"はボタン矩形領域の中央の座標です。鳥の中央の点だけで判定すると、鳥が壁にめり込んでしまってイマイチなので、ボタンの四つ角について判定処理を行います。
障害物(地面、柱)との衝突判定部分部分は以下です。
repeat with i = 1 to pmax
put left of btn "stack" into l
put top of btn "stack" into t
put right of btn "stack" into r
put bottom of btn "stack" into b
repeat with j = 1 to 4
if j is 1 then
get l&","&t
else if j is 2 then
get r&","&t
else if j is 3 then
get r&","&b
else if j is 4 then
get l&","&b
end if
if it is within rect of btn i then
if game_over then
if i is 1 then
exit mouseUp
end if
else
play "boing"
put true into game_over
put 0 into vy
end if
end if
end repeat
end repeat
あらかじめ鳥のボタンの四つ角の座標を変数に入れておき、repeat
ループで各障害物との判定を行います。
put left of btn "stack" into l
put top of btn "stack" into t
put right of btn "stack" into r
put bottom of btn "stack" into b
get l&","&t
は、座標のカンマ区切りデータを作って"it"変数に代入しています。衝突を検知したら、"play"で音を鳴らしてゲームオーバー状態にします。"boing"はデフォルトで使用できるサウンドリソースです。第2引数に音階を与えてメロディを鳴らすことも可能です。このゲームでは点数が入る際にも使用しています:
play "boing" "a"
これは「A」の音、「ラ」でボインを鳴らします。
おわりに
やってみたら、わりとさくっとFlappy Birdが作れました。みなさんも、直観的にインタラクティブなコンテンツの創作ができるHyperCardでゲームなりなんなり作ってみましょう!実はまだAppleのサイトでHyperCardが入手できますから、古い実機かエミュレーターで動かすことができますよ!
・・・という話をするつもりでしたが、AppleサイトからHyperCard 2.2Lite-Jのリンクが消えていました。
HyperCard 2.2 Lite-Jをダウンロードしたいのですが・・・
現在でもダウンロードできるのでしょうか?
7 年位前まではダウンロード可能だった様ですが、今ではダウンロード出来なくなっていますね。