MAGNITUDE−Μ

9999-00-00

ここは、あんすこえむのHSP作品に関するサポートページ兼開発日誌Blogです。

2015/12/01 「宇宙海賊キャプテン・オニオン」がHSPプログラムコンテスト2015「秀和システム賞」を受賞しました。

2015/10/16 リアルタイム・ストラテジー・ゲーム「宇宙海賊キャプテン・オニオン」をHSPコンテスト2015HSPTV部門にエントリーしました。No.1056

2014/12/01 「Kacotte!」がHSPプログラムコンテスト2014「株式会社インプレス 窓の杜編集部賞」を受賞しました。

2014/10/31 囲って閉じるアクションゲーム「Kacotte!」をHSPコンテスト2014HSPTV部門にエントリーしました。No.904

続きを読む

トラックバック - http://d.hatena.ne.jp/ANSUKOEMU/99990000

2016-01-16

賞状+本到着

コンテストの賞状、革製しおり(参加賞)、入賞賞品の書籍「Arduinoロボット工作をたのしもう!」が届きました。

入門編からどんどん難易度が上がっていく構成。

なるほど、Arduinoに興味があれば、どっかのスキルレベルに当たるなこれは。

トラックバック - http://d.hatena.ne.jp/ANSUKOEMU/20160116

2015-12-03

[]入賞報告

宇宙海賊キャプテン・オニオンは「秀和システム賞」となりました。よく入賞できました。

他の受賞作と見比べると、本作は詰め込み以外に特筆すべき要素に乏しかったですね。

(おにたま氏も詰め込み具合に慣れてきちゃってるのか、コメント短いですのぅ。

まあ、そこだけでも評価頂ければ光栄なんですが。)


さて、今回の受賞作の内、自分が注目していたのは2つ。

一つ目は優秀ゲーム賞のオオツルギ。最優秀も狙えると思ってましたよ。

唸らされたのはソード攻撃の仕様。

シューティングゴッドバードアタックや科学忍法火の鳥な感じの体当り攻撃を実装するとき、

どうやって自機をコントロールラインに戻すか、扱いに困るんですよね。

オオツルギでは、自機移動範囲が円のため、向い側への跳躍!で自然に解決できているのが凄い。

もちろんあんだけ「カッコイイ」演出というのも評価高いです。


もう一つ注目作だったのは、いつもハイセンスさが光る丸中さんのヌリツヴス。

結果はなんと2賞を同時受賞。

パネルを塗る一筆書き要素は去年の拙作Kacotte!にもあったので、かなり気になる作品でした。

パズル特化時の方向性とかアイデア、ルール拡張性など、深く掘り込む姿勢は見習うべきだなー。

トラックバック - http://d.hatena.ne.jp/ANSUKOEMU/20151203

2015-11-20

[]終了判定

とりあえず、一次選考通過の報告。そして、ついでにロジック解説。


128パーセク到達後に敵を殲滅かつ母艦健在である場合、離脱成功としています。

クリア判定処理に関与するコードを抜き出してみると、以下のような感じ。

if(plmode){   プレイ中であれば
    repeat 99   艦艇オブジェクトを操作するループ
        gosub *verdup  オブジェクト管理テーブルからID=cntのオブジェクト情報を変数にdupする処理。
        if(eep){          オブジェクト存在時の処理
            flag>>f0      敵ならフラグをクリア
            if(eep>=1000){ オブジェクトが健在
                flag|=(cnt=0) 母艦(cnt=0)であればflagに1をORする。
            }
        }
    loop
}
:
進行度が128パーセク以上でflag>0であればゲーム終了判定を出す。

このループでは、すべての艦艇オブジェクトに関して状態値eepを判断し、それぞれの操作(移動、当り判定、爆発、敵生成)などを行います。(クリア判定に関係のない処理は省いています)

同時に、フラグ変数flagの状態を変化させ、母艦健在で敵殲滅の状態になっているかを求めています。

128パーセク到達後に通る箇所でflag>0か判断。

クリア判定が出ていれば、ゲーム終了シーケンス(終了メッセージ表示、ハイスコア更新)を行って、タイトルへ移行します。


まず、ループ前にflagを初期化していません。

敵が一体でも存在(爆発含む)していれば0になるし、flag>0が意味を持つのは128パーセク到達後の1度だけ(1度クリア判定すればタイトルに移行する)なので、省略しても問題がないのです。


実質の初期化は、母艦が健在のときだけ意味のある処理として flag|=(cnt=0) で行っています。母艦が健在なら1をOR。

母艦以外でも該当オブジェクトが健在であれば実行されますが、cnt=0の比較演算が0を返すのでflagは変化しません。

