【ウディタ】ブロックパズル作りの基礎

<注釈>

・ウディタ Ver2.281で実施
・中身はザックリで、備忘録的なものです
・記事を読む前提条件として下記の辺りが対象
 > コモンイベントをそこそこ自作できる
 > テトリスとかのパズルのイメージが分かる
・正規のやり方などは知りません。独力です。

<概要>

ポリオミノと呼ばれる形式のパズルについて
ある程度の形はできたので記事にしとく。

ここで扱っているのは
ペントミノ(5マスブロック)です。
※有名なテトリスはテトロミノ

作ってたゲーム環境は下記。

マウス操作のみに対応
1個の4マス四角ブロックと
12種のブロックを回転・反転をして
8×8の正方形を完成させるゲーム

下記呼称を使います。
手持ちのブロック:ハンド
受け皿の箱型:ボックス

ここで扱う処理は下記になります。
・ハンドを回転する処理の考え方
・ハンドを反転する処理の考え方
・ハンドを置くときの判定

<事前準備>

可変DBを用意します。
・ボックスは8×8のサイズ
・ハンドは5×5のサイズ
※ハンドは使わないDB区画もあります。
ここでは2つのDB構造を例に出します。

<①データIDと項番で作る可変DB>

最もオーソドックスなDBを扱う方法。
初期値は空欄を示す値などにしましょう

①データIDと項番で作る可変DB

<②項番だけで作る可変DB>

少し特殊ですが10×10サイズまでなら
データ1つの枠で作ることができます。

②項番だけで作る可変DB

Xが10の桁で、Yが1の桁として考えます。
例えば、X=5 , Y=8 の場合、ID:58を参照する。
Xを10倍して、それにYを足せばIDになります。

8×8サイズなら、88番まで
タイプ設定で作りましょう。
(0~7でやるなら77番まで)

上図では、タイプ設定で初期値を
 空欄を示す値=ー1
 未使用欄=99
 ブロックID=0~(最大98、扱うブロック種類による)
として設定してます。

ちなみに未使用欄は他用途に使うことも可能です
※例外処理などで省いたりする必要はある

<ブロックを描写>

正方形の1マス画像を用意する。
または、<SQUARE>で描いてもOKです。
1タイル 40pxサイズで作るなど
タイルの大きさを決めておきましょう。

説明をかなり省きますが
ボックスは普通にマス目状にピクチャ表示するだけ。
ハンドブロックはマウス追従するようにします。

ブロックを描写

ボックス部分…8×8のDBからブロック情報を参照して描写
ハンド部分…5×5のDBから形状を参照して描写

ハンドのDB値と形状の対比図

ハンドブロックの生成時は
エフェクトの描画座標シフトでXY移動させると
形を崩さず追従させ やすいです。

▼ハンドブロック生成のサンプル

▼ セルフ変数の初期化 ▼
■変数操作: CSelf51[最小ピクチャ番号] = 25000 + 0 
■変数操作: CSelf50[現在ピクチャ番号] = CSelf51[最小ピクチャ番号] + 0 
▼ ブロック生成開始 ▼
■変数操作: CSelf31[一時変数X] = 0 + 0 
■回数付きループ [ 5 ]回
 |■変数操作: CSelf32[一時変数Y] = 0 + 0 
 |■回数付きループ [ 5 ]回
 | |▼ ここでDBから形状をチェック ▼
 | |■変数操作: CSelf40[DB項番] = CSelf31[一時変数X] * 10 
 | |■変数操作: CSelf40[DB項番] += CSelf32[一時変数Y] + 0 
 | |■DB読込(ユーザ): CSelf20[DBチェック] = ユーザDB[ ブロック形状 : CSelf0[ブロック形状ID] : CSelf40[DB項番] ]  (5 : - : -) 
 | |■条件分岐(変数):  【1】 CSelf20[DBチェック]  が   0 以上 
 | |-◇分岐: 【1】  [ CSelf20[DBチェック]  が  0 以上  ]の場合↓
 | | |■変数操作: CSelf53[X座標] = 40 * CSelf31[一時変数X] 
 | | |■変数操作: CSelf54[Y座標] = 40 * CSelf32[一時変数Y] 
 | | |■ピクチャ表示:CSelf50[現在ピクチャ番号] [中心]ウィンドウ「<SQUARE>」サイズ[40,40] X:0 Y:0 / 0(0)フレーム  / パターン 1 / 透 255 / 通常  / 角 0 / 拡 100% / カラー R[100] G[100] B[100]
 | | |▼ ここで座標シフト ▼
 | | |■ピクチャエフェクト:CSelf50[現在ピクチャ番号] [描画座標シフト] Xシフト CSelf53[X座標] / Yシフト CSelf54[Y座標] (0)フレーム
 | | |■変数操作: CSelf50[現在ピクチャ番号] += 1 + 0 
 | | |■
 | |◇分岐終了◇
 | |■変数操作: CSelf32[一時変数Y] += 1 + 0 
 | |■
 |◇ループここまで◇◇
 |■変数操作: CSelf31[一時変数X] += 1 + 0 
 |■
