視界内に表示される壁を把握して実際に壁を描画する際壁の見た目上の重なりを表現するため描画する順序を工夫する必要があります。

 

工夫と言っても難しいことではなく遠い壁から描画して、先に描画した壁後に描画した壁に上書きされることを利用します。

奥の壁の一部が手前の壁に隠れる場合に、隠れる部分の描画範囲の計算などの特別な考慮をする必要なく壁の遠近を表現出来ます

但し、同じ距離の壁の内横壁をセットで描画する場合より外側から描画する必要があります。

 

壁の描画順の例

遠距離→中距離→近距離→側の順で描画します。

・同距離の中で、遠距離は横壁を描画しないので順不同他は端から順に描画します。

※中距離の描画順は上記の例以外に、左2→左1→右2→右1→0でも問題ありません。

 

 

サンプルマップを使用して壁が上書きされて一部(または全部)が隠れる様子を確認します。

 

サンプルマップ:自分の位置=(7,3)&上向き

※描画のロジックの一部をコメントアウトして手前の壁が表示されない様に調整しながら確認します。

 

 

1.遠距離のみ(赤枠の範囲)表示

→遠距離の正面壁のみ表示されます。

 

2.遠距離+中距離を表示

→左側の遠距離の壁が中距離の壁に上書きされて見えなくなります。

 

3.遠距離+中距離+近距離を表示

→遠距離と中距離の壁全てが近距離の壁に上書きされて見えなくなります。

 

4.遠距離+中距離+近距離+側を表示

→右側の近距離の壁が側の壁に上書きされて見えなくなります。

 

この様に遠くの壁から順に描画することで、描画範囲の細かい調整等をすることなく遠くの壁が隠れて見えないことを表現出来ます。

 

但し、例えば見える範囲のみマッピングしていく様な機能を追加する場合にはどこが見えなくなるのかを正確に把握する必要があるので、壁の一部分だけ見えている場合の描画が楽になる程度になります。

 

以上です。

2. 三角関数を使用した相対座標の求め方

 

視界内の相対座標を求める際に、予め4方向全ての相対座標をリスト等に入れておいて使用することも出来ますが、ここでは三角関数のsinとcosを用いて使用時点で計算して求めます。

 

コンピュータの座標で三角関数を使用するに当たり、ひとつ注意があります。

数学の座標平面コンピュータの画面の座標ではY軸のプラスとマイナスの向きが逆になります。

そこで、Y座標を求めるのに使用するcos取得した結果にマイナスを掛けて使用します。

 

 

まずcos(マイナスを掛けるので正確には"-cos")とsinの角度毎の値を確認します。この表の値は自分の位置から見ている方向を表すベクトルになります。

※使用する際は-cosとsinの値ROUND関数で四捨五入します。

 

・45°毎の-cosとsinの一覧表

※便宜上、この表は「CS表」と略します。

※上表の-cosとsinの値はROUND関数に影響が出ない範囲で丸めています。

 →例えば、実際の-cos 45°の値は-0.70710678…となります。

※表外の丸数字は、自分の周囲の相対座標取得時に使用します。

 

イメージとしては、Y軸が逆向きの座標平面の真ん中に立って、その角度をROUND(-cos)とROUND(sin)が示す距離分見ている感じになります。

 

 

2-(1) 上向きの相対座標の求め方

 

2-(1)-1 自分の位置(0,0)周囲の相対座標の求め方

 

上向き(角度0°)時の視界-90°~90°の範囲になり、CS表の「⑦⑧①②③」の値が対象となります。

座標平面で表すと下図の範囲になります。

 

視界のイメージ図(上向きの場合)


視界内の相対座標表(上向きの場合)

 

y=ROUND(-cos)x=ROUND(sin)とした場合、この座標平面を視界のイメージ図赤枠の範囲に見立てると相対座標表(上向きの場合)CS表の値が一致します。