この初期化の前にflagが1だったとしても、先にも書いたように128パーセクに到達していなければ不問となるので不都合はありません。

そもそも、終盤は敵の出現頻度が高く、flagが1のままフレームを持ち越すことがないというのもあります。


そして、敵が存在(健在もしくは爆発)している場合にflagを落す処理は、flag>>f0 。

f0は敵味方の処理振分け用に用意されている変数で、値は味方→0、敵艦→1、敵ミサイル→2 です(*vardupにてcnt/33相当の値を代入)。

つまり、味方以外の処理でここを通ると、f0が0ではないためflagの左シフトが発生。flagは0か1なので、1ビットでも左シフトすれば0クリアされる仕掛けです。


ゲーム終了の処理は、ゲームクリア、ゲームオーバー兼用で、母艦が存在するかどうかでメッセージとハイスコア記録用文字列を変えるだけとしています。

これらの作り込みにより、100Bytes以内のコストでゲームクリア関連処理の追加を実現しています。

トラックバック - http://d.hatena.ne.jp/ANSUKOEMU/20151120

2015-11-06

[]弾の発生

通常弾、レーザーミサイルの生成処理について。

このゲームでは、登場するキャラクターをオブジェクト管理テーブル(2次元配列)で管理しています。

ID=0は母艦、1〜32は僚艦、33〜65は敵艦、66〜98は敵ミサイル、99不使用、100以上は攻撃オブジェクトに割り当てており、IDが99未満の「艦艇オブジェクト」については、共通のコードで弾の発生を処理しています。


フレーム毎に射撃インターバルカウンタが0かどうかチェックし、0になっていれば、以下のような流れで、攻撃オブジェクト(通常弾/レーザー)もしくはミサイルを生成します。(ミサイルは管理の都合上、艦艇扱い)。

1 ロックオン中の攻撃対象がない(ターゲットID=0)の場合は、対象範囲からランダムにIDを選択し、仮ロックオン

  ロックオンしている攻撃対象の情報を取得。

2-A ミサイル艦の場合

  ターゲット(ミサイル)が不在(状態値=0)で、自身が特攻前なら、ミサイル発射処理を実施

   射撃インターバルを再設定(固定値)。

   該当のIDにミサイル用のパラメータを格納(ミサイル耐久値は、ゲーム進行により増加)。

   ロックオンは不要なので、攻撃対象をなしにする。

2-B ミサイル艦以外

  攻撃対象の座標を取得し、自身からの距離を計算

  「攻撃対象が健在、射程圏内、弾に空きがある」の全てについて成立するかチェック。

  成立する場合、攻撃オブジェクトの生成を実施

    射撃インターバルを再設定(カウンタ値は、ゲーム進行により減少)。

    弾の空きリストから1件取り出して攻撃オブジェクトとしての各種パラメータを格納。

  成立しない場合は、自身のロックオン中の攻撃対象をなしにする。

一度ターゲットIDが決まったら条件から外れるまで保持するので、射程圏内に入った攻撃対象をロックオンするようになります。

(ターゲットを撃破するか射程圏外になるまで撃ち続ける)


ランダムに選択するIDの範囲は、艦艇の種類ごとに以下のように割り振っています。

