蛇足事項追記

・BGM
big19.midを使いました。ほどよい緊張感のある雰囲気がゲーム内容にぴったりだったので即決です。
mmplayの仕様上、MIDIオートリピートではループの瞬間に制御が一旦止まってしまいますので、No-BGMでプレイするか、止まるのも思考時間のうちとして許容するか、スタート時に選べるようにしました。


・爆弾の出現
各爆弾はすべて別個のオブジェクトとして状態制御しており、条件が整ったら出現開始するロジックであるため、レベルアップで個数が増える際には「出番を待ち侘びていたぜ」な感じで1つだけ先に出現します。
爆弾が落ち切ってからレベルアップすれば全部同時に出現しますが、増えたということが分かりやすいように、あえて爆弾落下開始の瞬間にレベルアップさせました。


・パネル生成
パネルは完全なランダムには生成されず、周囲の影響を受けることもあれば、独立領域ができるようにもなっています。
周囲に合わせるか独立するかは特別な制御はしていません。
とりあえず5色のランダムパターンでマップに床色登録しておき、同色連結領域の面積が3以下になった部分だけ「なかったこと」にして、次フレームに再度色選択することで実現しています。
つまり、下記のいずれかが成立するなるまで、パネルの床色決定が先送りされます。
・周囲の張り替えていない連結領域とたまたま同色になり、その一員として面積が3以上となる。
・新規登録でたまたま同色で3パネル以上が隣接し、連結領域の面積が3以上となる。
これでパネル色が確定すると、同色がまとまった感じになります。
また、連結領域の判別と面積計算はフレーム毎に常に行われており、一旦条件を満たしてパネル生成に状態遷移しても、周囲の同色パネルが張替えられることで面積不足になれば「なかったこと」にされます。
この面積3というのは絶妙で、2だとバラバラになりやすくなり、4だとパネル生成の時間差が広がりすぎてしまいます。

TV(3.5)で動確

HSPTVでの配信を確認しました。
HSP3.5にて最終チェックしたときのASで応募したためか、古いバージョンのHSPTVブラウザで実行するとNo-Dllエラーになります。
対処はブラウザを3.5に上げるしかなさそうです。
なんだか申し訳ございません。
3.5では問題なく動作します。
ハイスコア欄は色の選択をしくじった感じ。

応募完了

ANSUKOEMU2017-10-31

駆け込み応募してきました。
クリックゲーム「Teritorion」、HSPTV部門ID#1507です。そのまま「テリトリオン」と読みます。


同色で連結されているパネルをクリックすると、一繋がりになった範囲が落ちて、新しい色に張り替わります。
新しい色は、ランダムながらも周囲に影響を受けます。
パネルには複数の爆弾が載っていて、タイムリミットに達すると爆発してゲームオーバーです。
爆発を阻止するには、パネル張替えのときに一緒に落としてしまうしかありません。
しかし、爆弾は特殊な耐性を持っており、すべてが一繋がりのパネルに載っている状態で張替えして、同時に落とす必要があります。(1つでも繋がっていないところに残っていると、すべて生き残ります。)
パネル色をうまく変えて一繋がりのパネルに爆弾が載るようにし、一気に張替えすると、爆弾が落ちて面クリアです。


操作は、落とすパネルをポイントしてマウスボタンをクリックするだけ。
面クリアしてレベルが上がっていくと、連結されない狭小領域の閾値が上がって、爆弾も増えていきます。
全体認識力と素早い判断、正確なマウス操作が要求されます。


では、蛇足事項。
今年の作品は、ジャンルとしては「クリックゲーム」です。
闇雲連打とならないよう、何色で繋げるか、どのルートで繋げるかといった戦略性を盛り込むように検討しました。
ギャンブル要素も仕込んでいます。(パネル張り替えで思い通りの色が出なかったり、周りとまったく関係ない色が発生したり、予期しない狭小領域が発生してルートが作れなくなったり…)
タイトルのTeritorionは、エスペラント後で「領土」を意味するteritorio[テリトリーオ]から。
領土(同色連結されたパネル)を繋げたり、潰したり…が、本作品のテーマです。
内部的には、常に領土の面積(パネル数)カウントし、狭小領域の判断のほか、パネル数3未満領域の生成防止や、周囲の色に適度に合わせるようなパネル生成といった仕組みに使用しています。


