擬似3Dグラフィックスを搭載したシューティングゲーム... bash

こんにちは、Habrachelovek!



どういうわけか、「Hello world!」をbashで書く方法を学ぶのがいいと思いました。 結局、私は6か月間ubuntに取り組んでいます。これができないのは残念です。 私はHabréを見て、最近ではマニュアルを読むのが流行ではなく、自分でゲームを書く必要があることに気付きました。 どちらを選択するかは変わりません。 チェスXonix倉庫番海戦はすでに書かれていますが、テトリスも(リンクは見つかりませんでしたが)どうですか、何を選ぶべきですか? 最初のアイデアは戦略でしたが、完全な狂気のために捨てられました(bashのゲームに関するトピックの歴史を続けている人の1人がそれを書いてくれることを願っています)。 だから私はシューティングゲームに落ち着きました。





* 写真は、数歩先の廊下と怪物を示しています



スクリプトリンク: github.com/EvilTosha/labirinth/blob/master/lab2.sh



カットの下には、ゲームの内部についてのまったく面白くなく不必要な説明があります。



スケッチ、視点、一般的なアイデア。



それはすべて、紙のスケッチから始まりました。







これは何らかの形で端末に受け入れられる形式に変換する必要がありました。 結局のところ、目を楽しませてくれる廊下の遠近法は、描くのがそれほど簡単ではありません。 したがって、小さなプログラムはC ++で作成されました。 その後、出力画像の異なるレイヤーを生成するように修正されました。



UPD

頻繁に発生するクレームに答えます。 このコードはスクリプトでは使用されません。変数と配列の初期化の段階でスクリプトに入力されるデータの準備にのみ必要です。



#include <cstdio>

#include <cstdlib>

#include <iostream>

#include <cmath>

#include <vector>



using namespace std;



// p ,

// p1 p2

bool overLine(pair< int , int > p1, pair< int , int > p2, pair< int , int > p){

return (p1.second - p2.second) * p.first + (p2.first - p1.first) * p.second >

-(p1.first * p2.second - p2.first * p1.second);

}



const int width = 128;

const int height = 36;

//

const int delta_ceil = 20;

const int delta_floor = 20;



int main(){

freopen( ".out" , "w" , stdout);

char field[height][width];

//

pair< int , int > p3(11, width / 2), p6(12, width / 2);

//

pair< int , int > p1(0, delta_ceil), p2(0, width - delta_ceil);

pair< int , int > p4(height, delta_floor), p5(height, width - delta_floor);

//

int depths[8] = {10, 27, 39, 48, 54, 58, 61, 65};

for ( int x = 0; x < height; ++x){

for ( int y = 0; y < width; ++y){

pair< int , int > p(x, y);

//

if (!overLine(p2, p3, p) && !overLine(p3, p1, p))

field[x][y] = 'c' ;

//

else if (overLine(p6, p4, p) && overLine(p5, p6, p))

field[x][y] = 'f' ;

//

else {

int wall = min(y, width - y);

int d = 0;

while (wall > depths[d])

++d;

field[x][y] = '0' + d;

}

}

}

//

for ( int x = 0; x < height; ++x){

for ( int y = 0; y < width; ++y){

cout << field[x][y];

}

cout << endl;

}

return 0;

}



* This source code was highlighted with Source Code Highlighter .






その後、反射がありました:壁を平らにする(フィールドの2つの隣接するセル間のスペースを使用する)か、1つのセルを占有します。 最初のオプションでは、廊下が曲がるときに何を描くべきか、そしてすぐに反対方向に何を描くかが明確ではありませんでした。 (私は実際に塔で正直な幾何学をしたくありませんでした、そしてそれは亀よりも遅く働いていただろう)



したがって、いくつかのフィールドセルを壁にすることが決定されました。 しかし、レンダリングにはいくつかの問題があります。 たとえば、そのような状況で何をすべきか?



したがって、生成されたラビリンスには制限が課せられます。壁のない2 * 2の正方形が1つだけあってはなりません。 次に、この迷路を生成する必要があります。



迷路生成



ディープサーチに似たアルゴリズムを使用します。 つまり フィールド全体を壁で満たし、開始点を選択し、フィールドをグラフとして巡回し始めます。特定の順序ではなくランダムにすべての近傍をソートします。 さらに、「禁止」の2 * 2の正方形が形成されているかどうかを確認します。



生成はかなり長い時間(20 * 20約2〜3秒)動作します。おそらく、スタックへの再帰を有効にすると速度が著しく向上しますが、なぜこのような大きな迷路が必要なのでしょうか?



クイックレンダリング



最初は、各「ピクセル」は独自のエコーによって表示されていました。 「スクリーン」36 * 128のサイズでは、1つの「フレーム」を描くのに1秒近くかかり、私はそれが本当に好きではありませんでした。 変更された「ピクセル」のみを描画すると、速度はさらに低下します。 そのため、次のことが行われました。すべての文字を配列に入れてから、

echo -ne "$ {screen [*]}"


すべての要素を出力します。 しかし、このような呼び出しでは、配列の要素はスペースで区切られます。 私の出力画面もマルチカラースペースのみで構成されているため、これに目を留めることは可能ですが、普遍性が必要でした。 解決策は次のとおりです。最初に「\ n \ t」(ラインフィード、タブ、スペース)に設定されているIFS(Internal Field Separator)を空に変更し、スクリプトの最後で元に戻します(再オープンせずに続行できるようにターミナル)。 これで問題は完全に解決しました。 しかし、ちなみに、5 FPSを超えることはできなかったため、「リアルタイムモード」は最初は無効になっており、シューティングゲームは段階的に判明しました。 ただし、画面の「ちらつき」で目を楽しませたい場合は、定数で画面をオンにすることができます。

ところで、スクリプト全体では、テキストと背景に標準の8色のみを使用します。 多くの色と混同されると、美しいグラデーション照明を作成でき、色はより自然になります...



モンスターの作成、射撃能力、その他のささいなことについては説明しません。すべてがシンプルで退屈です。



おわりに



私がやりたいことはたくさんありましたが、忍耐力に欠けていました(より正確には、実装される前に興味が消えました)。 これは、たとえば、1つではなく複数のモンスター、正しい人生の仕事(現在は美のためにのみ表示されています)、武器の変更(それに応じて異なる特性)、コンソール(iddqd、しかしどうですか?=))、そしてもちろん、ネットワークゲームです。



ゲームプロセスの別のビデオをアップロードしたかったのですが、録画に必要なソフトウェアをインストールしたときに、仮想ボックスの音声が壊れました。 =(



ご清聴ありがとうございました。どんな批判も喜んでいます!



All Articles