Я делаю настольную игру под названием Arbitragg вариацией на тему Манкала.
В игре есть одиночная игра, которая работает, и AI в виде FSM, сломанный.
Игра работает так: 2 массива 2 записывают позиции камней. Еще 2 массива для инвентаря.
Игра начинается:
- Добавляет камни на доску, Определите игрока
- Игрок 1 ход начинается
- Игрок 2 (AI) MangaWeakAi ();
- AI_Possible_Moves (); // выбирает непустой под
- RemoveStonesToInv (ai_arr, ai_pos);
- AI_Inv (); // проходит через инвентарь игрока 2 и добавляет все слоты инвентаря, в которых есть камни.
- для l oop, который проходит через инвентарь и вызывает move ()
- SelectStoneInv (); // выбирает модуль инвентаря
- AI_Move_Stone (NextMove (ai_arr, ai_pos)); // AI_Move_Stone перемещает камень к следующему модулю, который отправляется через NextMove ()
Я получаю сообщение об ошибке UnityException: преобразование дочернего элемента за пределы, что, как я полагаю, означает нуль для дочернего элемента, но в нем определенно есть ребенок. Проблема возникает в строке 880:
GameObject child = p2InvPos [invPos] .gameObject.transform.GetChild (0) .gameObject;
Я пропустил несколько методов, но следую как Start () , definePlayer (), winCondition & Turn manager, но следуйте из MangaWeakAi ()
public class GameManager : MonoBehaviour
{
public void MangaWeakAi()
{
P1 = false;
p1Cam.SetActive(false);
p2Cam.SetActive(true);
AI_Possible_Moves();
int r = Random.Range(0, viableMoves.Count);
ai_arr = viableMoves[r].Array;
ai_pos = viableMoves[r].Pit;
Debug.Log("AI selected:a" + ai_arr + "p" + ai_pos);
RemoveStonesToInv(ai_arr, ai_pos);
AI_Inv();
for (int i = 0; i < possibleInv.Count; i++)
{
Debug.Log("Inv Pos: " + i);
move(i);
//StartCoroutine(moves(i, 0.2f));
}
}
void StartGame()
{
arr1 = new Pit[14];
arr2 = new Pit[14];
p1Inventory = new Pit(0);
p2Inventory = new Pit(0);
p1Inv = new Pit[18];
p2Inv = new Pit[18];
for (int i = 0; i < 18; i++)
{
p1Inv[i] = new Pit(0);
p2Inv[i] = new Pit(0);
}
for (int i = 0; i < 14; i++)
{
arr1[i] = new Pit(0);
arr2[i] = new Pit(0);
}
arr1[1].LightStones = arr1[13].LightStones = arr1[6].LightStones = arr1[8].LightStones = 2;
arr2[1].DarkStones = arr2[13].DarkStones = arr2[6].DarkStones = arr2[8].DarkStones = 2;
arr1[2].LightStones = arr1[4].LightStones = arr1[5].LightStones = arr1[9].LightStones = arr1[11].LightStones = arr1[12].LightStones = 1;
arr2[2].DarkStones = arr1[3].DarkStones = arr2[5].DarkStones = arr2[9].DarkStones = arr1[10].DarkStones = arr2[12].DarkStones = 1;
}
//fix
public void RemoveStonesToInv(int array, int pos)
{
int count = 0;
lastArr = array;
lastPos = pos;
showSelectedPit(array,pos);
//check which player and adjust
if (P1)
{
if (array == 1)
{
for (int i = 0; i < arr1[pos].LightStones; i++)
{
p1Inv[count].LightStones++;
spawnInventoryNew2(1, count);
count++;
}
for (int i = 0; i < arr1[pos].DarkStones; i++)
{
p1Inv[count].DarkStones++;
spawnInventoryNew2(2, count);
count++;
}
arr1[pos].LightStones = 0;
arr1[pos].DarkStones = 0;
}
else
{
for (int i = 0; i < arr2[pos].LightStones; i++)
{
p1Inv[count].LightStones++;
spawnInventoryNew2(1, count);
count++;
}
for (int i = 0; i < arr2[pos].DarkStones; i++)
{
p1Inv[count].DarkStones++;
spawnInventoryNew2(2, count);
count++;
}
arr2[pos].LightStones = 0;
arr2[pos].DarkStones = 0;
}
}
else
{
if (array == 1)
{
for (int i = 0; i < arr1[pos].LightStones; i++)
{
p2Inv[count].LightStones++;
spawnInventoryNew2(1, count);
count++;
}
for (int i = 0; i < arr1[pos].DarkStones; i++)
{
p2Inv[count].DarkStones++;
spawnInventoryNew2(2, count);
count++;
}
arr1[pos].LightStones = 0;
arr1[pos].DarkStones = 0;
}
else
{
for (int i = 0; i < arr2[pos].LightStones; i++)
{
p2Inv[count].LightStones++;
spawnInventoryNew2(1, count);
Debug.Log(count + ":" + p1Inv[count].LightStones);
count++;
}
for (int i = 0; i < arr2[pos].DarkStones; i++)
{
p2Inv[count].DarkStones++;
spawnInventoryNew2(2, count);
count++;
}
arr2[pos].LightStones = 0;
arr2[pos].DarkStones = 0;
}
}
Debug.Log("Stones Added To Inv");
refreshPit(array,pos);
}
void showSelectedPit(int array, int pos)
{
if (lastSelectedA == 1)
{
switch (lastSelectedP)
{
case 0:
SelectedBoard[lastSelectedP].SetActive(false);
break;
case 1:
SelectedBoard[lastSelectedP].SetActive(false);
break;
case 2:
SelectedBoard[lastSelectedP].SetActive(false);
break;
case 3:
SelectedBoard[lastSelectedP].SetActive(false);
break;
case 4:
SelectedBoard[lastSelectedP].SetActive(false);
break;
case 5:
SelectedBoard[lastSelectedP].SetActive(false);
break;
case 6:
SelectedBoard[lastSelectedP].SetActive(false);
break;
case 7:
SelectedBoard[lastSelectedP].SetActive(false);
break;
case 8:
SelectedBoard[lastSelectedP].SetActive(false);
break;
case 9:
SelectedBoard[lastSelectedP].SetActive(false);
break;
case 10:
SelectedBoard[lastSelectedP].SetActive(false);
break;
case 11:
SelectedBoard[lastSelectedP].SetActive(false);
break;
case 12:
SelectedBoard[lastSelectedP].SetActive(false);
break;
case 13:
SelectedBoard[lastSelectedP].SetActive(false);
break;
}
}
else
{
switch (lastSelectedP)
{
case 0:
SelectedBoard[14].SetActive(false);
break;
case 1:
SelectedBoard[15].SetActive(false);
break;
case 2:
SelectedBoard[16].SetActive(false);
break;
case 5:
SelectedBoard[17].SetActive(false);
break;
case 6:
SelectedBoard[18].SetActive(false);
break;
case 7:
SelectedBoard[19].SetActive(false);
break;
case 8:
SelectedBoard[20].SetActive(false);
break;
case 9:
SelectedBoard[21].SetActive(false);
break;
case 12:
SelectedBoard[22].SetActive(false);
break;
case 13:
SelectedBoard[23].SetActive(false);
break;
}
}
if (array == 1)
{
switch (pos)
{
case 0:
SelectedBoard[pos].SetActive(true);
break;
case 1:
SelectedBoard[pos].SetActive(true);
break;
case 2:
SelectedBoard[pos].SetActive(true);
break;
case 3:
SelectedBoard[pos].SetActive(true);
break;
case 4:
SelectedBoard[pos].SetActive(true);
break;
case 5:
SelectedBoard[pos].SetActive(true);
break;
case 6:
SelectedBoard[pos].SetActive(true);
break;
case 7:
SelectedBoard[pos].SetActive(true);
break;
case 8:
SelectedBoard[pos].SetActive(true);
break;
case 9:
SelectedBoard[pos].SetActive(true);
break;
case 10:
SelectedBoard[pos].SetActive(true);
break;
case 11:
SelectedBoard[pos].SetActive(true);
break;
case 12:
SelectedBoard[pos].SetActive(true);
break;
case 13:
SelectedBoard[pos].SetActive(true);
break;
}
}
else
{
switch (pos)
{
case 0:
SelectedBoard[14].SetActive(true);
break;
case 1:
SelectedBoard[15].SetActive(true);
break;
case 2:
SelectedBoard[16].SetActive(true);
break;
case 5:
SelectedBoard[17].SetActive(true);
break;
case 6:
SelectedBoard[18].SetActive(true);
break;
case 7:
SelectedBoard[19].SetActive(true);
break;
case 8:
SelectedBoard[20].SetActive(true);
break;
case 9:
SelectedBoard[21].SetActive(true);
break;
case 12:
SelectedBoard[22].SetActive(true);
break;
case 13:
SelectedBoard[23].SetActive(true);
break;
}
}
lastSelectedA = array;
lastSelectedP = pos;
}
public void refreshBoard()
{
GameObject[] stones = GameObject.FindGameObjectsWithTag("Stones");
foreach (GameObject stone in stones)
{
Destroy(stone);
}
for (int i = 0; i < 14; i++)
{
for (int k = 0; k < arr1[i].LightStones; k++)
{
//StartCoroutine(spawnDelay(0, i, 1, k));
spawnDelayTest(0,i,1,k);
}
for (int k = 0; k < arr1[i].DarkStones; k++)
{
//StartCoroutine(spawnDelay(1, i, 1, k));
spawnDelayTest(1, i, 1, k);
}
}
for (int i = 0; i < 14; i++)
{
for (int k = 0; k < arr2[i].LightStones; k++)
{
//StartCoroutine(spawnDelay(0, i, 1, k));
spawnDelayTest(0, i, 2, k);
}
for (int k = 0; k < arr2[i].DarkStones; k++)
{
//StartCoroutine(spawnDelay(1, i, 1, k));
spawnDelayTest(1, i, 2, k);
}
}
}
public void refreshPit(int array,int pos)
{
if (array == 1)
{
for (int i = 0; i < arr1Spawner[pos].transform.childCount; i++)
{
Destroy(arr1Spawner[pos].transform.GetChild(i).gameObject);
}
}
else
{
for (int i = 0; i < arr2Spawner[pos].transform.childCount; i++)
{
Destroy(arr2Spawner[pos].transform.GetChild(i).gameObject);
}
}
}
public void RemoveStoneFromInv(int player, int arr, int pos, int invPos)
{
showSelectedPit(arr, pos);
bool isLight;
if (player == 1)
{
//check to see if it is a light stone
if (p1Inv[invPos].LightStones == 1)
{
isLight = true;
}
else
{
isLight = false;
}
//remove from Inv and destroy object
p1Inv[invPos].LightStones = 0;
p1Inv[invPos].DarkStones = 0;
GameObject child = p1InvPos[invPos].gameObject.transform.GetChild(0).gameObject;
Destroy(child);
}
else
{
//check to see if it alight stone
if (p2Inv[invPos].LightStones == 1)
{
isLight = true;
}
else
{
isLight = false;
}
//remove from Inv and destroy object
p2Inv[invPos].LightStones = 0;
p2Inv[invPos].DarkStones = 0;
GameObject child = p2InvPos[invPos].gameObject.transform.GetChild(0).gameObject;
Destroy(child);
}
lastArr = arr;
lastPos = pos;
//add to the arr
if (arr == 1)
{
if (isLight)
{
arr1[pos].LightStones++;
spawnDelayTest(0, pos, arr, 0);
if (pos == 0 || pos == 7)
{
redStonesRemaining--;
}
}
else
{
if (pos == 0 || pos == 7)
{
arr1[pos + 1].DarkStones++;
spawnDelayTest(1, pos + 1, arr, 0);
lastPos = pos + 1;
}
else
{
arr1[pos].DarkStones++;
spawnDelayTest(1, pos, arr, 0);
}
}
}
else
{
if (isLight)
{
if (pos == 0 || pos == 7)
{
arr2[pos + 1].LightStones++;
spawnDelayTest(0, pos + 1, arr, 0);
lastPos = pos + 1;
}
else
{
arr2[pos].LightStones++;
spawnDelayTest(0, pos, arr, 0);
}
}
else
{
arr2[pos].DarkStones++;
spawnDelayTest(1, pos, arr, 0);
if (pos == 0 || pos == 7)
{
blueStonesRemaining--;
}
}
}
InvSelcted = null;
selected = false;
//check our inventory to see to pass on the token
if (isLight)
{
InventoryCheck(arr, pos, 0);
}
else
{
InventoryCheck(arr, pos, 1);
}
}
public void SelectStoneInv(int player, int pos)
{
selected = true;
Pit selectedPit = new Pit(0);
if (player == 1)
{
if (p1Inv[pos].LightStones == 1)
{
selectedPit.LightStones = 1;
}
else
{
selectedPit.DarkStones = 1;
}
}
else
{
if (p2Inv[pos].LightStones == 1)
{
selectedPit.LightStones = 1;
}
else
{
selectedPit.DarkStones = 1;
}
}
InvSelcted = selectedPit;
}
void InventoryCheck(int lastA, int lastP, int type)
{
bonus = false;
int t = 0;
if (P1)
{
for (int i = 0; i < p1Inv.Length; i++)
{
t += p1Inv[i].DarkStones + p1Inv[i].LightStones;
}
}
else
{
for (int i = 0; i < p2Inv.Length; i++)
{
t += p2Inv[i].DarkStones + p2Inv[i].LightStones;
}
}
if (t == 0)
{
if (lastA == 1)
{
if (lastP == 0 || lastP == 7 && type == 0)
{
bonus = true;
}
}
else
{
if (lastP == 0 || lastP == 7 && type == 1)
{
bonus = true;
}
}
//change turn
TurnManger();
}
}
void AI_Possible_Moves()
{
//array1
pMoves p1 = new pMoves();
p1.Array = 1;
p1.Pit = 1;
possibleMoves.Add(p1);
pMoves p2 = new pMoves();
p2.Array = 1;
p2.Pit = 2;
possibleMoves.Add(p2);
pMoves p3 = new pMoves();
p3.Array = 1;
p3.Pit = 3;
possibleMoves.Add(p3);
pMoves p4 = new pMoves();
p4.Array = 1;
p4.Pit = 4;
possibleMoves.Add(p4);
pMoves p5 = new pMoves();
p5.Array = 1;
p5.Pit = 5;
possibleMoves.Add(p5);
pMoves p6 = new pMoves();
p6.Array = 1;
p6.Pit = 6;
possibleMoves.Add(p6);
pMoves p11 = new pMoves();
p11.Array = 1;
p11.Pit = 11;
possibleMoves.Add(p11);
//array2
pMoves p7 = new pMoves();
p7.Array = 2;
p7.Pit = 1;
possibleMoves.Add(p7);
pMoves p8 = new pMoves();
p8.Array = 2;
p8.Pit = 2;
possibleMoves.Add(p8);
pMoves p9 = new pMoves();
p9.Array = 2;
p9.Pit = 5;
possibleMoves.Add(p9);
pMoves p10 = new pMoves();
p10.Array = 2;
p10.Pit = 6;
possibleMoves.Add(p10);
viableMoves.Clear();
foreach (var p in possibleMoves)
{
if (p.Array == 1)
{
if (arr1[p.Pit].LightStones != 0)
{
pMoves move = new pMoves();
move.Array = 1;
move.Pit = p.Pit;
viableMoves.Add(move);
}
if (arr1[p.Pit].DarkStones != 0)
{
pMoves move = new pMoves();
move.Array = 1;
move.Pit = p.Pit;
viableMoves.Add(move);
}
}
if (p.Array == 2)
{
if (arr2[p.Pit].LightStones != 0)
{
pMoves move = new pMoves();
move.Array = 2;
move.Pit = p.Pit;
viableMoves.Add(move);
}
if (arr2[p.Pit].DarkStones != 0)
{
pMoves move = new pMoves();
move.Array = 2;
move.Pit = p.Pit;
viableMoves.Add(move);
}
}
}
}
void AI_Inv()
{
possibleInv.Clear();
for (int i = 0; i < p2Inv.Length; i++)
{
if (p2Inv[i].DarkStones == 1)
{
possibleInv.Add(i);
}
if (p2Inv[i].LightStones == 1)
{
possibleInv.Add(i);
}
}
Debug.Log("Inv Size: " + possibleInv.Count);
}
string NextMove(int a, int b)
{
string nextMove = "";
if (a == 1)
{
//last pos
switch (b)
{
case 0:
nextMove = "a1p1";
break;
case 1:
nextMove = "a1p2";
break;
case 2:
nextMove = "a1p3";
break;
case 3:
nextMove = "a1p4#a2p5";
break;
case 4:
//move to option 1 ... a1p5 or option 2 ... a1p10
nextMove = "a1p5";
break;
case 5:
nextMove = "a1p6";
break;
case 6:
nextMove = "a1p7";
break;
case 7:
nextMove = "a1p8";
break;
case 8:
nextMove = "a1p9";
break;
case 9:
nextMove = "a1p10";
break;
case 10:
nextMove = "a1p12";
break;
case 11:
//move to option 1 ... a1p5 or option 2 ... a1p11
nextMove = "a1p3#a1p12";
break;
case 12:
nextMove = "a1p13";
break;
case 13:
nextMove = "a1p0";
break;
}
}
else
{
switch (b)
{
case 0:
nextMove = "a2p1";
break;
case 1:
nextMove = "a2p2";
break;
case 2:
nextMove = "a1p11";
break;
case 5:
nextMove = "a2p6";
break;
case 6:
nextMove = "a2p7";
break;
case 7:
nextMove = "a2p8";
break;
case 8:
nextMove = "a2p9";
break;
case 9:
nextMove = "a1p4";
break;
case 12:
nextMove = "a2p13";
break;
case 13:
nextMove = "a2p0";
break;
}
}
return nextMove;
}
void AI_Move_Stone(string bname)
{
Debug.Log("Nxt:" + bname);
string nextPossibleMove = bname;
if (bname.Contains('#'))
{
int ran = Random.Range(0, 2);
List<string> list = bname.Split('#').ToList();
if (ran == 0)
{
bname = list[0];
}
else
{
bname = list[1];
}
Debug.Log("New Pick: " + bname);
}
char[] c = bname.ToCharArray();
int a = int.Parse(c[1].ToString());
int b;
if (c.Length < 5)
{
b = int.Parse(c[3].ToString());
}
else
{
string s = c[3].ToString() + c[4].ToString();
b = int.Parse(s);
}
//check if the selected piece is a possible
if (nextPossibleMove.Contains("#"))
{
List<string> listStrLineElements = nextPossibleMove.Split('#').ToList();
if (listStrLineElements[0] == bname)
{
RemoveStoneFromInv(2, a, b, invPos);
}
else
{
if (listStrLineElements[1] == bname)
{
RemoveStoneFromInv(2, a, b, invPos);
}
else
{
StartCoroutine(invalidMove2());
}
}
}
else
{
if (nextPossibleMove == bname)
{
RemoveStoneFromInv(2, a, b, invPos);
}
else
{
StartCoroutine(invalidMove2());
}
}
}
//visuals
//Spawns Stones in the array
void spawnDelayTest(int type, int pos, int array, int delay)
{
if (array == 1)
{
if (type == 0)
{
GameObject g = Instantiate(lightStone);
float y = arr1Spawner[pos].transform.position.y + (delay * 1);
Vector3 v = new Vector3(arr1Spawner[pos].transform.position.x, y, arr1Spawner[pos].transform.position.z);
g.transform.position = v;
g.transform.parent = arr1Spawner[pos].transform;
}
else
{
GameObject g = Instantiate(darkStone);
float y = arr1Spawner[pos].transform.position.y + (delay * 1);
Vector3 v = new Vector3(arr1Spawner[pos].transform.position.x, y, arr1Spawner[pos].transform.position.z);
g.transform.position = v;
g.transform.parent = arr1Spawner[pos].transform;
}
}
else
{
if (type == 0)
{
GameObject g = Instantiate(lightStone);
float y = arr2Spawner[pos].transform.position.y + (delay * 1);
Vector3 v = new Vector3(arr2Spawner[pos].transform.position.x, y, arr2Spawner[pos].transform.position.z);
g.transform.position = v;
g.transform.parent = arr2Spawner[pos].transform;
}
else
{
GameObject g = Instantiate(darkStone);
float y = arr2Spawner[pos].transform.position.y + (delay * 1);
Vector3 v = new Vector3(arr2Spawner[pos].transform.position.x, y, arr2Spawner[pos].transform.position.z);
g.transform.position = v;
g.transform.parent = arr2Spawner[pos].transform;
}
}
}
//Spawns Stones in Inv
void spawnInventoryNew2(int type, int pos)
{
if (P1)
{
if (type == 1)
{
GameObject g = Instantiate(lightStone);
g.transform.position = p1InvPos[pos].transform.position;
g.transform.parent = p1InvPos[pos].transform;
g.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeAll;
}
else
{
GameObject g = Instantiate(darkStone);
g.transform.position = p1InvPos[pos].transform.position;
g.transform.parent = p1InvPos[pos].transform;
g.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeAll;
}
}
else
{
if (type == 1)
{
GameObject g = Instantiate(lightStone);
g.transform.position = p2InvPos[pos].transform.position;
g.transform.parent = p2InvPos[pos].transform;
g.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeAll;
}
else
{
GameObject g = Instantiate(darkStone);
g.transform.position = p2InvPos[pos].transform.position;
g.transform.parent = p2InvPos[pos].transform;
g.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeAll;
}
}
}
void move(int i)
{
InvP2[invSelectedlastP2].SetActive(false);
InvP2[i].SetActive(true);
invSelectedlastP2 = i;
SelectStoneInv(2, i);
Debug.Log("Curr: a" + ai_arr + "p" + ai_pos);
AI_Move_Stone(NextMove(ai_arr, ai_pos));
AI_Inv();
if (ai_arr == 2 && ai_pos == 2)
{
ai_arr = 1;
ai_pos = 11;
}
else
{
if (ai_arr == 2 && ai_pos == 9)
{
ai_arr = 1;
ai_pos = 4;
}
else
{
ai_pos++;
}
}
}
}
Images Доказательство существования ребенка