この赤枠内の値を利用して上向きの視界内の全てのマスの座標を求めることで、向き変更時にもCS表の角度の範囲を変更するだけ変更した向き全てのマスの座標が求まります

 

 

2-(1)-2 正面の相対座標(近0、中0、遠0)の求め方

 

近0の座標は①と一致するので①の座標(-1,0)となります。

中0遠0の座標は、それぞれ近0の2倍、3倍の距離になるので①×2(=(-2,0))、①×3(=(-3,0))で求まります。

 

 

2-(1)-3 正面以外の相対座標の求め方

 

正面以外の座標は、自分の位置(0,0)から右1マス分のベクトルを求めて中0遠0から横向きの距離を計算することで求まります。

(0,1)-(0,0)→(0,1)となります。

↓↓↓

各相対座標は以下の通り

中右1:(-2,0)+(0,1)→(-2,1)

中右2:(-2,0)+(0,1)×2→(-2,2)

中左1:(-2,0)-(0,1)→(-2,-1)

中左2:(-2,0)-(0,1)×2→(-2,-2)

遠右1:(-3,0)+(0,1)→(-3,1)

遠右2:(-3,0)+(0,1)×2→(-3,2)

遠左1:(-3,0)-(0,1)→(-3,-1)

遠左2:(-3,0)-(0,1)×2→(-3,-2)

 

 

2-(2) 上向き以外の相対座標の求め方

 

右向きの相対座標

 

右向き(角度90°)時の視界0°~180°の範囲になり、CS表の「①②③④⑤」の値が対象となります。

 

視界のイメージ図(右向きの場合)

 

視界内の相対座標表(向きの場合)

 

CS表

CS表の①~⑤相対座標表一致

 

・正面の座標

上向きの計算と同様それぞれのマスの座標を求めます

 

近0が③の座標(0,1)なので、中0遠0の座標は③×2(=(0,2))、③×3(=(0,3))となります。

 

・正面以外の座標

自分の位置から右1マス分=(1,0)なので、各相対座標は以下の通り

中右1:(0,2)+(1,0)→(1,2)

中右2:(0,2)+(1,0)×2→(2,2)

中左1:(0,2)-(1,0)→(-1,2)

中左2:(0,2)-(1,0)×2→(-2,2)

遠右1:(0,3)+(1,0)→(1,3)

遠右2:(0,3)+(1,0)×2→(2,3)

遠左1:(0,3)-(1,0)→(-1,3)

遠左2:(0,3)-(1,0)×2→(-2,3)

となります。

 

下向き左向き同様の計算手順なので省略します。

 

「向き」と「視界」は以上です。(3)に続きます。

 

向き視界の設定と表記について

 

2Dの迷路を3D化することで、「向き」と「視界」を考慮する必要が出てきます。

この検証プログラムの解説では、向きと視界を以下の様に設定および表記しています。

 

・向き:「」の4方向

・視界:距離4段階、列は正面と左右2列の計5列

 →距離:遠い方から「遠距離中距離近距離」と表記。(「」と略して表記する場合もあり)

 →列:正面を「0」は近い方から「右1右2」、も同様に「左1左2

 ※但し、「側と近距離の右2、左2」および「遠距離の側面」は視界外とします

 ※正面に壁があってその先の壁が見えなくても視界とします

 

・視界内のマスは距離と列を繋げて表記

 自分の位置(赤マス):「側0」、正面は近い方から近0」「中0」「遠0」、遠距離左に2列目は「遠左2

 使用例:「上向きの場合、遠左2の相対座標は-3,-2」等

 

視界のイメージ図(上向きの場合)

色の着いたマスが視界

赤マスは自分の位置黄色マスは正面の視界、グレーマスその他の視界範囲、青矢印は向き

 

 

1.視界内のマップ座標の取得

 

視界内に壁を表示するために、視界とマップ座標を関連付けて壁と通路の位置を把握します

 

1-1 視界内の相対座標

