2018年 5月18日
やっと少し形になってきたので、途中だがいったん報告する。
その前に、やっぱり始めから複雑なゲームを作りすぎたと後悔してる。
戦闘要素と戦略要素とでは全く別のゲームをそれぞれ作るようなものなのだと分かったので、やはり初心者は 1ジャンルゲーム要素のシンプルなものを作るように心がけた方が良いと思う。
例えば戦略ゲームにしても、もっと 1マップボードゲームのような単純なものから練習した方が良かったろう。
始めから複雑なものを作り過ぎたか。
戦闘も戦略もそれぞれ 1マップゲームから作って、両方慣れたら合わせて複雑なもの、という手順が良いだろう。
今の自分の状況で 1年以上も 1作に費やすのは時間的にもちょっと厳しい。
まずマップ戦略として何をするかだが
1、持ってる国のユニットの配備を全解除、全ユニットの持ってる装備を解除
2、ユニットの筋力と魔力と総力の順列を作る、各種アイテムの能力の順列を作る
3、隣接する国の勢力値を評価
4、それを基にユニットを配置、合わせてアイテムを装備
これらをどうプログラムでやるか。
そしてサラッと書いてるが、これだけのアルゴリズムを考えるだけでも結構時間がかかった。
やり方としては、ユニットもアイテムも出現時に適当に配置して後は変えない、ないし最小限に配置換えだけする、というようなものにすれば時間もメモリも短縮できると思うが、ゲームとしてはぬるい。
まず解除のプログラム
; 配備、装備等の解除 ------------------------------ #deffunc pmu_rst int pmu_rstn ; ヒーロー国ユニット配置解除 pn=pmu_rstn ; ヒーローNo. repeat 25,1 : kn=cnt if mpl(kn)!pn : continue ; 自領では無い mug=kn*10 ; データ先頭 repeat 10 if mu(mug+cnt)=0 : continue ; 配属されて無い un=mu(mug+cnt) : ug=un*udb : ud(ug+13)=0 ; 配属解除 mu(mug+cnt)=0 ; 領主、部隊解除 loop loop return #deffunc nmu_rst int nmu_rstn ; 中立国ユニット配置解除 kn=nmu_rstn ; 中立国No. mug=kn*10 ; データ先頭 repeat 10 if mu(mug+cnt)=0 : continue ; 配属されて無い un=mu(mug+cnt) : ug=un*udb : ud(ug+13)=0 ; 配属解除 mu(mug+cnt)=0 ; 領主、部隊解除 loop return #deffunc peq_rst int peq_rstn ; ヒーロー勢力ユニット装備解除 pn=peq_rstn ; ヒーロー勢力No. pug=(pn-1)*pub ; データ先頭 repeat pub if pud(pug+cnt)=0 : continue ; 配属されて無い un=pud(pug+cnt) : ug=un*udb ; ユニットNo. repeat 7 in=ud(ug+40+cnt) if in=0 : continue ig=in*idb : id(ig+13)=0 ; 所持解除 ud(ug+40+cnt)=0 ; 装備解除 loop repeat 5 : ud(ug+21+cnt)=ud(ug+1+cnt) : loop ; 基礎値 repeat 2 : ud(ug+11+cnt)=ud(ug+21) : loop ; 基礎攻防値 repeat 2 : ud(ug+14+cnt)=ud(ug+22) : loop ; 魔攻、魔防値 repeat 6 : ud(ug+31+cnt)=0 : loop ; 属性値リセット loop return #deffunc neq_rst int neq_rstn ; 中立国ユニット装備解除 kn=neq_rstn ; 中立国No. mug=kn*10 ; データ先頭 repeat 10 if mu(mug+cnt)=0 : continue ; 配属されて無い un=mu(mug+cnt) : ug=un*udb ; ユニットNo. repeat 7 in=ud(ug+40+cnt) if in=0 : continue ig=in*idb : id(ig+13)=0 ; 所持解除 ud(ug+40+cnt)=0 ; 装備解除 loop repeat 5 : ud(ug+21+cnt)=ud(ug+1+cnt) : loop ; 基礎値 repeat 2 : ud(ug+11+cnt)=ud(ug+21) : loop ; 基礎攻防値 repeat 2 : ud(ug+14+cnt)=ud(ug+22) : loop ; 魔攻、魔防値 repeat 6 : ud(ug+31+cnt)=0 : loop ; 属性値リセット loop return
このまま動くかどうか自信が無いから、後で検証しながら調整するようかな。
どうやってもバグはまずある。
次に能力事の順列だが、その前にそれらの配列変数をどう用意してどう使うか、それを思考錯誤してたのでその説明から。
まずデータの設定は今の所次のようになった。
; ユニットデータ *unit_syoki pubk=10 ; 国の人数 pubc=20 ; 城の人数 pubs=20 ; 人材府の人数 pubsb=5 ; 〃の最大数 pub=pubk*25+pubc+pubs*pubsb ; プレイヤーのユニットデータ数 hub=9*25 ; ヒーローの順列データ数 nub=10 ; 中立のユニットデータ数 ub=plb*pub+nub*25+10; ユニットの最大数 udb=60 ; 1ユニットのデータ量 dim ud,ub*udb+1 ; ユニットデータ dim hr1,plb*hub+1 ; ヒーローの筋力順列 dim hr2,plb*hub+1 ; ヒーローの魔力順列 dim hr5,plb*25+1 ; ヒーローの総力順列 dim nr1,25*nub+1 ; 中立の筋力順列 dim nr2,25*nub+1 ; 中立の魔力順列 dim nr5,25*nub+1 ; 中立の総力順列
pubk 1国の養える最大人数 × 25最大国数 + pubc首都城の養える人数 + pubs建設で建てられる人材府の人数 × pubsb建てられる最大の数。
10 × 25 + 20 + 20 × 5 = 370
だから、今の所ヒーロー 1勢力の最大数は 370人としている。
中立は攻め込まず国を増やさないので、配置最大数の 10人で良い。
10 × 25国 = 250人だけ全部で用意する。
ユニットの最大データ数 = ヒーローの数 × 370 + 中立 250だ。
今の所 7ヒーローでテストしてるから、それなら 2840人がユニットデータ数、もし 25ヒーロー数なら中立+250も足して 9500人が最大数だ。
これに 1ユニットのデータ数 60がかかるから、変数の量は 570000、前回やったバイト数はこの 4倍だから 2280000バイト、2.3MBほどかな。
う~ん 2.3MBならたいした事ないか・・・。
これもやり方としては、データの取得だけ 2000人とかだけにして、そこから処理毎に各ヒーローや中立のユニットを拾って処理する、という風にすればメモリの使用量を少なく出来ると思う。
ただその場合速さが犠牲になるので、なぜ全部使用すると思えない 370固定にするのかと言うと、専用の変数を持つ事によって処理を早くする狙いから。
さて 2000くらいの計算なら今のコンピューターならさして問題ないのかもしれないけど、1ターンに 1国〃毎に処理して、しかも順列の要素事だったりだとするとさすがに遅くなるのではないか、と考えた。
この辺は本当は実際にやってみないと分からないので、あるいは無駄な考えであった可能性もある。
それとこの方が変数の扱いの構造を単純にできるので、単純化してプログラムをなるべく簡単にしないと作れるかどうか自信が無い。
例えば登録総数で 2000を超えたとして、どの勢力のどのユニットから何の優先順位で消していけば良いのか?
これだと始めに多くユニットを作った勢力が有利という事になるし、あとから勢力が縮んだりしたら数の調整はどうするのか?
とにかくも 1つ 370固定で専用の領域を持っていた方が単純で扱いやすいと考えた訳だ。
それから次の工夫が、筋力や魔力、総力(筋力、魔力、知力、魅力の総計)の順列だ。
これまた 1ターンに各国それぞれ再計算していたのでは時間がかかる。
特にソート(順列)計算は難しいプログラム理論を知らないと時間のかかるものだと思う。
そこで、こちらはあらかじめ専用の配列変数を用意しておき、ユニットの出現時にソート配置を済ませてしまう、という手法を考えた。
そのための配列変数がこれになる
dim hr1,plb*hub+1 ; ヒーローの筋力順列
dim hr2,plb*hub+1 ; ヒーローの魔力順列
dim hr5,plb*25+1 ; ヒーローの総力順列
dim nr1,25*nub+1 ; 中立の筋力順列
dim nr2,25*nub+1 ; 中立の魔力順列
dim nr5,25*nub+1 ; 中立の総力順列
数 hub = 225だが、これは 1国の部隊配置最大 9人 × 25国分あれば足りるからだ。
中立の場合は 10人で良い、どうせ 10人以上増やさない。
この時のソート配置プログラムはこれ
; ステータスの順列 ------------------------------ #deffunc hper_set int hper_setn1,int hper_setn2 ; ヒーローの順列 pn=hper_setn1 ; ヒーローNo. un=hper_setn2 ; ユニットNo. hug=(pn-1)*hub ; データ先頭 un1=un : ug1=un1*udb : n1=ud(ug1+1) ; 筋力1 un2=hr1(hug+hub) : ug2=un2*udb : n2=ud(ug2+1) ; 筋力2 if n1>n2 { ; 最後尾より大きい repeat hub ; 筋力の順列 n=hug+cnt if hr1(n)=0 : hr1(n)=un1 : break ; 空白なら登録して終わり un2=hr1(n) : ug2=un2*udb : n2=ud(ug2+1) ; 筋力2 if n2<n1 : hr1(n)=un1 : un1=un2 : n1=n2 ; 入れ替え loop } un1=un : ug1=un1*udb : n1=ud(ug1+2) ; 魔力1 un2=hr2(hug+hub) : ug2=un2*udb : n2=ud(ug2+2) ; 魔力2 if n1>n2 { ; 最後尾より大きい repeat hub ; 魔力の順列 n=hug+cnt if hr2(n)=0 : hr2(n)=un1 : break ; 空白なら登録して終わり un2=hr2(n) : ug2=un2*udb : n2=ud(ug2+2) ; 魔力2 if n2<n1 : hr2(n)=un1 : un1=un2 : n1=n2 ; 入れ替え loop } hug=(pn-1)*25 ; データ先頭 un1=un : ug1=un1*udb : n1=ud(ug1+1)+ud(ug1+2)+ud(ug1+3)+ud(ug1+4) ; 総力1 un2=hr5(hug+25) : ug2=un2*udb : n2=ud(ug2+1)+ud(ug2+2)+ud(ug2+3)+ud(ug2+4) ; 総力2 if n1>n2 { ; 最後尾より大きい repeat 25 ; 総力の順列 n=hug+cnt if hr5(n)=0 : hr5(n)=un1 : break ; 空白なら登録して終わり un2=hr5(n) : ug2=un2*udb : n2=ud(ug2+1)+ud(ug2+2)+ud(ug2+3)+ud(ug2+4) ; 総力2 if n2<n1 : hr5(n)=un1 : un1=un2 : n1=n2 ; 入れ替え loop } return
中立の分は割愛。
その勢力の人数が何人であろうと、配置する分の順列があれば良い。
(例えば、そんなのも一つのひらめきと発明だった)
次はアイテムだが、これまた随分と悩んだ。
とりあえずまずデータ数から。
pibk=20 ; 国のアイテム数 pibc=50 ; 城のアイテム数 pibs=50 ; 倉庫のアイテム数 pibsb=5 ; 〃の最大数 pib=pibk*25+pibc+pibs*pibsb ; ヒーローのアイテムデータ数 hib=800 ; ヒーローアイテムの順列数 nib=80 ; 中立のアイテムデータ数 ib=pib*plb+nib*25 ; アイテムの最大数 idb=40 ; 1アイテムのデータ量 dim id,(ib+1)*idb ; アイテムデータ sdim is,80,ib ; 名前
pib = 1ヒーローの所持総数だが、これはユニット数と同じような形で、総数 800になってるが、後でゲームバランス的に調整するようかもしれない。
20000 + 2000 × 40データなので、880000個 × 4 = 3520000バイトだから、3.5MBくらいかな。
アイテム要素で問題なのが、どの隊列のユニットに何の装備をさせるのか、これは非常に頭の痛い問題だ。
これについてまだこれから調整がいるだろうが、とりあえず各キャラクラーの装備タイプという項目を足して、そのタイプ事に装備をしていかせる事にした。
そのプログラムはまだこれから作るのだが、それに対応する順列を作った。
n=10 ; ヒーローのアイテム順列 hib1=8*n : dim hip1,hib1*plb+1 ; 片手 80 hib2=3*n : dim hip2,hib2*plb+1 ; 両手 30 hib3=4*n : dim hip3,hib3*plb+1 ; 槍 40 hib4=3*n : dim hip4,hib4*plb+1 ; 棍棒 30 hib5=3*n : dim hip5,hib5*plb+1 ; 杖 30 hib6=5*n : dim hip6,hib6*plb+1 ; 弓銃 50 hib7=3*n : dim hip7,hib7*plb+1 ; 投射 30 hib8=4*n : dim hip8,hib8*plb+1 ; 盾 40 hib9=12*n : dim hip9,hib9*plb+1 ; 鎧 120 hib10=14*n : dim hip10,hib10*plb+1 ; アイテム 140 hib11=14*n : dim hip11,hib11*plb+1 ; 魔法 140 hib12=7*n : dim hip12,hib12*plb+1 ; 特殊 70 n=1 ; 中立のアイテム順列 nib1=8*n : dim nip1,nib1*25+1 ; 片手 8 nib2=3*n : dim nip2,nib2*25+1 ; 両手 3 nib3=4*n : dim nip3,nib3*25+1 ; 槍 4 nib4=3*n : dim nip4,nib4*25+1 ; 棍棒 3 nib5=3*n : dim nip5,nib5*25+1 ; 杖 3 nib6=5*n : dim nip6,nib6*25+1 ; 弓銃 5 nib7=3*n : dim nip7,nib7*25+1 ; 投射 3 nib8=4*n : dim nip8,nib8*25+1 ; 盾 4 nib9=12*n : dim nip9,nib9*25+1 ; 鎧 12 nib10=14*n : dim nip10,nib10*25+1 ; アイテム 14 nib11=14*n : dim nip11,nib11*25+1 ; 魔法 14 nib12=7*n : dim nip12,nib12*25+1 ; 特殊 7
順列総数 hub = 800というのは倉庫総数に合わせた数で、これはアイテム種類の所持割合総数を合わせるため。
つまり今の所、各種類の所持割合は 8の倍数で調整がつくようにしている。
たぶんユニット登録と違って、アイテムの登録はこの順列に乗らないものは登録されない、あるいは押し出し廃棄という運びとなると思う。
ザックリした所持方法だが、これ以上は処理時間的にもメモリ的にも自分の頭脳的にも(笑)過大だと今の所判断した。
いや、いらないアイテムをどの優先順位で廃棄するかだけでもサッパリ分からない難しい問題だと思う。
それではアイテムの順列のソースはこちら
; アイテムの順列 ------------------------------ #deffunc hiper_set int hiper_setn1,int hiper_setn2 ; ヒーローの順列 pn=hiper_setn1 ; ヒーローNo. in=hiper_setn2 ; アイテムNo. hig=(pn-1)*hib ; データ先頭 ; 片手武器 in1=in : ig1=in1*idb if id(ig1+16)=1 : if id(ig1+19)=1 or id(ig1+19)=4 or id(ig1+19)=5 { ; 片手、剣、斧、棍 hig1=(pn-1)*hib1 ; データ先頭 n1=id(ig1+11) ; 攻撃力1 in2=hip1(hig1+hib1) : ig2=in2*idb : n2=id(ig2+11) ; 攻撃力2 if n1>=n2 { ; 最後尾より大きい repeat hib1 ; の順列 n=hig1+cnt if hip1(n)=0 : hip1(n)=in1 : break ; 空白なら登録して終わり in2=hip1(n) : ig2=in2*idb : n2=id(ig2+11) ; 攻撃力2 if n2<n1 : hip1(n)=in1 : in1=in2 : n1=n2 ; 入れ替え loop } } ; 両手武器 in1=in : ig1=in1*idb if id(ig1+16)=2 : if id(ig1+19)=2 or id(ig1+19)=4 or id(ig1+19)=5 { ; 両手、大剣、斧、棍 hig2=(pn-1)*hib2 ; データ先頭 n1=id(ig1+11) ; 攻撃力1 in2=hip2(hig2+hib2) : ig2=in2*idb : n2=id(ig2+11) ; 攻撃力2 if n1>=n2 { ; 最後尾より大きい repeat hib2 ; の順列 n=hig2+cnt if hip2(n)=0 : hip2(n)=in1 : break ; 空白なら登録して終わり in2=hip2(n) : ig2=in2*idb : n2=id(ig2+11) ; 攻撃力2 if n2<n1 : hip2(n)=in1 : in1=in2 : n1=n2 ; 入れ替え loop } } ; 槍 in1=in : ig1=in1*idb if id(ig1+19)=3 { ; 槍 hig3=(pn-1)*hib3 ; データ先頭 n1=id(ig1+11) ; 攻撃力1 in2=hip3(hig3+hib3) : ig2=in2*idb : n2=id(ig2+11) ; 攻撃力2 if n1>=n2 { ; 最後尾より大きい repeat hib3 ; の順列 n=hig3+cnt if hip3(n)=0 : hip3(n)=in1 : break ; 空白なら登録して終わり in2=hip3(n) : ig2=in2*idb : n2=id(ig2+11) ; 攻撃力2 if n2<n1 : hip3(n)=in1 : in1=in2 : n1=n2 ; 入れ替え loop } } ; 棍 in1=in : ig1=in1*idb if id(ig1+19)=5 { ; 棍棒 hig4=(pn-1)*hib4 ; データ先頭 n1=id(ig1+11) ; 攻撃力1 in2=hip4(hig4+hib4) : ig2=in2*idb : n2=id(ig2+11) ; 攻撃力2 if n1>=n2 { ; 最後尾より大きい repeat hib4 ; の順列 n=hig4+cnt if hip4(n)=0 : hip4(n)=in1 : break ; 空白なら登録して終わり in2=hip4(n) : ig2=in2*idb : n2=id(ig2+11) ; 攻撃力2 if n2<n1 : hip4(n)=in1 : in1=in2 : n1=n2 ; 入れ替え loop } } ; 杖 in1=in : ig1=in1*idb if id(ig1+19)=6 { ; 杖 hig5=(pn-1)*hib5 ; データ先頭 n1=id(ig1+11) ; 攻撃力1 in2=hip5(hig5+hib5) : ig2=in2*idb : n2=id(ig2+11) ; 攻撃力2 if n1>=n2 { ; 最後尾より大きい repeat hib5 ; の順列 n=hig5+cnt if hip5(n)=0 : hip5(n)=in1 : break ; 空白なら登録して終わり in2=hip5(n) : ig2=in2*idb : n2=id(ig2+11) ; 攻撃力2 if n2<n1 : hip5(n)=in1 : in1=in2 : n1=n2 ; 入れ替え loop } } ; 弓銃 in1=in : ig1=in1*idb if id(ig1+19)=7 or id(ig1+19)=8 or id(ig1+19)=9 or id(ig1+19)=10 { ; 弓銃 hig6=(pn-1)*hib6 ; データ先頭 n1=id(ig1+11) ; 攻撃力1 in2=hip6(hig6+hib6) : ig2=in2*idb : n2=id(ig2+11) ; 攻撃力2 if n1>=n2 { ; 最後尾より大きい repeat hib6 ; の順列 n=hig6+cnt if hip6(n)=0 : hip6(n)=in1 : break ; 空白なら登録して終わり in2=hip6(n) : ig2=in2*idb : n2=id(ig2+11) ; 攻撃力2 if n2<n1 : hip6(n)=in1 : in1=in2 : n1=n2 ; 入れ替え loop } } ; 投擲 in1=in : ig1=in1*idb if id(ig1+8)=1 { ; 投擲 hig7=(pn-1)*hib7 ; データ先頭 n1=id(ig1+11) ; 攻撃力1 in2=hip7(hig7+hib7) : ig2=in2*idb : n2=id(ig2+11) ; 攻撃力2 if n1>=n2 { ; 最後尾より大きい repeat hib7 ; の順列 n=hig7+cnt if hip7(n)=0 : hip7(n)=in1 : break ; 空白なら登録して終わり in2=hip7(n) : ig2=in2*idb : n2=id(ig2+11) ; 攻撃力2 if n2<n1 : hip7(n)=in1 : in1=in2 : n1=n2 ; 入れ替え loop } } ; 盾 in1=in : ig1=in1*idb if id(ig1+16)=5 { ; 盾 hig8=(pn-1)*hib8 ; データ先頭 n1=id(ig1+12) ; 防御力1 in2=hip8(hig8+hib8) : ig2=in2*idb : n2=id(ig2+12) ; 防御力2 if n1>=n2 { ; 最後尾より大きい repeat hib8 ; の順列 n=hig8+cnt if hip8(n)=0 : hip8(n)=in1 : break ; 空白なら登録して終わり in2=hip8(n) : ig2=in2*idb : n2=id(ig2+12) ; 攻撃力2 if n2<n1 : hip8(n)=in1 : in1=in2 : n1=n2 ; 入れ替え loop } } ; 鎧 in1=in : ig1=in1*idb if id(ig1+16)=6 { ; 防具 hig9=(pn-1)*hib9 ; データ先頭 n1=id(ig1+12) ; 防御力1 in2=hip9(hig9+hib9) : ig2=in2*idb : n2=id(ig2+12) ; 防御力2 if n1>=n2 { ; 最後尾より大きい repeat hib9 ; の順列 n=hig9+cnt if hip9(n)=0 : hip9(n)=in1 : break ; 空白なら登録して終わり in2=hip9(n) : ig2=in2*idb : n2=id(ig2+12) ; 攻撃力2 if n2<n1 : hip9(n)=in1 : in1=in2 : n1=n2 ; 入れ替え loop } } ; アイテム in1=in : ig1=in1*idb if id(ig1+16)=9 or id(ig1+16)=7 { ; 防具 hig10=(pn-1)*hib10 ; データ先頭 n1=id(ig1+9) ; 能力1 in2=hip10(hig10+hib10) : ig2=in2*idb : n2=id(ig2+9) ; 能力2 if n1>=n2 { ; 最後尾より大きい repeat hib10 ; の順列 n=hig10+cnt if hip10(n)=0 : hip10(n)=in1 : break ; 空白なら登録して終わり in2=hip10(n) : ig2=in2*idb : n2=id(ig2+9) ; 攻撃力2 if n2<n1 : hip10(n)=in1 : in1=in2 : n1=n2 ; 入れ替え loop } } ; 魔法 in1=in : ig1=in1*idb if id(ig1+16)=10 { ; 魔法 hig11=(pn-1)*hib11 ; データ先頭 n1=id(ig1+9) ; 能力1 in2=hip11(hig11+hib11) : ig2=in2*idb : n2=id(ig2+9) ; 能力2 if n1>=n2 { ; 最後尾より大きい repeat hib11 ; の順列 n=hig11+cnt if hip11(n)=0 : hip11(n)=in1 : break ; 空白なら登録して終わり in2=hip11(n) : ig2=in2*idb : n2=id(ig2+9) ; 能力2 if n2<n1 : hip11(n)=in1 : in1=in2 : n1=n2 ; 入れ替え loop } } ; 特殊 in1=in : ig1=in1*idb if id(ig1+16)=8 { ; 特殊 hig12=(pn-1)*hib12 ; データ先頭 n1=id(ig1+9) ; 能力1 in2=hip12(hig12+hib12) : ig2=in2*idb : n2=id(ig2+9) ; 能力2 if n1>=n2 { ; 最後尾より大きい repeat hib12 ; の順列 n=hig12+cnt if hip12(n)=0 : hip12(n)=in1 : break ; 空白なら登録して終わり in2=hip12(n) : ig2=in2*idb : n2=id(ig2+9) ; 攻撃力2 if n2<n1 : hip12(n)=in1 : in1=in2 : n1=n2 ; 入れ替え loop } } return
中立は割愛。
これだけでも自分にはややこしくてもう、バグつぶしながら奇跡的に動いた、という感じのプログラム。
試験的な確認表示、上から順に値の大きいものになってる
今の所、作り上げたのはここまで。
この次は勢力の評価をどう算出するか、ユニットの配置と装備プログラム。
と、そんな感じなので、長い間なぜ報告が無かったのか分かってもらえると思う。
特にプログラムに時間がかかるというよりは、その構造論をどうするかを考えないといけないので、それで時間がかかる、やった事の無い要素だとね。
という訳で毎日散歩しながら考える日々だったので、引きニートのくせに日焼けして黒くなってるという(笑)