◇ループここまで◇◇
▼ ブロック追従処理
■ループ開始
 |■変数操作+: CSelf53[X座標] = マウスX座標
 |■変数操作+: CSelf54[Y座標] = マウスY座標
 |■ピクチャ移動:CSelf50[現在ピクチャ番号] ~ CSelf51[最小ピクチャ番号]  X:CSelf53[X座標] Y:CSelf54[Y座標] / 0(0)フレーム  / パターン 同値 / 透 同値 / 表示形式:同値  / 角 同値 / 拡 同値 / カラー 同値
 |■ウェイト:1 フレーム
 |■
◇ループここまで◇◇
■

あとで処理を作る際に、マウス座標を元に
ボックスの座標を取得することになる。
最初はボックスピクチャを0:0座標に表示しておくか
ボックスの始点座標を把握しておく。

<①ハンドを回転させる>

右クリックをしたときに
ハンドブロックを時計回り(右回り)に回転させること
を想定して話を進めます。

回転させるのに、処理的にも負荷的にも楽なのは
形状を先にUDBへ登録してしまうこと。
仮に5×5のブロックであるなら
25×4=100となり、
ウディタのDB項番最大値ギリギリ可能です。
 ID  0~24:   0度の回転
 ID 25~49: 90度の回転
 ID 50~74:180度の回転
 ID 75~99:270度の回転

イメージがわかない場合は図を紙に描いて回転させてください。

プログラム側で済ませたい場合は
値を90度右回転させることをイメージしましょう。

「UDBに登録した形状」のDBイメージ

上記イメージでは2進数(0と1)で形状を表しています。

<②ハンドを反転させる>

右クリックをしたときに
ハンドブロックを時計回り(右回り)に回転させるが
1周したら反転させて表示する

を作っていることを想定して話を進めます。

簡単に結論を言えば、
通常表示のX座標をマイナス方向にする
と反転表示になります。
これも紙に描いて反転させて(透かして)
見ればイメージしやすいです。

ハンドブロックの反転イメージ

▼ハンドブロックを描写のサンプルコード

■変数操作: CSelf12[一時変数X] = 0 + 0 
■回数付きループ [ 5 ]回
 |■変数操作: CSelf13[一時変数Y] = 0 + 0 
 |■回数付きループ [ 5 ]回
 | |■DB読込(ユーザ): CSelf20[DBチェック] = ユーザDB[ パズル形状 : CSelf60[現在パズル形状_ID] : CSelf10[一時変数A] ]  (7 : - : -) 
 | |■条件分岐(変数):  【1】 CSelf20[DBチェック]  が   1 と同じ 
 | |-◇分岐: 【1】  [ CSelf20[DBチェック]  が  1 と同じ  ]の場合↓
 | | |■ピクチャ表示:CSelf70[現在PAZ_P番号] [中心]ウィンドウ「<SQUARE>」サイズ[CSelf62[所持タイルの大きさ],CSelf62[所持タイルの大きさ]] X:0 Y:0 / 0(0)フレーム  / パターン 1 / 透 0 / 通常  / 角 0 / 拡 100% / カラー R[CSelf57[RED]] G[CSelf58[GREEN]] B[CSelf59[BLUE]]
 | | |■変数操作: CSelf53[X座標] = CSelf12[一時変数X] * CSelf42[1タイルの大きさ] 
 | | |■変数操作: CSelf53[X座標] *= CSelf65[反転判定] + 0 
 | | |■変数操作: CSelf54[Y座標] = CSelf13[一時変数Y] * CSelf42[1タイルの大きさ] 
 | | |■可変DB書込:DB[ ハンドブロック状態 : CSelf13[一時変数Y] : CSelf12[一時変数X] ]  (30 : - : -) =  CSelf60[現在パズル形状_ID]
 | | |■ピクチャエフェクト:CSelf70[現在PAZ_P番号] [描画座標シフト] Xシフト CSelf53[X座標] / Yシフト CSelf54[Y座標] (0)フレーム
 | | |■変数操作: CSelf70[現在PAZ_P番号] += 1 + 0 
 | | || |◇分岐終了◇
 | |■変数操作: CSelf10[一時変数A] += 1 + 0 
 | |■変数操作: CSelf13[一時変数Y] += 1 + 0 
 | ||◇ループここまで◇◇
 |■変数操作: CSelf12[一時変数X] += 1 + 0 
 |■
◇ループここまで◇◇

上記では、CSelf65:反転判定(1 or -1)を使って
X座標だけピクチャエフェクトで表示位置をずらしています。

マイナスにするのはY座標でも問題ないですが
どちらかと言えば
X座標をいじる方が使いやすいかなと思います。
(画面は横長なので)

