JSL を管理するプロジェクトを試してみましょう
昔、私は横スクロールゲームを書くことを提案しました。 https://community.jmp.com/t5/Uncharted/Wild-Road-Map/bc-p/20996/highlight/true#M5 。 80年代にゲームをプレイしていなかったら、 https://en.wikipedia.org/wiki/Parallax_scrollingにはいくつかの例があります。 横スクロールは、キャラクターが左から右に移動する 2D ゲームで、背景には 3D の奥行き感を与えるために異なる速度でスライドする複数のレイヤーが含まれる場合があります。 他のバリエーションとしては、垂直スクロール寸法を備えたプラットフォーム ジャンパーも考えられます。
解決すべき問題があります:
- ゲーム開発 (JMP でこれを簡単に作成できますか?)
- ゲームのグラフィックス(どんな感じですか?)
- ゲームオーディオ(聞こえましたか?)
- ゲーム入力(どうやって動くの?)
- ゲームプレイ(何か起こりましたか?)
1. ゲーム開発
私は JMP プロジェクトを使用しています (そしてつい最近、JMP 16 自己完結型プロジェクトに切り替えました)。5 ~ 10 個の独立したファイルがあるプロジェクトでは、自己完結型プロジェクトが好きになり始めています。 開いているファイルのタブとログ ウィンドウのドッキング ポイントがあります。 自己完結型プロジェクトは、すべてを 1 つのファイル (zip、内部) に保存し、開いたり閉じたりすると自動的に解凍および再パックします。
グラフィックス用のファイル、オーディオ用のファイル、ゲームプレイ用のファイルは個別の比較的小さなファイルであるため、このゲームを動作させるのは簡単でした。 これにより、ゲーム キャラクター間のゲーム プレイを管理する JSL などを簡単に見つけることができます。 プロジェクトでは、次のようにファイルがタブに表示されます。
A JMP project with several files.A JMP project with several files.A JMP project with several files.A JMP project with several files.A JMP project with several files.複数のファイルを含む JMP プロジェクト。
このプロジェクトを開くとすぐに 9 つのファイルが開かれます。ゲーム内の吸血鬼のクラス定義を保持するファイルが現在表示されています。 ファイルをいつプロジェクトに再保存するのか、いつプロジェクトを保存するのかがよくわからないので、プロジェクトを閉じる前に左上にある強調表示されたアイコンを使用します。 左下にもログをドッキングしました。 プロジェクトは JMP の残りの部分や相互から分離されているように見えるため、独自のログがあります。
MakeAddin ファイルはゲームの一部ではありませんが、ゲーム開発の一部です。 そのタブが開いているときに ^R (実行) すると、アドインが再生成されます。 別のタブを実行するとどうなりますか? JSL が実行されますが、これはゲーム ロジックの始まりではない可能性があります。 しかし、私はいつも間違ってそれを行っていたので、次のように修正しました。
- メイン ファイル game.jsl があり、他のすべてのファイルが適切な順序で含まれています。
- ほとんどのファイルは独立しており、クラスまたは名前空間を作成するだけです。
- Sidescroller.jsl ファイルには、他のすべてのファイルをロードする必要があります (これはメインのゲーム ループです)。
独立したファイルはすべて終わりと
try(include("game.jsl"),if(!contains(char(exception_msg),"includes itself through a closed path"),show(exception_msg)));これにより、現在のファイルの後に game.jsl ファイルが実行されます。 game.jsl ファイルは現在のファイルを再インクルードしようとし、再帰的インクルード エラーをスローしますが、これは無視されるか、その他のエラーがスローされます。これは報告されます。 横スクロール ファイルは最後に置く必要があり、その try ステートメントを初めライン。 そうすることで、サイドスクロール ファイルの残りの部分が実行される前に、game.jsl ファイルに他のすべてのものが組み込まれます。
game.jsl ファイルは次のようになります
files = {"AUDIO.jsl", "RGBA.jsl", "ASSETS.jsl", "LAYERS.jsl", "VAMPIRE.jsl", "BEAR.jsl",
// currently SIDESCROLLER contains the game logic. All of the files include this file,
// at the end, except for SIDESCROLLER which include it at the start. SIDESCROLLER is
// dependent on all of the other files being loaded. The other files are not order-dependent.
"SIDESCROLLER.jsl"};
For( iFile = 1, iFile <= N Items( files ), iFile += 1,
Try(
Include( files[iFile] ), // this exception is EXPECTED if you start one of the other files; it is OK!
If( !Contains( Char( exception_msg ), "includes itself through a closed path" ),
Show( files[iFile], exception_msg )
)
)
);これで、編集したファイルを実行できるようになります。 ただし...複数のファイルを編集する場合は、明示的に実行されていないファイルを必ず保存してください。 インクルードは、編集タブのコピーではなく、ディスクのコピーを取得します。 ただし、ファイルを 1 つだけ変更する場合は、上記のインクルードの設定方法により、保存する必要がなく、現在の編集タブのコピーが使用されます。
欲しいものリスト:
- 実行する前にすべてを保存します (または、編集タブのコピーを使用して含めます)
- プロジェクトの実行時に開始ファイルを指定します (プロジェクトロード時のファイルではありません)。
- タブの保存とプロジェクトの保存がどのように同じか異なるかを文書化する
- JSL からプロジェクトのすべて保存コマンドを実行する方法
2. ゲームグラフィックス
このプロジェクトでは、JSL で生成されたグラフィックスとダウンロードされたビットマップ グラフィックスの両方を使用します。 下の青い空、山、木々、そして砂利道は JSL によって作成されました。 岩の壁の表面はタイル状のビットマップであり、吸血鬼、コウモリ、クマはアニメーション化されたビットマップ シーケンスです。 最後にクレジット。
The little bear is idling; the vampires are releasing bats or disappearing.The little bear is idling; the vampires are releasing bats or disappearing.The little bear is idling; the vampires are releasing bats or disappearing.The little bear is idling; the vampires are releasing bats or disappearing.The little bear is idling; the vampires are releasing bats or disappearing.小さなクマは何もしていない。吸血鬼たちはコウモリを放ったり、姿を消したりしています。
RGBA.jsl ファイルは、JSL グラフィックスの重要な部分です。 JMP では、グラフ内で透明度を使用して描画したり、グラフ内で透明度を指定したビットマップを使用したりできますが、たとえば、透明な背景上に折れ線グラフを作成し、その透明な背景でそのビットマップを取得する簡単な方法はありません。 (レポート PNG 画像の背景を透明にするオプションがあり、グラフ以外のすべてを透明にして保存します。 保存した SVG を編集して背景を削除することはできますが、それを透明な背景の PNG に戻すには別のプログラムが必要です)。
ウィッシュリスト
RGBA ファイルは、何も描画されていない透明なピクセルでビットマップを作成するためのクラスを作成します。 お気に入りのプリミティブを拡張する必要があるかもしれません。 葉が不透明ではない木や、葉と葉の間に隙間がある木を確認してください。 Path() を使用したベジェ ツリーでは木の描画について説明していますが、アルファ チャネルを使用したものではありません。 山はさまざまなパラメーターを備えた丘描画アルゴリズムの複数のレイヤーであり、空は不透明な青から黒の影付きの長方形です。 砂利道は生成するのにかなり時間がかかるかもしれませんが、一度実行すると十分に速くなります。砂利の各ビットはビットマップで描画されます。
ASSETS.jsl ファイルは、ゲームが使用するビットマップ アセット、それらを開く方法、正規化する方法、名前を付ける方法について知っています。 アニメーションは異なる人によって描かれているため、同じ方法で中央に配置するには正規化が必要です。 その情報は次のような構造で保持されます
Assets:vampire_images["hit"] = {{"attack/hit_1",.,.,0.80,0.5},これは、コウモリを放つ吸血鬼が、幅広のアニメーションを処理するためにビットマップ内でシフトされている (他のものでは .80 に対して .5) ことを示しています。 吸血鬼とクマは横スクロールで独自のレイヤーを取得し、その透明性により、より遠くのレイヤーが透けて見えるようになります。
ゲームは実際にはグラフ内にあるため、ズーム ツールを使用してグラフを覗いてレイヤーを理解することができます。 ここではズームアウトされており、空が左右に窓よりも大きくないことがわかります。 スクロールしません。 ただし、近くにあるレイヤーの幅はどんどん広くなり、より多くスクロールできるようになります。
Normally the sky fills the display, left-to-right. Zoomed out, see the vampire about to enter the stage.Normally the sky fills the display, left-to-right. Zoomed out, see the vampire about to enter the stage.Normally the sky fills the display, left-to-right. Zoomed out, see the vampire about to enter the stage.Normally the sky fills the display, left-to-right. Zoomed out, see the vampire about to enter the stage.Normally the sky fills the display, left-to-right. Zoomed out, see the vampire about to enter the stage.通常、空は左から右にディスプレイを埋め尽くします。 ズームアウトすると、吸血鬼がステージに入ろうとしているのが見えます。
小さなクマが右に歩くにつれて、ビットマップの位置が調整されます...
Not afraid.Not afraid.Not afraid.Not afraid.Not afraid.怖くないよ。
ちょうど真ん中を過ぎたところ・・・
The NPCs animate even when off the display.The NPCs animate even when off the display.The NPCs animate even when off the display.The NPCs animate even when off the display.The NPCs animate even when off the display.NPC はディスプレイから消えているときでもアニメーションします。
そして一番奥には…
The little bear has reached the right-hand end of his world.The little bear has reached the right-hand end of his world.The little bear has reached the right-hand end of his world.The little bear has reached the right-hand end of his world.The little bear has reached the right-hand end of his world.小さなクマは自分の世界の右端に到達しました。
吸血鬼は熊よりも歩くのが遅い。 彼らは追いつくでしょう。 そして、これは背景と前景の画像の一部が削除されたものです...
Without all the layers, the characters seem to float.Without all the layers, the characters seem to float.Without all the layers, the characters seem to float.Without all the layers, the characters seem to float.Without all the layers, the characters seem to float.すべてのレイヤーがないと、文字が浮いているように見えます。
3. ゲームオーディオ
サウンドは没入型体験の重要な部分です。 私はこのゲームのサウンドを作成するために LMMS を使用しましたが、適切なサウンド デザイナーならもっとうまくできるはずです。 しかし、音が途切れることなく重ねられるので、それでもかなり良いです。 Windows の場合。 Mac を使用している人がサウンドを再生できるコマンド ライン プログラムを見つけたら、おそらく Mac 上で使用できるでしょう。 ありがとう@ジェフ・パーキンソンMac オーディオ コードを手伝ってくれてありがとう。 Windows の場合、AUDIO.jsl ファイルは RunProgram を使用して Windows サウンド システムにアクセスできる PowerShell を実行します。 Mac では、コマンド ライン サウンド プレーヤー /usr/bin/afplay を使用します。 すべての再生サウンドが終了する前に JMP を終了しようとすると、JMP がクラッシュする可能性があります。最後の進行状況バーが開始されたすべてのサウンドの再生を完了するまで待ちます。
4. ゲーム入力
このゲームは、ゲームを保持するグラフ ボックスの周囲にマウス ボックスを配置することにより、キーボードを入力デバイスとして使用します。
New Window( "overlay",
mb = MouseBox(
V List Box(
hlistbox(
leftSpacer=spacerbox(size(5,windowy),color("black")),
gb = Graph Box(
suppressaxes,
framesize( windowx + 1, windowy + 1 ),
X Scale( -1, windowx ),
Y Scale( -1, windowy )
),MouseBox は、キーストロークを、キーと時間を記憶する小さな関数に転送します。
lastkey=empty();
lastkeyexpire=tickseconds();
spriteRunner = function({key},{},
lastkey=key;
lastkeyexpire=tickseconds()+1;
);他の場所では、キーのアクションが 1 秒後に期限切れになるまで繰り返されます。
While( go,
if( tickseconds() > lastkeyexpire,
lastkey="";
);
…鍵は小さなクマを操縦します。 これらは、Bear の有限状態マシン (FSM) に実装されています。 クマをアイドリングからウォーキングに変更する例は、BEAR.jsl のcycle() 関数にあります。
If( begin,
laststate=m_state;
if( keystroke=="LEFT" & ( pFaceLeft=="faceright" | (pFaceLeft=="faceleft" & pName=="idle") ),
m_state = m_stateWalkLeft;現在のアニメーション サイクルが開始位置にある場合、Begin は true であり、状態を変更するのに適しています。 ジャンプアニメーションの途中をアイドリングアニメーションのままにするのは奇妙に見えます。 クマが左を向いてアイドル状態の場合にのみ左に移動し始める必要があるが、右を向いている場合は…左に移動し始めるだけだというロジックを書いてからしばらく時間が経ちました。 これにより、歩いているときに即座に元に戻すことができ、おそらく同じ状態への変化を防ぐことができ、別の方法でも対処できるのではないかと思います。
5. ゲームプレイ
魅力的なゲームを作るのは私にとって難しい部分です。 ストーリーを語り、目標を作成し、パズルを追加します。 このゲームはほとんどが環境であり、ストーリーテラーを待っています。 ただし、ゲームプレイを少し追加しました。
,/*else if*/ keystroke=="DOWN" & m_NumRocks<6 & (m_state == m_stateWalkLeft | m_state==m_stateIdleLeft),
m_state = m_statePickLeft;
m_NumRocks = min(6,m_NumRocks+1);
// use SPACE to HIT
,/*else if*/ keystroke==" " & (m_state == m_stateWalkRight | m_state==m_stateIdleRight),
if(m_NumRocks,
m_NumRocks = max(0,m_NumRocks-1);
m_state = m_stateHitRight;
m_RockThrownRightFrom = m_x;
);下矢印を押すと岩を拾います。小さなクマは最大6個まで保持できます。 スペースキーを押すと、正面方向に岩を投げます。 クマは投げられた石をメモします岩を右から投げたまたは岩を投げた左からこれは、吸血鬼とクマを確認できるメインループ内のコードによってチェックされます。
// check for interaction between bear and vampire
if(!ismissing(bearPlayer:m_RockThrownRightFrom),
if(bearPlayer:m_RockThrownRightFrom<GETPOS></GETPOS>
吸血鬼を岩で叩くと、50 ピクセル後ろにノックバックされます。 (実際には、私が書いた方法で、一石で 2 人の吸血鬼を手に入れることができます。) 吸血鬼は、おそらく 2 人以上をサポートできるリストに含まれているはずです。 実際には、すべての NPC (非プレイヤーキャラクター) はリスト内に存在する必要があり、共通の基本クラスからサブクラス化して、代わりにループ内でcycle() の呼び出しを行う必要があります。
vampire1:cycle(stagepos);
vampire2:cycle(stagepos);
bearPlayer:cycle(stagepos,lastkey);
しかし、それではこの単純な例がどのように機能するのかがわかりにくくなるだけです。
プロジェクト ファイルとアドイン ファイルの 2 つの添付ファイルが必要です。 (現在プロジェクトをコミュニティに添付することはできませんが、アドインをインストールすると、プロジェクトのコピーがアドイン ディレクトリに存在します。)
アートクレジット
オープン ゲーム アート サイトには、さまざまな品質のコンテンツがさらにたくさんあります。