自分の位置(赤マス)からの相対座標を求めて下図に(y,x)で表記します

※相対座標の求め方は説明が長いので後でまとめて解説します(※1)。

※自分の位置を(0,0)として、上は「y」がマイナス、下は「y」がプラス、左は「x」がマイナス、右は「x」がプラスとします

この相対座標マップ座標を合わせることで、マップの壁と通路の情報を取得します。

 

視界内の相対座標表(上向きの場合)

※視界内の壁を描画するためには上表で色の着いた位置のマップ座標を取得する必要があります

 

1-2 マップ座標の取得

以下のサンプルマップ(下図左)の(5,5)の位置(赤斜線)で上を向いた場合、(下図右)赤枠内の太線で囲われた範囲が視界となります。

自分の位置の座標は、赤マスの位置(5,5)に視界内の相対座標(0,0)を足して(5,5)となります

視界内の以下のマップ座標は次の通り

遠左2:(5,5)+(-3,-2) → (2,3)

遠右2:(5,5)+(-3,2) → (2,7)

側左1:(5,5)+(0,-1) → (5,4)

側右1:(5,5)+(0,1) → (5,6)

 

実行画面

 

向き変更時相対座標

上向き以外も向きに応じた相対座標図を作成して上向きと同様にマップ座標を求めます。

 

視界内の相対座標表(右向きの場合)

視界内の以下のマップ座標は次の通り

遠左2:(5,5)+(-2,3) → (3,8)

遠右2:(5,5)+(2,3) → (7,8)

側左1:(5,5)+(-1,0) → (4,5)

側右1:(5,5)+(1,0) → (6,5)

 

実行画面


視界内の相対座標表(下向きの場合)

視界内の以下のマップ座標は次の通り

遠左2:(5,5)+(3,2) → (8,7)

遠右2:(5,5)+(3,-2) → (8,3)

側左1:(5,5)+(0,1) → (5,6)

側右1:(5,5)+(0,-1) → (5,4)

 

実行画面


視界内の相対座標表(左向きの場合)

視界内の以下のマップ座標は次の通り

遠左2:(5,5)+(2,-3) → (7,2)

遠右2:(5,5)+(-2,-3) → (3,2)

側左1:(5,5)+(1,0) → (6,5)

側右1:(5,5)+(-1,0) → (4,5)

 

実行画面

 

長いので分割します。「向き」と「視界」②に続きます。

 

迷路を作ってもただ上から眺めて左上から右下まで目で追ってなんとなくゴールした気分になっても空しいだけなので…

 

迷路の中を歩き回ってゴールを目指す感じになる様に、迷路をレトロゲームエンジンpyxelで擬似3D化してみました。

一点透視法を使って壁等の大きさを計算して扱いやすい数値に丸めています。

 

pyxelの機能でgifを作ってみました。

 

操作方法:

前進:↑ボタン、左旋回:←ボタン、右旋回:→ボタン、振り返り:↓ボタン

壁色変更:スペースキー、迷路リセット:Qキー

 

※マウスでの操作も可能です。

前進、振り返り:マウスホイール、左旋回:左クリック、右旋回:右クリック

迷路リセット:左右同時クリック(操作が少しシビアですが…)

 

※ゲームコントローラーでの操作も可能です。

※PS4のゲームパッドでテストしました

前進:↑、振り返り:↓、左旋回:L1ボタン、右旋回:R1ボタン、

迷路リセット:OPTIONSボタン(STARTボタン?)

 

ソースはGoogleドキュメントに載せてあります。

迷路内の擬似3D化

 

迷路自動生成クラスのソースはこちらです。

c103maze.py

 

※「擬似3D」というのは、

Wizardryシリーズ

ダンジョンマスター

真・女神転生シリーズ

等々、のダンジョンをイメージしていただくと理解しやすいかと思います。

今回の擬似3Dを作成するにあたり、上記3シリーズを参考にしました。

 