前回はオープニングが殺風景だったので、本作品ではバックでチュートリアル的なパネル変化をさせて、ちょっとだけ賑やかにしてみました。

魔石の移動

うすあじ賞の副賞が届いていました。
ワインの広告とかと一緒になっていて気付けなかったら捨てられたところ。危ない危ない。


さて、本題。Temples Trickの魔石移動、移動開始と破壊の制御について。


魔石は障害物に当たるまで同じ方向に動きます。
これは、魔石オブジェクトが持つ移動カウンターが1→0に変化するタイミング(1マス分の移動の終わり)にて自身の移動方向に移動継続できるか判断、移動可能なら次のマスを目的地として再度移動を始めるということで実現しています。
プレイヤーが魔石を押したときに必要な処理にもここをうまく使い、スリム化を行っています。


プレイヤーが魔石を押したときの見た目の動作は、押されたオブジェクトが魔石の場合に、その魔石の向こうのマスが空きであれば魔石が動き出し、押した魔石が赤魔石で移動方向に障害物が接しており赤ポーション残数ありだと、赤ポーションを消費してその魔石を破壊、といった感じです。
このような動作をプログラムする場合、押した方向の隣接マスのオブジェクトを判別して、オブジェクトの向こう側のマスの確認を行い、条件に適した処理(移動・破壊)に振り分ける、のような手法が定番です。


Temples Trickではこの方法はとらず、マップから対象のオブジェクトIDを拾い、該当のオブジェクト管理テーブルに対して、先の移動継続判断に必要な情報だけ代入して、あとは魔石オブジェクトの処理にまかせるということをしています。
具体的には、移動カウンターに1、赤Pフラグに移動要求時の赤ポーション残数、移動量にプレイヤーの向きに相当する1マス分移動量をに与えておしまい。
このとき、マップから拾ったオブジェクトIDが何のオブジェクトの物なのかはチェックせず、壁(ID=128)だろうが、空間(ID=0)だろうが構わず情報を代入していますが、魔石オブジェクトだけが意味を持つ値なので、問題はありません。
あとは魔石オブジェクト側の制御で移動継続の判断が行われますので、移動可能であれば与えられた移動量をもとに勝手に移動開始となります。
移動できない場合には、自身が赤魔石かつ赤Pフラグに値があるなら、赤ポーション残数を減らし、破壊開始させます。
(赤Pフラグは移動・破壊にかかわらずオブジェクトの情報からクリアします)
要求してダメだったらなかったことにする系のサイズ削減手法です。

「うすあじ賞」を受賞

今回、スクリプトのコーディング期間は実質2日でした。
ルールやステージ案とかは9月あたりから検討はしていたものの、なんだかんだで時間がとれず、10月最後の土日(29,30)は自室に引篭もってコーディング。
Kacotte!同様マス目移動のため、例のvardup,posclcサブルーチンと、キー入力判定ロジックは流用しましたが、あと使えたのはハイスコア処理くらい。
面データを除いても全体の8割は新規コーディングが必要で、この2日間の集中度は半端では無かったです。
(以上、結果が出たのでカミングアウト)
例年に増して無謀でしたが、受賞できて良かった。


さて、気になったその他の作品について。
総合優秀賞の「オオツルギ2」。これはくると思っていましたよ。大方の予想通りではないでしょうか。
前回上位賞の時点でも伸びしろを感じましたが、がっちり進化させてきました。
こういうのをアーケードとかギャラリー見守る中で(若い時に)プレイしたかったなー。