艦艇オブジェクトの種類選択するIDの乱数範囲
プレイヤー母艦、プレイヤー僚艦(通常弾)33〜65:敵艦
プレイヤー僚艦(レーザー66〜98:敵ミサイル
敵艦通常弾0〜32:プレイヤー側全体
レーザー0固定:常にプレイヤー母艦
ミサイル66〜98:敵ミサイル(生成対象として)
ミサイル99〜132(この範囲は常に状態値=0なので弾を撃たない)

母艦を示すID=0は、この処理ではロックオンなしの意味でもあります。

そのため、敵の通常弾攻撃は母艦に対しては消極的で、側に僚艦がいるとそちらをロックオンするようになります。

逆に敵レーザー艦では、攻撃対象をID=0固定とするので、常に母艦をロックオン(発射は距離次第)します。

また、ミサイル艦の場合は、求めたIDは新たに生成するミサイルオブジェクトIDとして使用しますので、空きオブジェクトのIDを掴めないとそのフレームでの発射はなし、次フレームでの再試行に回されます。


通常弾とレーザーを生成する場合、弾の空きリストからオブジェクトIDを持ってくることによって、ほぼ切れ目なく、等間隔連射が可能になっています。

この弾の空きリストは、1次元配列と、リスト件数で管理しています。

フレーム毎にリスト件数をクリアし、通常弾とレーザーの描画や衝突判定など処理するループの中で、移動カウンタが0のオブジェクトについて空きリスト前方から順に追記。

(リスト件数が示す配列要素に該当IDを記録し、リスト件数を1加算)

次フレームの弾発生処理にて、リスト件数で示されている場所から順次遡って使用(リスト件数を減算しつつ、示されるIDを利用)します。

トラックバック - http://d.hatena.ne.jp/ANSUKOEMU/20151106

2015-11-05

[]背景描画

本作の背景は、星を多重スクロール風(4層)で表示しています。

多重といっても描画は各層の重ねあわせではなく、それぞれの星を全くバラバラに縦移動させています。

このような描画をする場合、X座標、Y座標、速度、色などの情報を管理する必要があります。

しかし、各情報を個別の配列で管理したり、乱数値をそれぞれ得たりすると、コード量が膨れてしまいます。


最終的に以下のようなコード(本体はrepeat-loop部分)となりました。(このままスクリプトエディタに張り付けて実行可能です。)

なお、dim省略などの行儀のよくない作りをしており、ヘタに組み込むと弊害が出たりします。参考にする場合は十分注意してください。

*main
    redraw:await 15:redraw 0:color :boxf
	repeat 207			; cntはx座標成分と兼用
		dup fs,sppg(cnt)	; sppgはdimしていないが、初回描画で207個分に拡張される
		if(fs){}else{fs=rnd(32767)}	; 描画色(0-31)、速度(0-3)、Y位置(32倍計算)を1度に乱数取得
		tmp=((fs&3)+1)*32:hsvcolor (fs&31)*6,100,tmp+127:pset cnt*3,fs/32
		fs+tmp:fs\(16400+cnt) ; Y位置を動かして、下まで行ったら変化を加えて上から繰り返し。
	loop
	goto *main

詳細を見ていきましょう。

repeat 207

207は星の数。半端ですが、後のpsetで3倍した値をX座標の範囲にあてています。

右側ゲージに掛からないよう、X座標を621までに抑えたので、この値。


dup fs,sppg(cnt)

整数型配列sppgによって各星の位置や属性を管理しています。アクセスのコストを下げるためcntで示される要素をfsにdupします。

どこにもdimがありませんが、初回で207個分のループによって配列が自動拡張されることを利用して、配列宣言を省略しています。


if(fs){}else{fs=rnd(32767)}

fsの値が0である場合、乱数値で初期化します。初期化したいのはY位置、色指定、スクロール速度。

関数は高コストなので、rnd()は一回。

Y座標の初期値(32倍計算)、描画色指定(0-31)、速度指定(0-3)のまとまりとして乱数を得てfsに代入します。

最初はどの配列要素も0ですから、ランダムなY座標に星が置かれます。

(厳密には配列拡張が行われた際に反故にされる範囲がありますが、初回描画だけなので無視)


tmp=((fs&3)+1)*32

fsの下2ビット(0-3の4種)に1足して32倍したものを速度値(32,64,96,128)としています。

速度であると同時に、明度の制御にも使っています。


hsvcolor (fs&31)*6,100,tmp+127

hsvcolorによる色指定。

fsの下5ビット(0-31)を6倍して色相値として指定、彩度は100固定、明度は速く動く星ほど大きくします。


pset cnt*3,fs/32

X座標は上にも書いたようにcntの3倍、Y座標はfsを32で割った値。


fs+tmp

Y方向の移動計算。速度値を加算するだけです。


fs\(16400+cnt)

星が画面下に到達した場合に、画面上部に持ってくるための計算。480*32より適当に大きな値でfsを割った余りを代入しています。

速度や描画色も変わってきます。(隣の星と変化の差をつけるためにcntも利用)

このとき余りが丁度0になって、次の描画で乱数値の取得対象になることが稀にあります。

その場合、途中の高さから星が出現するわけですが、ただの背景描画ですから気にする必要はありません。


repeat−loop部分、AXにして220Bytesになります。

トラックバック - http://d.hatena.ne.jp/ANSUKOEMU/20151105

2015-11-04

[]パーセク

蛇足事項。

このゲーム、ステージ進行の単位をパーセクにしたため、ワープ時亜空間での戦闘、という裏設定を入れています。

パーセクとは「年周視差が1秒(角度)になる距離」っていう定義で、だいたい3.26光年。ものすごい距離。

128パーセク生き延びるということは、417.3光年の逃避行です。

通常宇宙空間の前提で考えると荒唐無稽な移動距離なので、亜空間なる御都合空間にいるという設定。

パーセクを採用したのは、なにより単位記号が「pc」の2文字であるのと、語感を重視。

光年はlyで1とlが紛らわしいため却下。天文単位(au)は某キャリア名と被ったので除外。

あと、某アニメの宇宙キロとかも捨てがたかったけど、記号がわからなかった。

(キロだけだと、キロメートルかキロマイルかまったく別のキロナントカなのかも不明だし…)

トラックバック - http://d.hatena.ne.jp/ANSUKOEMU/20151104

2015-10-28

[]V1.07

バージョンをV1.07に上げました。多分これが最終バージョン。反映待ち。

クリア(離脱成功)時のHSP-TVへのハイスコア登録で、*マークをつけるようにしました。


128pc.に到達しても、敵を殲滅する前に母艦が撃破されるとクリアにはならないため、

クリア時と失敗の両方ともハイスコア登録が128pc.の表記になって区別不能です。

というわけでV1.07では、失敗時「 128pc.」、クリア時「*128pc.」を登録することで対処。

スコア登録時の文字列先頭は、通常空白なので、クリア時のみPOKEで'*'を書き込むことで実現。

この処理のために必要な16Bytesを捻出するため、僚艦ドラッグ時の僚艦ステータス表示を抑止して、

僚艦追加メニューと僚艦ステータス/強化メニューの表示に使用するPOS命令を1本化しました。

ついでに、GameOver時・クリア時のメッセージ文字色が僚艦耐久値ゲージと被っていたので、

個別指定で赤に変更。

トラックバック - http://d.hatena.ne.jp/ANSUKOEMU/20151028

2015-10-22

[]配信確認

本作品について、コンテストページへの反映と、HSP-TVの配信を確認しました。

動いた。


今回は開発中のトラブルがあり、きちんと配信後に動くかちょっと不安でした。

というのも、スクリプトエディタからstart.ax作成すると古い内容のstart.axが復活する現象が出ていたのです。

エラーもなく、スリム化したのになんでaxのサイズが減らないんだろう…と困惑。

作品バージョン番号を画面に表示しない仕様にしたので、なおさら不安。

これは環境に問題がありました。

hsptmpが読取り専用になっていて更新されず、それを元にして作られるstart.axも古い内容になってしまう状態でした。

ワークファイル関連を一旦すべて消して解決しましたが、hsptmpが読取り専用になっていた原因は不明です。

トラックバック - http://d.hatena.ne.jp/ANSUKOEMU/20151022

2015-10-21

[]V1.06

反映は木曜の夜なのかな? まだ配信されていなかったので、こっそり更新。

無駄なpalcolorを見つけて削除したら8Bytes減ったので、敵の爆炎色(palcolor命令で指定)について、撃破時と母艦到達時で異なるようにしました。

敵と味方でも変えたかったけどサイズに余裕がなかった。


なんで8Bytesで色の切替ができるのかについて、圧縮ネタをちょっと解説

各キャラクターは、オブジェクト管理テーブル(配列名eobj)上に状態値(dup変数名eep)を持っています。

この値が0なら不在、1〜999は破壊シーケンス、1000以上は耐久値ありとして扱います。

破壊シーケンスでは、状態値が1〜499の場合には爆炎表示(状態値で爆炎の大きさを表現)後、常に状態値を1減算します。

オブジェクト健在の場合は、ダメージを受けた時に、耐久値すなわち状態値を1減算します。

ダメージ蓄積により状態値が1000を切ると破壊シーケンスに入り、キャラクター種別にあった爆炎初期サイズ(母艦:200、敵ミサイル:50、その他:100)になるように状態値を強制変更します。(敵の場合は併せて点数計算、資金加算を実施。)

また、別の場所でやっている敵艦および敵ミサイルの母艦到達チェックでは、状態値を100へ強制変更します。(点数計算、資金加算なし)

で、都合の良いことに、オブジェクト管理テーブルにおける状態値の次要素が射撃間隔(dup変数名eeq)となっており、破壊されたら用済みなので、ここを爆炎色として使えます。

スクリプト上では、eep=状態値 → eep=状態値,色指定 と、オペランドを1個追加するだけで、爆炎初期サイズと一緒に爆炎色を指定でき、これが2カ所あるので8Bytes増。

爆炎の円を描画するときの色指定は敵味方共通。palcolor 15 固定だったのをpalcolor eeqとしただけなので、こちらはサイズ増加なしです。

ちなみに、母艦はID=0でオブジェクト管理テーブルの先頭オブジェクト、さらに状態値は配列の先頭要素なので、母艦が生きているかどうかの判別は、eobjを1変数として値を見れば分かります。

トラックバック - http://d.hatena.ne.jp/ANSUKOEMU/20151021