擬似ではない本物の3Dを作るには今の自分には技術的に無理そうなので、3Dっぽく見える2Dの画像それっぽい位置に表示して3Dを表現しています。

 

ここでは主に実際に描画される各パーツ一点透視法による3D表現について解説します。

 

画面

 

ちなみに当初案はこちらになります。

最初はこちらの比率にしようと思ったんですが、通路上に何かを表示する際に「小さすぎる」ので現行サイズにしました。

 

リソース(256*256):イメージバンク0

一段目(左から):正面壁遠距離、正面壁中距離、正面壁近距離、謎のゴールポール

二段目:横壁中距離左右、横壁近距離左右、横壁側左右、横壁中距離左右(一列外側)

三段目:コンパス枠コンパス向き(上、右、下、左)

四段目:移動操作表示(左折、右折、前進、振り返り)

 

 

遠近感を出すために遠くのものは小さく近くのものは大きく見える様にサイズを変えています。

正面に壁がある直線の通路を前進した時の画面表示になります。

一歩進む度(画像の左上→右上→左下→右下の順)に正面の壁が大きく描かれます

 

謎のゴールポールはただゴールに座標を合わせるだけだと達成感が薄いので、目標物として立ててみました

謎のゴールポール近くなると大きく描かれます。但し、ゴールの位置に立つと見えなくなります。

 

画面右上に表示されているコンパス自分が向いている方向を示します。

左から、上向き、右向き、下向き、左向きとなります。

コンパスの外円の中は市松状に透過色を設定して壁と重なった時に少し透過する様にしています。

 

画面下移動操作表示は、動いたことが把握しやすい様移動操作時に0.1秒だけ表示されます。

移動操作後に表示される壁のパターン全く同じ場合座標表示またはコンパス以外に違いがなくなるので追加しました。

※ラグで実際は0.1秒より少し長い時間表示されている場合もありますが設定では0.1秒を超えたら表示を消しています。

※FC版Wizardryでは、移動操作時に一瞬だけ暗転することで移動操作を表現している様です。

 

横壁中距離左右横壁中距離左右(一列外側)の違いですが、

一点透視法の場合、奥の一点から放射状に引いた線上物体を描くので外側の方が角度的に開いて見えます。

正面近くの横壁(画像左)よりも正面から一列外側にある横壁(画像右)の方が開いて見える様に描いています。

 

 

見栄えの確認用に、壁色を変更出来る様にしてあります。

リソース(48*24):イメージバンク1

 

壁の位置に先に色を描画して、その上から壁を透過指定で描画して色が表示される様に作ってあります。

階層違いや特殊な場所を表現するのに使えそうな気がします。

 

 

左上の座標は上段が自分の現在の座標(x,y)、下段はゴールの座標(x,y)になります。

 

自分がスタート座標にいる場合は"START!"、ゴール座標にいる場合は"GOAL!"と表示されます。

 

 

(1)は以上です。(2)に続きます。

 

サイズを与えるとそのサイズの迷路を生成して返す関数を作ってクラス化しました。

ソースをGoogleドキュメントに載せました。

ソースファイル名:c103maze.py

クラス名:Maze
迷路自動生成(壁伸ばし法)クラス

・使い方
迷路クラスのインスタンスを作ってgetmaze」関数に迷路のサイズ(横&縦)を渡す迷路データのリストが返されます


迷路クラス呼び出しのサンプルプログラムを作ってみました。
こちらのソースもGoogleドキュメントに載せました。
迷路自動生成クラス呼び出しテスト

 

-ソース------------------------------------------------------
T105maze.py 迷路自動生成クラス呼び出しテスト
import pyxel as px

from c103maze import Maze

