Published Date : 2020年8月4日17:16
YouTubeにアップした動画、「【Processing, プログラミング】経営戦略として有名になってしまったランチェスターの法則をコンピューターシュミレーションしてみよう」の補足説明の記事です。
Here's a little more about the 「[Processing, programming] Let's do a computer simulation of Lanchester's Law which unintentionally made famous as a business strategy」 video I uploaded to YouTube.
目次
Table of Contents
① ランチェスターの法則の超簡潔なまとめ ① A very brief summary of Lanchester's laws |
② Processingを使ってコーディングしていきましょう ② Start coding with Processing |
ページの最後へ Go to the end of the page. |
経営戦略として有名になってしまったランチェスターの法則をコンピューターシュミレーションしてみよう
Let's do a computer simulation of Lanchester's Law which unintentionally made famous as a business strategy.
シュミレーションの実際の動作はこんな感じです。
Here's how the simulation works.
日本では経営戦略として有名なランチェスターの法則ですが、実際の数理モデルを見て、本当に巷に溢れる経営戦略の置き換え理論が正しいのか疑問に思いました。
In Japan, Lanchester's Law is famous as a management strategy, but when I saw the actual mathematical model, I wondered whether the theory of substitution for a management strategy that was abundant in the market was really correct.
例えばよくある第一法則を説明する時の「攻撃力=兵数×武器性能」。
[Offensive power = number of soldiers × weapon performance] when explaining a common first law, for example.
この第一法則は一回に一人の相手と戦う「一騎打ち」、つまり近距離攻撃の時適用されます。
This first law is applied in the case of one opponent at a time [one-on-one battle], that is, a short-range attack.
そして第二法則を説明する時の「攻撃力=兵数の二乗×武器性能」。
And [Attack power = square of the number of soldiers × weapon performance] in explaining the second law.
この第二法則は一人で複数の敵を同時に攻撃可能、つまり遠距離攻撃可能な武器を使用した場合に適用されます。
This second law applies when one person uses a weapon that can attack multiple enemies at the same time, that is, [a long distance attack].
これを経営戦略に置き換えると、よく目にするのが、弱者の戦略と強者の戦略。
When we translate this into management strategies, we often see the strategies of the weak and those of the strong.
弱者、つまり資本力が強者に比べて少ない者が取るべき戦略は、接近戦、一点集中、陽動作戦等。
The strategies that the weak, So those with less capital than the strong, should adopt include close combat, one-point concentration, and diversionary tactics.
強者、つまり資本力が弱者に比べて多い者が取るべき戦略は、遠隔戦、戦力の分散、待ち伏せ作戦等。
The strategies that the strong, So those with more capital than the weak, should adopt include remote warfare, force diversification, and ambush operations.
さらに発展している考えとして、弱者は直接顧客と取引してニッチな商品を売る。
The idea is that the weak will deal directly with customers and sell niche products.
強者は大量の広告を出して業界シェアナンバー2以下の人気商品を真似して売る。等があります。
The strong put out a lot of ads to copy and sell the most popular products below the number two market share. and so on.
これらを確かめるため、Processingを使って単純な戦闘モデルでシュミレーションしてみました。
To test this, I simulated a simple battle model using Processing.
だがどうやら法則には補給率等もっと細かい係数があるみたいです。
But it seems that the law has finer factors such as replenishment rate.
そして実際の戦闘には回復や弾数、兵の士気等の心理的要素と勝因と敗因の要素が沢山あります。
And in actual combat, there are many factors of victory and defeat factors such as recovery, and the number of bullets, as well as the psychological factors that the morale of soldiers.
なので、今からやるシュミレーションはただのご都合主義的なお遊びとして気楽に見て頂ければ幸いです。
So, it would be great if you could take it easy and look at the simulation I'm going to do now as just an opportunistic play.
シュミレーションの内容を簡単に説明します。
A brief description of the simulation is provided.
青い円がA軍、赤い円がB軍を表しています。
The blue circle represents the A army and the red circle represents the B army.
それぞれの軍のパラメーターは、兵の総数、その総数をいくつの部隊に分けるか、
The parameters of each army the total number of soldiers and how many units the total number of soldiers is divided into.
そして攻撃力、射程距離、接近する速度、移動速度等です。
And attack power, range, approaching speed, moving speed, etc.
ご覧の通り、シュミレーションで動く兵士達は接近戦をする古代の戦い方です。
As you can see, simulated soldiers are ancient fighting styles of close combat.
ですが、射程距離を増やし、攻撃範囲を円状にすれば、近代的な戦い方に近づけることも出来ます。
However, if you increase the range and make the attack range circular, you can get closer to the modern way of fighting.
先に結論を言うと、このような範囲が決まったフィールドにおいては、攻撃力や兵数は勿論戦いの勝因において重要ですが、
To conclude first, in a field where such a range is fixed, of course, offensive power and number of soldiers are important for winning a battle.
それよりも射程距離と攻撃回数、そしてどれだけ一回で複数の敵を攻撃できるかが勝因を分けているかのように見えました。
More than that, the range, the number of attacks, and how many times you can attack multiple enemies at once seemed to be the key to winning.
ではしばらくの間、各パラメータがシュミレーションに与える影響をご覧ください。
For a moment, see how each parameter affects the simulation.
ではProcessingでコードを書いていきましょう。
Now let's write the code in Processing.
兵士のオブジェクトを作るクラスの配列
an array of classes that make objects for soldiers
ArrayListA;
ArrayListB;
兵力をいくつ分散させるか
the number that disperses an army
int countA;
int countB;
兵力の数
number of soldiers
float initNoSA;
float initNoSB;
float nosA;
float nosB;
兵隊の集合
a band of soldiers
float bosA;
float bosB;
軍を色で分ける
distinguish armies by color
color colorA;
color colorB;
武器、もしくは戦闘能力の係数
a coefficient of armed or combat capability
float performanceA;
float performanceB;
武器の射程距離
range of a weapon
float arangeOfW;
float brangeOfW;
移動距離を決める
Determine the stride of travel distance
float stride;
フレームレイトが高めだと動きが速すぎるので、通常の約半分に設定
If the frame rate is high, the agent is moving too fast, so set it to about half of the normal frame rate.
int fps;
時間の経過を表示するための変数
Variables to display the passage of time
int elapsedTime;
オブジェクト同士の距離を測る為の変数。この変数は一番近い値を更新していくので、すごく大きい値で初期化する。
A variable used to measure the distance between objects. This variable updates to the nearest value, so initialize it with a very large value.
float nearestd;
一番近いオブジェクトに進むように計算するために必要な変数
Variables required to calculate to go to nearest object
その都度一時的に使用するので、コピー用の変数。PVectorはそれ自身にメソッドを使用すると値が変わってしまう場合があるのでコピーメソッドを使ってコピーするようにする。
A variable for copying because it is used temporarily each time. PVector uses a copy method to make copies because using a method on itself can change the value.
PVector copynearestA;
PVector copynearestB;
補間係数
interpolation coefficient
float ic;
boolean reset;
初期化された時の経過時間
Elapsed time when initialized
int elapsedInitTime;
初期化する関数。セットアップ関数と分ければ、シュミレーションの結果が出た後にリセットして再開したりする時に便利です。
The function to initialize. If you separate it from the setup function, it is useful when you want to reset and restart the simulation after the results have come out.
void init(){
兵士のオブジェクトを作るクラスの配列
an array of classes that make objects for soldiers
A = new ArrayList();
B = new ArrayList();
兵力をいくつ分散させるか
the number that disperses an army
countA = 20;
countB = 20;
兵力の数
number of soldiers
initNoSA = 100;
initNoSB = 1000;
兵隊の集合
a band of soldiers
bosA = initNoSA/countA;
bosB = initNoSB/countB;
現在の兵力の総数を変動させるため、ループの最初で一度初期化する。
Initialize once at the beginning of the loop to change the current total number of soldiers.
nosA = 0;
nosB = 0;
軍を色で分ける
distinguish armies by color
colorA = color(0, 0, 255, 180);
colorB = color(255, 0, 0, 180);
武器、もしくは戦闘能力の係数
a coefficient of armed or combat capability
performanceA = 0.3;
performanceB = 1.0;
武器の射程距離
range of a weapon
arangeOfW = 300;
brangeOfW = 100.0;
移動距離を決める
Determine the stride of travel distance
stride = 10.0;
フレームレイトが高めだと動きが速すぎるので、通常の約半分に設定
If the frame rate is high, the agent is moving too fast, so set it to about half of the normal frame rate.
fps = 15;
時間の経過を表示するための変数
Variables to display the passage of time
elapsedTime = 0;
オブジェクト同士の距離を測る為の変数。この変数は一番近い値を更新していくので、すごく大きい値で初期化する。
A variable used to measure the distance between objects. This variable updates to the nearest value, so initialize it with a very large value.
nearestd = 10000;
近いオブジェクトまでの距離を測定したら、その距離の何パーセントの値で近づいていくかを決める補間係数
An interpolation factor that determines what percentage of the distance you measure to get closer to an object.
ic = 0.03;
リセットをする為の変数
Variable to reset
reset = false;
時間の経過を表示するための変数
Variables to display the passage of time
elapsedInitTime = millis()/1000;
当たり判定はオブジェクト自身が感知して、オブジェクト自身がダメージを受けるので、戦闘係数はAとBで逆に初期化する。
In the hit determination, the object itself is sensed, and the object itself is damaged, so that the combat coefficient is initialized inversely by A and B.
for (int i = 0; i < countA; i++) {
float x = random(width/12, width/8);
float y = random(height);
A.add(new Soldier(x, y, bosA, colorA, performanceB, arangeOfW, stride));
}
for (int j = 0; j < countB; j++) {
float x = random(width-(width/8), width-(width/12));
float y = random(height);
B.add(new Soldier(x, y, bosB, colorB, performanceA, brangeOfW, stride));
}
}
全てをリセットしてシュミレーションを再開する。
Reset everything and resume the simulation.
void mousePressed(){
if (reset) {
init();
loop();
}
}
void setup() {
size(1600, 800);
init();
frameRate(fps);
}
void draw() {
background(222);
現在の兵力の総数を変動させるため、ループの最初で一度初期化する。
Initialize once at the beginning of the loop to change the current total number of soldiers.
nosA = 0;
nosB = 0;
兵士の位置と数をアップデートさせて、当たり判定を行う。
先に敵のオブジェクトに触れたほうが先に攻撃する。
兵士の数がなくなったオブジェクトは配列から消去させる。
その際、オブジェクトの配列の数が変わってしまうので、最後からループさせ存在しない配列のインデックスにアクセスしないようにする。
The soldier's position and number of soldiers are updated and collision detection is performed.
The first to touch the enemy object is the first to attack.
Objects with no soldiers are erased from the array.
This changes the total number of arrays
for (int i = A.size() - 1; i >= 0; i--) {
Soldier a = A.get(i);
a.move();
findBnearA(a);
a.display();
aAttack(a);
nosA += a.d;
if (a.d <= 0) {
A.remove(i);
}
}
for (int j = B.size() - 1; j >= 0; j--) {
Soldier b = B.get(j);
b.move();
findAnearB(b);
b.display();
bAttack(b);
nosB += b.d;
if (b.d <= 0) {
B.remove(j);
}
}
現在のパラメーターを画面に表示させる処理をまとめた関数
function that displays the current parameter on the screen
textDisplay();
}
攻撃を表現する関数
Function that represents the attack
void aAttack(Soldier a) {
Aのオブジェクト一つに対して、周りにある全てのBのオブジェクトを総当たりで衝突検出する。
当然オブジェクトが増えると計算量が増えるのであまりおすすめしない。
For one object in A, one by one, check to see if all objects in the surrounding B are hit.
Of course, this method is not recommended because the more objects you have, the more computations you need.
for (int j = B.size() - 1; j >= 0; j--) {
Soldier b = B.get(j);
PVector.dist()メソッドは2点間のベクトルの距離の絶対値を返す便利なメソッドです。
The PVector.dist() method is useful for returning the absolute value of the vector distance between two points.
float d = PVector.dist(a.coordinate, b.coordinate);
if ( (d <= (((a.d/2) + a.row) + b.d/2)) & ( ((a.d/2) > 0.0) & ((b.d/2) > 0.0) ) ) {
b.hit = true;
b.collision();
pushStyle();
noFill();
strokeWeight(3);
stroke(0,0,255, 100);
if(arangeOfW == 1.0){
ellipse(a.coordinate.x, a.coordinate.y, a.d * 1.25, a.d * 1.25);
} else {
ellipse(a.coordinate.x, a.coordinate.y, a.d + a.row, a.d + a.row);
}
popStyle();
}
if (b.d <= 0) {
B.remove(j);
}
}
}
void bAttack(Soldier b) {
for (int i = A.size() - 1; i >= 0; i--) {
Soldier a = A.get(i);
float d = PVector.dist(b.coordinate, a.coordinate);
if ( (d <= ((a.d/2) + ((b.d/2) + b.row))) & ( ((a.d/2) > 0.0) & ((b.d/2) > 0.0) ) ) {
a.hit = true;
a.collision();
pushStyle();
noFill();
strokeWeight(3);
stroke(255,0,0, 100);
if(brangeOfW == 1.0){
ellipse(b.coordinate.x, b.coordinate.y, b.d * 1.25, b.d * 1.25);
} else {
ellipse(b.coordinate.x, b.coordinate.y, b.row + b.d, b.row + b.d);
}
popStyle();
}
if (a.d <= 0) {
A.remove(i);
}
}
}
一番近いオブジェクトに進むように計算するために必要な関数
Function required to calculate to go to nearest object
Aの近くにいるBのオブジェクトを見つける
find object B near A
void findBnearA(Soldier a) {
for (int j = B.size() - 1; j >= 0; j--) {
Soldier b = B.get(j);
float d = PVector.dist(a.coordinate, b.coordinate);
if (nearestd > d) {
nearestd = d;
copynearestB = b.coordinate.copy();
}
}
a.coordinate.x = lerp(a.coordinate.x, copynearestB.x, ic);
a.coordinate.y = lerp(a.coordinate.y, copynearestB.y, ic);
nearestd = 10000;
}
Bの近くにいるAのオブジェクトを見つける
find object A near B
void findAnearB(Soldier b) {
for (int j = A.size() - 1; j >= 0; j--) {
Soldier a = A.get(j);
float d = PVector.dist(a.coordinate, b.coordinate);
if (nearestd > d) {
nearestd = d;
copynearestA = a.coordinate.copy();
}
}
b.coordinate.x = lerp(b.coordinate.x, copynearestA.x, ic);
b.coordinate.y = lerp(b.coordinate.y, copynearestA.y, ic);
nearestd = 10000;
}
現在のパラメーターを画面に表示させる処理をまとめた関数
function that displays the current parameter on the screen
void textDisplay() {
経過時間を表示する
Show the elapsed time
pushStyle();
fill(0);
textAlign(CENTER, CENTER);
textSize(30);
elapsedTime = millis()/1000 - elapsedInitTime;
text("Time : " + elapsedTime + " sec.", width/2, height/30);
popStyle();
現在の部隊数を表示させる
display the current number of troops
pushStyle();
fill(colorA);
textAlign(LEFT, CENTER);
textSize(21);
text("Number of troops of A = " + A.size(), width/60, height/10);
textSize(24);
text("Number of soldiers in A = " + int(nosA), width/60, height/20);
popStyle();
pushStyle();
fill(colorB);
textAlign(RIGHT, CENTER);
textSize(21);
text("Number of troops of B = " + B.size(), width*59/60, height/10);
textSize(24);
text("Number of soldiers in B = " + int(nosB), width*59/60, height/20);
popStyle();
武器の射程距離を表示する
Display range of a weapon
pushStyle();
fill(colorA);
textAlign(LEFT, CENTER);
textSize(21);
text("A's range of a weapon = " + arangeOfW, width/60, height*9/10);
popStyle();
pushStyle();
fill(colorB);
textAlign(RIGHT, CENTER);
textSize(21);
text("B's range of a weapon = " + brangeOfW, width*59/60, height*9/10);
popStyle();
個々の戦闘力を表示する
display individual combat capability
pushStyle();
fill(colorA);
textAlign(LEFT, CENTER);
textSize(24);
text("A's combat capability = " + performanceA, width/60, height*19/20);
popStyle();
pushStyle();
fill(colorB);
textAlign(RIGHT, CENTER);
textSize(24);
text("B's combat capability = " + performanceB, width*59/60, height*19/20);
popStyle();
1分経ったら戦闘を終了する。使いたい場合はアンコメントする。
We finish the battle in a minute. Uncomment if you want to use it.
//if ( elapsedTime <= 60 ){
// noLoop();
// pushStyle();
// fill(0);
// textAlign(CENTER, CENTER);
// textSize(60);
// text("Time out !", width/2, height/4);
// textSize(30);
// //AとBの残りの兵隊の数を表示する
// //Display the number of remaining soldiers for A and B
// text("The number of remaining soldiers in A : " + nf(nosA, 0, 1), width/2, height/2);
// text("The number of remaining soldiers in B : " + nf(nosB, 0, 1), width/2, height*2/3);
// popStyle();
// reset = true;
//}
どちらかの軍が全滅したら、最終的な残りの兵数を表示させる
If either army is destroyed, the final remaining number of soldiers will be displayed.
if ( ( nosA <= 0.0 ) | ( nosB <= 0.0 ) ) {
noLoop();
pushStyle();
fill(0);
textAlign(CENTER, CENTER);
textSize(60);
text("Game over !", width/2, height/6);
ランチェスターの第一法則を適用した、Bが全滅した時のAの残数
residual number of A when B is completely destroyed by applying the first law of Lanchester
float rA_dB_LsFLow = initNoSA - ((performanceB/performanceA) * initNoSB);
ランチェスターの第二法則を適用した、Bが全滅した時のAの残数
residual number of A when B is completely destroyed by applying the second law of Lanchester
float rA_dB_LsSLow = sqrt(pow(initNoSA,2) - ((performanceB/performanceA) * pow(initNoSB,2)));
ランチェスターの第一法則を適用した、Aが全滅した時のBの残数
residual number of B when A is completely destroyed by applying the first law of Lanchester
float rB_dA_LsFLow = initNoSB - ((performanceA/performanceB) * initNoSA);
ランチェスターの第二法則を適用した、Aが全滅した時のBの残数
residual number of B when A is completely destroyed by applying the second law of Lanchester
float rB_dA_LsSLow = sqrt(pow(initNoSB,2) - ((performanceA/performanceB) * pow(initNoSA,2)));
textSize(18);
Aがランチェスターの第一法則で負けた為、「Aが勝つためにはXXXの兵数とXXXの武器性能が必要です」と画面に表示させる。
Since A lost by applying the first law of Lanchester, [In order for A to win, the number of soldiers of XXX and the weapon performance of XXX are required.] is displayed on the screen.
textAlign(LEFT, CENTER);
text("Lanchester's first law", width/20, height*5/16);
if ( !(rA_dB_LsFLow < 0.0) ) {
AがBに勝つために必要になる兵士の数をランチェスターの第一法則で割り出す
use Lanchester's first law to determine the number of soldiers A will need to beat B
float requiredNum = initNoSA;
while(true){
if((requiredNum - ((performanceB/performanceA) * initNoSB)) < 0){
AがBに勝つにはXXXの兵数が必要になります。
In order for A to beat B, XXX's number of soldiers is needed.
text("In order for A to beat B, " + requiredNum + " 's number of soldiers is needed.", width/20, height*6/16);
break;
}
requiredNum += 0.1;
}
AがBに勝つために必要になる武器性能をランチェスターの第一法則で割り出す
determine the weapon performance required for A to beat B by Lanchester's first law
requiredNum = performanceA;
while(true){
if((initNoSA - ((performanceB/requiredNum) * initNoSB)) < 0){
AがBに勝つにはXXXの武器性能が必要になります。
In order for A to beat B, XXX's weapon performance is required.
text("In order for A to beat B, " + requiredNum + " 's weapon performance is required.", width/20, height*7/16);
break;
}
requiredNum += 0.1;
}
}
第二法則
Second Law
text("Lanchester's second law", width/20, height*9/16);
if ( !(rA_dB_LsSLow < 0.0) ) {
AがBに勝つために必要になる兵士の数をランチェスターの第二法則で割り出す
use Lanchester's second law to determine the number of soldiers A will need to beat B
float requiredNum = initNoSA;
while(true){
if((sqrt(pow(requiredNum,2) - ((performanceB/performanceA) * pow(initNoSB,2)))) < 0){
AがBに勝つにはXXXの兵数が必要になります。
In order for A to beat B, XXX's number of soldiers is needed.
text("In order for A to beat B, " + requiredNum + " 's number of soldiers is needed.", width/20, height*10/16);
break;
}
requiredNum += 0.1;
}
AがBに勝つために必要になる武器性能をランチェスターの第二法則で割り出す
determine the weapon performance required for A to beat B by Lanchester's second law
requiredNum = performanceA;
while(true){
if((sqrt(pow(initNoSA,2) - ((performanceB/requiredNum) * pow(initNoSB,2)))) < 0){
AがBに勝つにはXXXの武器性能が必要になります。
In order for A to beat B, XXX's weapon performance is required.
text("In order for A to beat B, " + requiredNum + " 's weapon performance is required.", width/20, height*11/16);
break;
}
requiredNum += 0.1;
}
}
textAlign(RIGHT, CENTER);
text("Lanchester's first law", width*19/20, height*5/16);
Bがランチェスターの第一法則で負けた為、「Bが勝つためにはXXXの兵数とXXXの武器性能が必要です」と画面に表示させる。
Since B lost by applying the first law of Lanchester, [In order for B to win, the number of soldiers of XXX and the weapon performance of XXX are required.] is displayed on the screen.
if ( !(rB_dA_LsFLow < 0.0) ) {
BがAに勝つために必要になる兵士の数をランチェスターの第一法則で割り出す
use Lanchester's first law to determine the number of soldiers B will need to beat A
float requiredNum = initNoSB;
while(true){
if((requiredNum - ((performanceA/performanceB) * initNoSA)) < 0){
BがAに勝つにはXXXの兵数が必要になります。
In order for B to beat A, XXX's number of soldiers is needed.
text("In order for B to beat A, " + requiredNum + " 's number of soldiers is needed.", width*19/20, height*6/16);
break;
}
requiredNum += 0.1;
}
BがAに勝つために必要になる武器性能をランチェスターの第一法則で割り出す
determine the weapon performance required for B to beat A by Lanchester's first law
requiredNum = performanceB;
while(true){
if((initNoSB - ((performanceA/requiredNum) * initNoSA)) < 0){
BがAに勝つにはXXXの武器性能が必要になります。
In order for B to beat A, XXX's weapon performance is required.
text("In order for B to to beat A, " + requiredNum + " 's weapon performance is required.", width*19/20, height*7/16);
break;
}
requiredNum += 0.1;
}
}
第二法則
Second Law
text("Lanchester's second law", width*19/20, height*9/16);
if ( !(rB_dA_LsSLow < 0.0) ) {
BがAに勝つために必要になる兵士の数をランチェスターの第二法則で割り出す
use Lanchester's second law to determine the number of soldiers B will need to beat A
float requiredNum = initNoSB;
while(true){
if((sqrt(pow(requiredNum,2) - ((performanceA/performanceB) * pow(initNoSA,2)))) < 0){
BがAに勝つにはXXXの兵数が必要になります。
In order for B to beat A, XXX's number of soldiers is needed.
text("In order for B to beat A, " + requiredNum + " 's number of soldiers is needed.", width*19/20, height*10/16);
break;
}
requiredNum += 0.1;
}
BがAに勝つために必要になる武器性能をランチェスターの第二法則で割り出す
determine the weapon performance required for B to beat A by Lanchester's second law
requiredNum = performanceB;
while(true){
if((sqrt(pow(initNoSB,2) - ((performanceA/requiredNum) * pow(initNoSA,2)))) < 0){
BがAに勝つにはXXXの武器性能が必要になります。
In order for B to beat A, XXX's weapon performance is required.
text("In order for B to beat A, " + requiredNum + " 's weapon performance is required.", width*19/20, height*11/16);
break;
}
requiredNum += 0.1;
}
}
popStyle();
reset = true;
}
スタート時の初期値を見やすくするために、プログラムの始まりの最初の1秒間を一時停止する。
Pause the first second of the beginning of the program to make the initial start values easier to see.
if ((frameCount <= 0) & (frameCount >= 3)) {
pushStyle();
fill(0);
textAlign(CENTER, CENTER);
textSize(60);
text("Start!", width/2, height/2);
popStyle();
}
if (frameCount == 3) {
delay(1000);
}
}
class Soldier{
兵隊を表す円の中心
the center of a circle representing a soldier
PVector coordinate;
兵隊数を表す円の直径
the Diameter of a circle representing the number of soldiers
float d;
色
Color
color c;
衝突判定に使用
Used for collision determination
boolean hit;
兵士達を表す円が動く方向を決める角度
the angle that determines the direction in which the circles representing soldiers move
float[] anglelist = {0, 45, 90, 135, 180, 225, 270, 360};
武器、もしくは戦闘能力の係数
a coefficient of armed or combat capability
float coeff;
武器の射程距離
range of a weapon
float row;
移動距離を決める
Determine the stride of travel distance
float distance;
一番近いオブジェクトに進むように計算するために必要な変数
Variables required to calculate to go to nearest object
PVector nearestVector;
オブジェクトを作成する為の初期化関数
Initialization function for creating an object
Soldier(float x, float y, float bos, color agentColor, float factor, float rangeW, float sod){
coordinate = new PVector(x, y);
d = bos;
c = agentColor;
hit = false;
coeff = factor;
row = rangeW;
distance = sod;
nearestVector = new PVector(width/2, height/2);
}
このオブジェクトの座標位置を8方向にランダムに動かすためのmoveメソッド。
A move method for randomly moving the coordinate position of this object in eight directions.
void move(){
int index = (int)random(anglelist.length);
float angle = radians(anglelist[index]);
float forwardX = cos(angle) * distance;
float forwardY = sin(angle) * distance;
if ( ( (coordinate.x < width-d) & (forwardX >= 0) ) | ( (coordinate.x > d) & (forwardX > 0) ) ){
coordinate.x = coordinate.x + (forwardX * -1);
} else {
coordinate.x = coordinate.x + forwardX;
}
if ( ( (coordinate.y < height-d) & (forwardY >= 0) ) | ( (coordinate.y > d) & (forwardY > 0) ) ){
coordinate.y = coordinate.y + (forwardY * -1);
} else {
coordinate.y = coordinate.y + forwardY;
}
}
エリプス関数を使って、実際にオブジェクトを移動させる。
Use the ellipses function to actually move the object.
void display(){
pushStyle();
noStroke();
fill(c);
ellipse(coordinate.x, coordinate.y, d, d);
popStyle();
}
他のオブジェクトと衝突したら発動するメソッド。
オブジェクト同士の衝突が感知されると、自らの兵力数を相手の武器性能の係数分だけ減らしていく。
Method to invoke when colliding with another object.
When a collision between objects is detected, the number of its own troops is reduced by the coefficient of the opponent's weapon performance.
void collision(){
if(hit){
d -= coeff;
if (d <= 0.0) {
d = 0;
}
hit = false;
}
}
}
以上です。お疲れ様です。
That's all. Thank you for your hard work.
もっとパラメーターを増やして、地形、士気等の心理的な要素を加えていっても面白いかもしれません。
It might be interesting to add more parameters and psychological factors such as geography and morale.
それでは色々と工夫と改良を行って楽しんでみてください。
Then, please enjoy it with various ideas and improvements.