<③ハンドを置くときの判定>

まずは何も回転させてないピース状態から
考えていくのがいいと思います。

置いたハンドブロックとボックスの図

ハンドブロックは最大5x5なので
ループで簡単に処理できます。

ボックスのどこに座標=マス目があるかを把握して
そこを基点に形状を照合しましょう。

【処理の流れは下記】
①ハンドブロックをチェック
②ブロックがあるマスなら、ボックスをチェック
③ボックスに何かある=衝突するなら処理終了
④5x5マスを見てハンドとボックスが衝突しないなら設置OK

次は逆表示も含めて
実際に組んだコモンの設定とコード

クリックした地点のXY座標
コモンイベント呼び出し時に入力しています。
CSelf2の逆表示には、{1 or -1} が入力されます。

ハンドブロック形状は先に
"ハンドピース状態"という名前のCDBに登録済みの状態。

CSelf3はボックスに登録するときに使う識別IDです。

 |■変数操作: CSelf12[一時変数X] = 0 + 0 
 |■変数操作: CSelf32[一時XX] = 0 + 0 

 |■回数付きループ [ 5 ]回
 | |■変数操作: CSelf13[一時変数Y] = 0 + 0 
 | |■回数付きループ [ 5 ]回
 | | |■DB読込(可変): CSelf20[DBチェック] = 可変DB[ ハンドピース状態 : CSelf13[一時変数Y] : CSelf12[一時変数X] ]  (31 : - : -) 
 | | |■条件分岐(変数):  【1】 CSelf20[DBチェック]  が   0 以上 
 | | |-◇分岐: 【1】  [ CSelf20[DBチェック]  が  0 以上  ]の場合↓
 | | | |■変数操作: CSelf25[DBボックス座標] = CSelf32[一時XX] + 1 
 | | | |■変数操作: CSelf25[DBボックス座標] += CSelf0[X座標] + 0 
 | | | |■変数操作: CSelf25[DBボックス座標] *= 10 + 0 
 | | | |■変数操作: CSelf25[DBボックス座標] += CSelf13[一時変数Y] + 1 
 | | | |■変数操作: CSelf25[DBボックス座標] += CSelf1[Y座標] + 0 

 | | | |■条件分岐(変数):  【1】 CSelf25[Dマップ座標]  が   100 以上  【2】 CSelf25[Dマップ座標]  が   10 以下 
 | | | |-◇分岐: 【1】  [ CSelf25[Dマップ座標]  が  100 以上  ]の場合↓
 | | | | |■変数操作: CSelf99[結果] = 1 + 0 
 | | | | |■イベント処理中断
 | | | | |■
 | | | |-◇分岐: 【2】  [ CSelf25[Dマップ座標]  が  10 以下  ]の場合↓
 | | | | |■変数操作: CSelf99[結果] = 1 + 0 
 | | | | |■イベント処理中断
 | | | | || | | |◇分岐終了◇

 | | | |■DB読込(可変): CSelf21[接触チェック] = 可変DB[ ボックス : 現在編集中 : CSelf25[DBボックス座標] ]  (29 : 0 : -) 
 | | | |■条件分岐(変数):  【1】 CSelf21[接触チェック]  が   0 以上 
 | | | |-◇分岐: 【1】  [ CSelf21[接触チェック]  が  0 以上  ]の場合↓
 | | | | |■変数操作: CSelf99[結果] = 1 + 0 
 | | | | |■イベント処理中断
 | | | | |■
 | | | |◇分岐終了◇
 | | | |■
 | | |◇分岐終了◇
 | | |■変数操作: CSelf13[一時変数Y] += 1 + 0 
 | | || |◇ループここまで◇◇
 | |■変数操作: CSelf12[一時変数X] += 1 + 0 
 | |■変数操作: CSelf32[一時XX] += CSelf2[逆表示?] + 0 
 | ||◇ループここまで◇◇

※接触時:-1 / 未接触:0をそれぞれ返します

まず CSelf32[一時XX] について
ハンドの表示は反転しているものの
ハンドの可変DBは無反転なので
ボックスを反転参照させるためのものです。

ここは少しややこしいですが
ハンドピースを参照するXYと別々に使っています。

DBボックス座標は
可変DBの1つのデータに0~99の項番で用意。
実際には項番11~88で、XY座標分を使用。
※条件分岐でイベント処理中断を仕込んでますが
 10以下は特殊な値で使用、100以上はエラー参照の防止弁
 なのであまり気にしないでください。

チェックさえ通れば、同じ処理で
ボックスに1以上のIDを入れるだけなので
登録処理も同じコモンで済ますことができます。

<今回内容のサンプルコモン>

マウスとキーボード操作が必要になる代物で
操作統一性を得るには
自力その部分のコモンは作る必要があります。
※公序良俗に反しない限り自由にご使用可能です

この記事が気に入ったらサポートをしてみませんか?