Ver1.15更新登録

無駄な処理を削って、機能を増やしました。
ステージクリア、スキップの達成状況がわかるように、画面左上スコア欄に表示。
5面区切りで、クリアした面の場所に「*」をGameOverしたところに「X」が入ります。
ハイスコア登録の際も、達成状況を送信します。
Ver1.15でのハイスコア登録が増えないと表示がガタガタになりますが…
あと、タイトル画面のハイスコア表示について色数を増やしてみました。

ステージデータ展開

順番前後しましたが、スクリプト内でのステージデータの展開について。

>9x9のフィールドデータ部分は、横3マスをASCII文字1Byteで表現しており、81マスで27文字使います。
>これに、敵と赤ポーションの数を示す1文字を付けた構造で、1ステージ分を正味28バイトの文字列データとします。
たとえば、スクリーンショットの面(Ver1.12では20面)の文字列データは "X@pZ@r@h@@B@PGP@B@@h@ZRrX@pL" です。
先頭から27バイト分を元に、以下のようなスクリプトで魔石オブジェクトとグランドマップへ展開しています。

memset mapg,255,EMAPNUMSZ
lpoke c1
repeat PLFNUM
	c1+:gosub *vardupc1
	e0t=(peek(mg,cnt/DTW)>>(cnt\DTW))&9,cnt+PLFOFSET+(cnt/PLFW)*PLFGAP,1 ; オブジェクトデータ登録
	gosub *posclc:emapg=(e0t=1) ; グランドマップ更新
loop

あらかじめ#constされている各シンボルは、以下のような意味と値になっています。
EMAPNUMSZ マップ配列のバイト数、15*11*4→660
PLFNUM プレイフィールドのマスの数 9*9→81
DTW ASCII文字1バイトで現わすマスの数 3
PLFOFSET マップにおけるプレイフィールド開始位置 15+1→16
PLFW プレイフィールドの幅 9
PLFGAP 2つの段のプレイフィールド間にある壁の厚さ 15-9→6


まず、memsetはグランドマップの中を255(&HFF)で埋めています。
配列は整数型なので、1要素4バイト分として考えると&HFFFFFFFF、つまり-1で埋まるのと同義です。
ループ内ではプレイフィールドのみ操作するので、81回ループしています。(壁は触りません)
c1をオブジェクトID(1〜82)として用いるので、ループ前にlpoke c1で0クリア、ループ最初でインクリメントしています。
おまじないのサブルーチンvardupc1をコールした後、オブジェクト情報の定義をします。
e0tは該当オブジェクトについての管理テーブル先頭要素で、ここからカンマ区切りで、マスのタイプ、位置、移動カウントを代入。
マスのタイプ(空白:0、魔法陣:1、紫魔石:8、赤魔石:9)は、文字列変数mgより該当する1バイトを参照し、シフト&マスク(9)で取得。
位置は、cntの値に<プレイフィールドの段数>×<壁の厚さ>とオフセットを加算した値。
オブジェクト情報に位置と移動カウントが入ったらposclcを呼び、魔石オブジェクトの下準備(現在位置のx、y情報登録など)を行います。
空き床や魔法陣についても構わずオブジェクト登録していますが、メインルーチンではタイプ8,9だけが魔石として扱われるので問題ありません。
posclcにてemapgに該当位置のグラウンドマップがdupされるので、タイプが1なら魔法陣(1)、それ以外は空き床(0)を代入します。


微々たる量ですがサイズが肥大化しないよう、配列添字の隠蔽と、計算式削減を念頭にスクリプトを書いています
要所に出てくるvardupc1,posclc(もしくはvardup,posclceg)などに共通化できる定型処理をまとめておき、マップ配列はできるだけdupされた変数が使えるようにしています。
シフトの計算については1マス1ビットシフトで済むタイプ値を採用し、式が大きくならないようにしています。
また、処理全体として1次元のデータとして扱うことで、ループ多重化も回避。