class App():
    def __init__(self):
        #self.h,self.wは5以上の奇数!
        self.h=131       #迷路の縦幅(外周込み)
        self.w=201       #迷路の横幅(外周込み)
        px.init(610,400,title="迷路自動生成クラス呼び出しテスト"+f"({self.w}*{self.h})",display_scale=2)
        px.mouse(True)
        self.sttflg=0   #開始フラグ
        self.lmap=[]

        px.run(self.update,self.draw)

    def update(self):
        if self.sttflg==0:                      #開始前の場合
            wk=Maze()
            self.lmap=wk.getmaze(self.w,self.h)
            self.sttflg=1                       #開始済にする
        elif px.btnp(px.MOUSE_BUTTON_RIGHT):    #開始済時に右クリックされた場合
            self.sttflg=0   #開始フラグ初期化
            self.update()   #update処理

    def draw(self):
        px.cls(0)

        #迷路描画
        for j in range(self.h):
            for i in range(self.w):
                if self.lmap[j][i]==1:
                    px.rect(3+i*3,3+j*3,3,3,7)  #壁を四角で表示

App()

-------------------------------------------------------

 

以上です。

迷路の自動生成後に作成された迷路のゴールを探索する処理追加してみました。

 

 

この迷路には元々スタート・ゴールという設定はないので、左上をスタート右下をゴールとしてルート探索を行います。

実際にゴールの探索を行う際は、スタートとゴールを通路上の任意の場所に設定して使用します。

 

探索系のアルゴリズムには何種類かありますが、その中で「幅優先探索」を採用しました。

※Wikipedia等に載っていますので、専門的な解説が必要な場合はそちらを参照してください

理由は大体以下の通りです。

・処理が単純

・解が存在する場合、必ず解を見つけられる完全性

重み(隣りのマスに進むコスト)の考慮は無いが、そもそも迷路の道のコストが一律(コストが常に1)なので不要

 

等々、迷路のゴール探索に向いていると思われるからです

どの様な探索法かと言うと「しらみつぶしに探して、途中でゴールが見つかったらそこで終了」という感じになります。


ソースはGoogleドキュメントに載せてあります。

迷路自動生成後にゴール探索追加

 

 

幅優先探索によるゴール探索の解説

 

1.以下のリストを作成する。

探索座標リスト探索座標を登録し、先頭から抜き出して使用する

探索済み保存用リスト探索座標から各方向の調査を行う時に調査方向の道が探索済みかチェックする

経路保存用リスト探索座標調査先関連付けてゴールに辿り着いた後にスタートに戻れる様にする

 

2.スタート座標探索座標リストに入れる。

 

3.以下の3-1~3-5の処理を探索結果が出るまで繰り返す。

3-1.探索座標リストが空の場合、探索結果「ゴールなし」として処理を抜ける

3-2.探索座標リスト先頭データを抜き出す(抜き出したデータ探索座標リストから削除する(popメソッドを使用))

3-3.探索済み保存用リスト抜き出したデータを登録する。

3-4.探索座標ゴール座標の場合、探索結果「ゴール到達」として処理を抜ける

3-5.探索座標隣(上下左右)の座標を調査し、未探索かつ通路の場合は探索座標リスト経路保存用リスト追加する

 

4.探索結果に応じて以下の処理を行う

4-1.ゴール到達の場合はゴール座標をマップにセットし、ゴール座標から順に経路保存用リストでスタートまで辿る。

4-2.ゴールなしの場合は経路を辿る処理をしない様にフラグを立てる。

 

5.探索結果がゴール到達の場合はマップに経路を描画する。

 

Googleドキュメントに載せてあるソースには左クリックゴール探索および経路表示右クリック迷路の再作成を行う様にしてあります。

 

以上です。

 

迷路自動生成の応用編として、前の記事で少し触れましたが「区画線」「小部屋」がある迷路の自動生成について解説します。

 

設定上の話になりますが、右上、右下、左上に小部屋黄色の十字を扉として固定配置し、間の迷路が書き換わることでそれぞれの小部屋や扉へのアクセスの仕方を変化させています。

 

ソースはGoogleドキュメントに載せてあります。

迷路自動生成テスト応用編

 

 

