我目前正在 Unity 引擎中开发一款三消游戏类型,并为此使用了一些宝石艺术品。我遇到过一种情况,将宝石位置存储在二维数组中并交换它们后,我需要再次更新数组。
我有两个问题:
考虑到已经更新过的二维数组,为什么我们还需要再次更新它? 这个概念在编程中叫什么? 您能推荐一本书或教程来了解更多信息吗?
请注意,无需阅读所有代码;请只关注我在评论中提到的部分
1级:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Board : MonoBehaviour
{
public int width;
public int height;
public GameObject backgroundTilePrefab;
public Gem[] gems;
//this one
public Gem[,] allGems;
public float gemSpeed;
public MatchFinder matchFinder;
private void Awake()
{
matchFinder = FindObjectOfType<MatchFinder>();
}
private void Start()
{
//this one
allGems = new Gem[width, height];
Setup();
}
private void Update()
{
matchFinder.FindAllMatches();
}
private void Setup()
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
Vector2 pos = new Vector2(x, y);
GameObject backgroundTile = Instantiate(backgroundTilePrefab,pos,Quaternion.identity);
backgroundTile.transform.parent = transform;
backgroundTile.transform.name = "Background Tile " + x + "," + y;
int gemToUse = Random.Range(0, gems.Length);
int iterations = 0;
while (MatchesAt(new Vector2Int(x,y), gems[gemToUse]) && iterations < 100)
{
gemToUse = Random.Range(0, gems.Length);
print("already matched found");
iterations++;
}
SpawnGem(gems[gemToUse],new Vector2Int(x,y));
}
}
}
private void SpawnGem(Gem gemToSpawn,Vector2Int pos)
{
Gem gem = Instantiate(gemToSpawn,new Vector3(pos.x,pos.y,0),Quaternion.identity);
gem.transform.parent = transform;
gem.transform.name = "Gem " + pos.x + "," + pos.y;
//this one
allGems[pos.x, pos.y] = gem;
gem.SetupGem(pos,this);
}
bool MatchesAt(Vector2Int posToCheck, Gem gemToCheck)
{
if (posToCheck.x > 1)
{
if (allGems[posToCheck.x - 1,posToCheck.y].gemTypes == gemToCheck.gemTypes && allGems[posToCheck.x - 2, posToCheck.y].gemTypes == gemToCheck.gemTypes)
{
return true;
}
}
if (posToCheck.y > 1)
{
if (allGems[posToCheck.x, posToCheck.y - 1].gemTypes == gemToCheck.gemTypes && allGems[posToCheck.x, posToCheck.y -2].gemTypes == gemToCheck.gemTypes)
{
return true;
}
}
return false;
}
public void DestroyMatchesGemAt(Vector2Int pos)
{
if (allGems[pos.x,pos.y] != null)
{
if (allGems[pos.x,pos.y].isMatched)
{
Destroy(allGems[pos.x,pos.y].gameObject);
allGems[pos.x,pos.y] = null;
}
}
}
public void DestroyMatches()
{
for (int i=0; i < matchFinder.currentMatches.Count; i++)
{
if (matchFinder.currentMatches[i] != null)
{
DestroyMatchesGemAt(matchFinder.currentMatches[i].posIndex);
}
}
StartCoroutine(DecreaseRowCoroutine());
}
public int nullCounter;
IEnumerator DecreaseRowCoroutine()
{
yield return new WaitForSeconds(0.2f);
nullCounter = 0;
for (int x=0; x < width; x++)
{
for (int y=0;y<height;y++)
{
if (allGems[x,y] == null)
{
nullCounter++;
}else if (nullCounter > 0)
{
allGems[x, y - nullCounter] = allGems[x, y];
allGems[x, y - nullCounter].posIndex.y -= nullCounter;
allGems[x, y] = null;
}
}
}
}
}
2级:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gem : MonoBehaviour
{
public Vector2Int posIndex;
public Board board;
public enum GemTypes { blue, green, red,purple,yellow }
public GemTypes gemTypes;
public bool isMatched;
public Vector2Int previousPos;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (mousePressed && Input.GetMouseButtonUp(0))
{
mousePressed = false;
finalTouchPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
CalculateAngle();
}
if (Vector2.Distance(transform.position,posIndex) > 0.01f)
{
transform.position = Vector2.Lerp(transform.position, posIndex, board.gemSpeed * Time.deltaTime);
}else
{
transform.position = new Vector3(posIndex.x,posIndex.y);
board.allGems[posIndex.x,posIndex.y] = this;
}
}
public void SetupGem(Vector2Int posIndex,Board board)
{
this.posIndex = posIndex;
this.board = board;
}
public Vector2 firstTouchPosition;
public bool mousePressed;
public Vector2 finalTouchPosition;
public float swipeAngle;
private void OnMouseDown()
{
firstTouchPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
//Debug.Log(firstTouchPosition);
mousePressed = true;
}
private void CalculateAngle()
{
swipeAngle = Mathf.Atan2(finalTouchPosition.y - firstTouchPosition.y, finalTouchPosition.x - firstTouchPosition.x);
swipeAngle = swipeAngle * 180 / Mathf.PI;
print(swipeAngle);
if (Vector2.Distance(firstTouchPosition,finalTouchPosition) > 0.5f)
{
MovePieces();
}
}
Gem otherGem;
private void MovePieces()
{
previousPos = posIndex;
//drag left to right
if (swipeAngle < 45 && swipeAngle > -45 && posIndex.x < board.width - 1)
{
otherGem = board.allGems[posIndex.x + 1, posIndex.y];
otherGem.posIndex.x--;
posIndex.x++;
}
//drag down to up
else if (swipeAngle > 45 && swipeAngle < 135 && posIndex.y < board.height - 1)
{
otherGem = board.allGems[posIndex.x , posIndex.y + 1];
otherGem.posIndex.y--;
posIndex.y++;
}
//drag up to down
else if (swipeAngle < -45 && swipeAngle > -135 && posIndex.y > 0)
{
otherGem = board.allGems[posIndex.x, posIndex.y - 1];
otherGem.posIndex.y++;
posIndex.y--;
}
//drag right to left
else if (swipeAngle > 135 || swipeAngle < -135 && posIndex.x > 0)
{
otherGem = board.allGems[posIndex.x - 1, posIndex.y];
otherGem.posIndex.x++;
posIndex.x--;
}
//my main problem is these 2 following lines
board.allGems[posIndex.x, posIndex.y] = this;
board.allGems[otherGem.posIndex.x,otherGem.posIndex.y] = otherGem;
StartCoroutine(CheckMoveCoroutine());
}//MovePieces()
public IEnumerator CheckMoveCoroutine()
{
yield return new WaitForSeconds(0.5f);
//board.matchFinder.FindAllMatches();
if (otherGem != null)
{
if (!isMatched && !otherGem.isMatched)
{
otherGem.posIndex = posIndex;
posIndex = previousPos;
board.allGems[posIndex.x, posIndex.y] = this;
board.allGems[otherGem.posIndex.x, otherGem.posIndex.y] = otherGem;
}else
{
board.DestroyMatches();
}
}
}
}//类
如果我通过更新数组理解正确的话,你的意思是这部分:
private void SpawnGem(Gem gemToSpawn,Vector2Int pos)
{
Gem gem = Instantiate(gemToSpawn,new Vector3(pos.x,pos.y,0),Quaternion.identity);
gem.transform.parent = transform;
gem.transform.name = "Gem " + pos.x + "," + pos.y;
//this one
allGems[pos.x, pos.y] = gem;
gem.SetupGem(pos,this);
}
我认为您误解了
Instantiate
功能。当你调用 Instantiate
时,你应该给它一个对预制件的引用,然后它会将该预制件克隆到场景中的新游戏对象中。如果你给它一个场景中已经存在的游戏对象,它会做类似的事情(将其克隆到新的游戏对象中),这很可能不是所需的行为。
所以我认为这就是问题所在,
gem
是在这个方法中新创建的,没有人引用它,所以你需要在数组中分配它。实例化后,gem
和gemToSpawn
彼此无关。
或者也许我没有正确理解您的问题,如果是这样,请指定您遇到问题的代码部分,这些是要跟踪的很大一部分代码。