前往
大廳
主題

【 RPG Maker MZ】 戰棋移動研究

蜜糖情人 | 2023-05-10 01:23:55 | 巴幣 0 | 人氣 384

主席說要研究做戰棋遊戲
聽到只有興奮二字XD
只是沒想到光是一個移動就搞半天
然後只要研究到這邊就好QQ
先筆記起來省的要用又忘了

先上成品
多虧RPGMaker-Games的Discord群
這次靈感跟解法都是靠大佬支援的

我的預想原本是,看滑鼠點擊位置跟物件距離
距離內即可移動
這個不難,不外乎就是畢氏定理搞定
但出來的結果就是很完整的菱形
類似上圖,範圍內他都會走
如果碰到如圖,中間有無法穿越的障礙物
那就會完全卡死(且理論上步數4的情況是到不了的)
所以勢必要改成及時判定的

第二次的構想是,算出滑鼠點與物件的最短路徑
然後用步數判定是否可以移動
但這個又要靠 A*搜索算法 (A* search algorithm)
簡單來說,不會Orz

所以最後大佬說,那就逐步判定,直到步數用盡
這個倒是簡單,For迴圈能搞定的都不是事
可問題在,我要怎麼去做每一次步數範圍的標記
最後大佬給了一個語法
$dataMap.data[((5*$dataMap.height+y)*$dataMap.width+x)]=n;
我不是很懂運作方式
感覺上應該是把地圖X Y的地區ID改成n,寫入暫讀
這個暫讀只要畫面有動,包含叫出F9視窗/功能視窗/角色轉跳這類
都會清空

最後我決定做法如下:
1.判定我選的事件,所在座標地區ID改成1
2-a.全地圖判斷座標,看該座標地區ID是否為1
2-b.如果是,則判斷該座標上/下/左/右是否可走
  如果可以,就把該格座標地區ID改成2
2-c.以上的步驟跑步數次數
3.判定滑鼠點座標地區ID是否可以走,若可以就移動


預先設定:
一開始行動為1時,滑鼠點取事件
滑鼠地圖座標事件1座標,代表選擇了事件0
$gameMap.events()[0].x==$gameVariables.value(1) && $gameMap.events()[0].y==$gameVariables.value(2)
這邊有一個預設的變數1跟2,分別儲存了滑鼠的地圖座標
而事件座標讀取語法為 $gameMap.events()[n-1].x
n是事件編號,因此若我選取的是事件1,則[ ]中間就是1-1=0

若選取了事件1,則選定人物(變數22)=0,方便後面應用
而人物行動改成1,進入下一個階段


1:事件座標地區ID改成1
先確認選定的是這個事件
若是,將這個事件座標的地區ID改成1
$dataMap.data[((5*$dataMap.height+$gameMap.events()[$gameVariables.value(22)].y)*$dataMap.width+$gameMap.events()[$gameVariables.value(22)].x)]=1;
這邊一個小重點,剛剛提過事件座標為$gameMap.events()[n-1].x
而上面設的變數22,就是直接帶入取代n-1的部分
這樣如果複製了其他角色,就只要改變數22,就能用了
之後距離監測(變數23)=1,這個基本上就是預設的地區ID
行動值(變數24)=4,代表這個角色可以移動4格

2:全地圖偵測判定可行動範圍
接下來進入迴圈
for(x=0;x<=40;x++){
for(y=0;y<=22;y++){
if($gameMap.regionId(x, y)==$gameVariables.value(23)){

for(j=x-1;j<=x+1;j++){
if($gameMap.regionId(j, y)==0){
$dataMap.data[((5*$dataMap.height+y)*$dataMap.width+j)]=$gameVariables.value(23)+1;
}}
for(j=y-1;j<=y+1;j++){
if($gameMap.regionId(x, j)==0){
$dataMap.data[((5*$dataMap.height+j)*$dataMap.width+x)]=$gameVariables.value(23)+1;
}}

}}}
這邊分成三區
藍色這區,是偵測地圖上所有格子
因為我的地圖是40X22格,因此X跑40次,Y跑22次
去偵測每一格的地區ID是不是=1(變數23)
if($gameMap.regionId(x, y)==$gameVariables.value(23))