区画線について

 

区画線は迷路作成前に引いておくことで、線で区切られた区画毎に隣接した別々の迷路が出来上がります。

区画線の引き方は、左上の座標(y,x)=(0,0)としてy(またはx)が偶数(または)に引きます。

 

区画間の行き来をするための区画線上yが奇数ならxは偶数yが偶数ならxは奇数の座標に設置します。

 

ここまで設定してから迷路の自動生成を行うと、一例として以下の様な迷路が出来ます。

 

 

小部屋について

 

小部屋は上記の区画線と扉の応用になります。小部屋の範囲内の起点を取り除くことで小部屋内に新たな壁が発生せずに部屋になります。

↓↓↓

 

ここまで設定してから迷路の自動生成を行うと、一例として以下の様な迷路が出来ます。

 

但し、小部屋壁と接点を作る必要があります。

上記の例の様に壁と一体化した小部屋なら問題ありませんが、以下の例の様な位置に作るとルートが一意にならなくなります

例:壁に接点のない小部屋

↓↓↓

迷路自動生成を行うとルートが複数作られる

 

一か所壁とつないでおく等の工夫が必要

 

以上です。

 

ダンジョン等を毎回違うマップにするために迷路を自動生成するプログラムを作ってみました。

 

迷路の自動生成アルゴリズムは何種類かありますが、その中で「壁伸ばし法」を採用しました。

理由は大体以下の通りです。

・縦横共に5マス以上の奇数であれば大きさは自由に設定可能

複雑なものから単純なものまで多彩な迷路が出来る

・生成前に壁で囲って中の起点を取り除くと小部屋にすることが可能

 ※起点とは壁を伸ばし始める点

・生成前に全体マップを壁で分割しておくと区画分けが可能

 

等々、使い勝手が非常に良さそうなんです。

他のアルゴリズムでも実現は可能なのかも知れませんが「壁伸ばし法」では簡単な改修で実現可能です。

 

ソースはGoogleドキュメントに載せてあります。

迷路自動生成(壁伸ばし法)テスト

 

壁伸ばし法の解説

 

壁伸ばし法による迷路生成は以下の手順で行います。

 

1.迷路のサイズを決定します。

 迷路の縦幅と横幅を決めますが、この縦幅と横幅には外周の壁も含まれます

 例えば、縦5マス×横5マスと設定すると上下左右に壁が作られるので中身は縦3マス×横3マスになります。

 また縦幅と横幅には5マス以上の奇数という制限があるので、その範囲で設定します。

 

2.全体の座標を管理する迷路マップリストを作成し、外周の座標に「壁」を、その他に「通路」を設定します。

 

3.起点リストを作成し、左上の座標(y,x)=(0,0)としてyとxが共に偶数の座標を起点リストに登録します。

例:縦9マス×横11マスの場合、以下の青い四角の座標全て起点リストに登録

※上記の例では(2,2),(4,2),(6,2),(2,4),(4,4),(6,4),(2,6),(4,6),(6,6),(2,8),(4,8),(6,8)の12か所を登録

 

4.起点リストのデータをシャッフルして順番をランダムに入れ替えます。

※3の例を使用してシャッフルすると…

ランダムなので実際はどうなるかは分からないが、例えば上記の様に3で使用したデータ

(2,2),(4,2),(6,2),(2,4),(4,4),(6,4),(2,6),(4,6),(6,6),(2,8),(4,8),(6,8)

が、以下の様な感じに順が入れ替わる

↓↓↓

(2,8),(6,6),(4,8),(4,6),(6,2),(6,4),(4,2),(2,6),(2,4),(2,2),(4,4),(6,8)

 

5.シャッフル後の起点リスト内の起点をfor文で先頭から順に抜き出して、その起点の座標から壁作りを行います。これを起点リスト内の全ての起点に行います。但し、壁の延長中現在の起点から伸ばしている壁繋がらない様にします。もし延長中の壁に囲まれて壁を伸ばせなくなった場合は、延長中の壁を全て破棄して最初の座標から再度壁作りを行います。

※延長不可になった時の延長中の壁が作り直しの対象で、既に壁として確定している箇所を作り直す必要はない

 

壁作りの詳細

5-1.起点の座標既に壁の場合何もせずに次の起点を抜き出します。

5-2.起点の座標通常の壁とは別「作成中の壁」として迷路マップリストに設定します。

5-3.延長可能リストを作成します。

5-4.起点の座標から上下左右に2マス離れた座標チェックし、「作成中の壁」でない場合は延長可能リストに追加します。

上下左右が全て「作成中の壁」の場合は「作成中の壁」を全て「通路」に戻して5-2から作り直します。

5-5.延長可能リストの中からランダムにひとつ選択して壁を延長する方向を決定します。

5-6.決定された方向1マス「作成中の壁」設定します。

5-7.決定された方向2マス目設定状況に応じて以下のどちらかの処理に分岐します。

5-7-1.「壁」の場合「作成中の壁」を全て「壁」に設定して、この起点からの延長を終了して次の起点を抜き出します。

5-7-2.「通路」の場合この座標を起点として5-2から繰り返します。

 

この5-1~5-7の処理を起点リストの全ての起点に行う迷路が完成します。

 

4でシャッフルした起点リストを使用して壁作りの具体的な進行例を挙げます。

※少々長いです

起点リスト:(2,8),(6,6),(4,8),(4,6),(6,2),(6,4),(4,2),(2,6),(2,4),(2,2),(4,4),(6,8)

※0~11の計12か所

 

1.起点リスト(0)の(2,8)を起点とし、「作成中の壁」(緑のマス)とする。

 

2.上下左右の2マス先を調査し、「作成中の壁」でない場合延長可能リストに追加する。

(0,8),(4,8),(2,6),(2,10)延長可能リストに追加

 

3.延長可能リストからランダムで延長方向を選択する。

(4,8)選択されたことにする

 

4.選択した方向1マス(3,8)を「作成中の壁」にする。

 

5.延長先(4,8)「通路」なので、(4,8)起点とし「作成中の壁」とする。

 

6.上下左右の2マス先を調査し、「作成中の壁」でない場合延長可能リストに追加する。

(6,8),(4,6),(4,10)延長可能リストに追加

 

7.延長可能リストからランダムで延長方向を選択する。

(4,10)選択されたことにする

 

8.選択した方向1マス(4,9)を「作成中の壁」にする。

 

9.延長先(4,10)「壁」なので、「作成中の壁」を全て「壁」にする。

 

10.起点リスト(1)の(6,6)を起点とし、「作成中の壁」とする。

 

11.同様の流れで矢印の順「壁」まで進む。

 

12.延長先(6,10)「壁」なので、「作成中の壁」を全て「壁」にする。

 

13.起点リスト(2)の(4,8)は既に「壁」なので、何もしない。

 

14.起点リスト(3)の(4,6)を起点とし、「作成中の壁」とする。

 

15.同様の流れで矢印の順に進むと、「作成中の壁」に囲まれて延長不可になる。

 

16.今回作成した「作成中の壁」を全て「通路」に戻し、再度(4,6)「作成中の壁」とする。

 

17.(4,6)から作り直して、矢印の順「壁」まで進む。

 

18.「作成中の壁」を全て「壁」にする。

 

19.起点リスト(4),(5),(6)はいずれも既に「壁」なので、何もしない。

 

20.起点リスト(7)の(2,6)を起点とし、「作成中の壁」とする。

 

21.矢印の順「壁」まで進む。

 

22.「作成中の壁」を全て「壁」にする。

 

23.起点リスト(8),(9),(10),(11)はいずれも既に「壁」なので、何もしない。

 

24.全ての起点を処理し終えたので迷路が完成

 

この様な流れで迷路が作成されます。

 