橘色這區
從上面的判定,我抓到了座標x y 的這格是角色所在
因此就要判斷它左/右是否可以走
而因為是左右,所以基本上是座標x-1、x、x+1三格
因此迴圈從 x-1跑到x+1
for(j=x-1;j<=x+1;j++){

這邊我預先把不能走,就是有障礙物的地方,地區ID改成51了
所以地圖上可以走的地方地區ID=0
因此要先判斷地區ID是不是=0
if($gameMap.regionId(j, y)==0){

如果=0表示可以走,那就把那一格的地區ID改成2
$dataMap.data[((5*$dataMap.height+y)*$dataMap.width+j)]=$gameVariables.value(23)+1;
}}
這邊一個小重點
因為如果把可行動的地區ID也改成1
多重判定的情況會無限延伸
所以我是把它改成2,避免在這個迴圈中一路延伸出去
因此語法中,我改成變數23+1

綠色這塊其實一樣,就只是Y的判定
所以迴圈變數j就是從位置x改成y
一開始我寫成一起的,結果因為x y一起延伸
會變成正方形8格,而不是十字4格
(這邊我卡超久Orz)

最後這一個迴圈跑完,就等於地圖掃完一次
而因為我們這次偵測是把可以走的地區ID改成2
因此我把變數23+1,這樣下一次迴圈偵測時
就會去找這次行動可走的地方去偵測上/下/左/右

至於這個迴圈要跑幾次,就看移動值決定
因為監測距離從1開始,且每次跑完一輪都會+1
所以我直接拿監測距離計算圈數
若監測距離>步數值,那就斷開迴圈

3:顯示可行動範圍
跑完迴圈之後,可以得到從事件為中心點向外擴散的可行動範圍
按距離地區ID分別為1~5
var k=1;
for(x=0;x<=40;x++){
for(y=0;y<=22;y++){
if($gameMap.regionId(x, y)>0 && $gameMap.regionId(x, y)<50){
$gameScreen.showPicture(k, '移動範圍1', 0, x*48, y*48+12, 100, 100, 255, 0);
k=k+1;
}}}
橘色的部分是圖片ID,從1開始
進入迴圈,紫色部分是全地圖判定
若該座標x y的地區ID大於0且小於50(51是障礙物)
則該座標顯示圖片,也就是48X48的滿格50%紅
圖片座標是座標x y*48,y感覺有點偏所以+12

如此就完成整個可行動範圍判定跟顯示
最後進入下一階段

4:角色移動
若滑鼠按下,先確定該格座標地區ID是否大於0,且小於50
如果是,事件X、Y(變數5、6) = 滑鼠X、Y
$gameMap.regionId($gameVariables.value(1),$gameVariables.value(2))>0 && $gameMap.regionId($gameVariables.value(1),$gameVariables.value(2))<50
並且進入下一階段

這邊讓事件移動到滑鼠選擇的位置
用了語法 this.moveTowardCharacter({x:n, y:n})
n就是要移動到哪個座標,也就是上一步設定的變數5、6
this.moveTowardCharacter({x:$gameVariables.value(5), y:$gameVariables.value(6)})
並且判定若事件座標=目標座標(變數5、6)
$gameMap.events()[$gameVariables.value(22)].x==$gameVariables.value(5) && $gameMap.events()[$gameVariables.value(22)].y==$gameVariables.value(6)
如果是,表示事件已經移動完成
那就把圖片淨空,並且把行動改回0,回到最初

另外這邊有個步驟,是玩家瞬移
主要是淨空剛剛設定的地區ID
這個瞬移不會有轉場,所以看不出來


以上完成,不過這邊還有一點要處裡
1.因為事件要選定了才會轉地區ID為1,不然也是0
但如果這樣兩個角色會卡住
這也不難解決,就是要多個地區ID的設定
我目前想到的是
若選定人物不等於自己的事件,就把地區ID改成51
2.我目前是點選事件才改選定人物的變數
那就會必須要每複製一個事件都要多改一次一開始判定事件座標
這個要再想想能不能改得更方便一點
例如判定滑鼠座標格是不是有事件,並返回事件ID
不過因為主席說先這樣就好,這部分就等真的要開工再做

創作回應

相關創作

更多創作