Googleドキュメントに載せてあるソースには迷路の再作成簡単に行える様に右クリック新規の迷路を作る様にしてあります。

 

以上です。

テトリスをレトロゲームエンジンpyxelで作ってみました。

ブロックと壁pyxelのリソースエディタで作成しています。

文字日本語フォントで出力しています。

 

pyxelの機能でgifを作ってみました。

 

 

ソースはGoogleドキュメントに載せてあります。

テトリスソース(Googleドキュメント)

 

テトリス作成の事前検証を、検証01、検証02で行っているので、ソースの説明はそちらを参考にしてください。

 

 

 

 

 

 

 

 

 

概要です。

落ちてくるブロックを操作して壁の中に配置していき、1行(幅10マス)をブロックで隙間なく埋めるその行が消えますひとつでも隙間があると行が消えずブロックが積み上がっていきます

ブロックが上まで積み上がるゲームオーバーになります。

 

・ゲーム画面

 

 

 

操作説明

ブロックの移動操作

 

ブロックの回転操作

 

※ブロックの操作はマウスでも行えます。

左右の移動→マウスホイール

下に移動→右ボタン(押し続けると落ち続けます)

回転→左クリック

 

 

・リソース(144*48)

リソースはブロックと壁と空間(何もない部分)になります。

上段は左から、操作ブロック1マス分固定化ブロック1マス分左右壁下端壁左下角壁右下角壁です。

中段ブロックの色で、左の黒はブロックなし用です。

ブロックの色ブロックの下に置いて透過させて使用します。

下段の白い四角はゲームオーバー表示縁線用です。

 

 

・ブロックの種類

4マスブロック:7種類

5マスブロック:18種類

3マスブロック:2種類

通常4マスブロックが出現しますが、11回に1回だけ5マスブロックまたは3マスブロックが出現します

 

 

・ゲームオーバー画面

 

初めからやり直す場合 → 左クリックまたはENTERキー押下

終了する場合 → ウィンドウの×ボタンまたはESCキー押下

 

以上です。

ブロック移動処理

マウスホイールの操作および対応するキー押下操作ブロック座標を変更します。

移動する前の座標を保存しておいて、移動後に後述のブロック重なりチェックFalseが返された場合は移動前の座標戻します

 

ブロック回転処理

左クリックまたはスペースキー押下ブロックを回転させます。

移動と同様に、回転前の向きを保存しておいて、回転後に後述のブロック重なりチェックFalseが返された場合は回転前の向き戻します

 

ブロック変更

右クリックまたはzキー押下でブロック型を変更します。

ブロック変更時初期表示位置に戻ります。

 

ブロック重なりチェック

操作ブロックの移動(落下も含む)または回転によって操作ブロック固定化ブロック(または)が両方存在するマスが発生した場合はブロックが重なったことになるので、行われた動作をキャンセルします。

 

このテストプログラムでは落下処理が存在しないので、手動の移動回転で発生します。

-ソース(一部抜粋)------------------------------------------------------

    def chkbox(self):   #ブロック重なりチェック

        chkflg=True #重なりチェックフラグ初期化

        for j in range(self.l[self.typ][2]):

            for i in range(self.l[self.typ][2]):

                if self.l[self.typ][3+self.set][j][i]=="1":     #ブロックあり

                    if self.lbox[self.by+j][self.bx+i]>=1:      #ブロックが壁と重なる場合

                        chkflg=False    #変更中止

                        break

            if chkflg==False:

                break

        return chkflg

-------------------------------------------------------

操作ブロックブロック定義が「1」のマスと固定化ブロック配置管理用リスト(ブロックのある場所には色(1~7)が設定されている)をチェックして、両方ブロックが存在する場合に戻り値をFalseにして返します。

 

描画処理

固定化ブロック操作ブロックをそれぞれ描画しています。

また、内部変数(確認用)と操作説明も描画しています。

 

以上です。