【发布时间】:2021-08-03 04:06:28
【问题描述】:
我是 Unity 的新手,我一直在关注并结合教程中的示例,使用本教程中的 3d 骰子组合一个简单的棋盘游戏样演示:https://www.youtube.com/watch?v=LHQ4ynQhPLY 和使用本教程的棋盘游戏瓷砖设置:@ 987654322@ 以及本教程中的回合制系统:https://www.youtube.com/watch?v=W8ielU8iURI
虽然我有一个完全可用的 3D 骰子,并且我可以让我的棋子移动适当数量的空间,但我发现自己很难融入回合制方面。
我的项目文件可以在这里下载:https://drive.google.com/drive/folders/1Odj3iqeYAaO3lnkzGOjwyxIdL0g00Xge?usp=sharing
对于那些不愿意下载项目文件的人,我将在此处尝试详细说明:
我有六个主要脚本:Dice.cs、DiceSide.cs、ButtonHandler.cs、PlayerPiece.cs、Route.cs 和 GameControl.cs。
我排除了 DiceSide.cs,因为此代码没有损坏。它只是检测哪一边在地上,这样我就可以检测到另一边是骰子的值,它存储在下面代码中的 diceValue 变量中。
我还排除了 Route.cs,因为它也没有损坏。它根据“棋盘”游戏对象的子对象的位置定义玩家棋子的路径。
最后,我还排除了 ButtonHandler.cs,它只是一个简单的函数,它告诉按钮何时被单击以使用 Dice.cs 中的 RollDice() 函数掷骰子
Dice.cs(附加到“Die”预制件):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Dice : MonoBehaviour
{
Rigidbody rb;
bool hasLanded;
bool thrown;
Vector3 initPosition;
public int diceValue;
public DiceSide[] diceSides;
public bool IsDoneRolling;
public int whosTurn = 1;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
initPosition = transform.position;
rb.useGravity = false;
}
// Update is called once per frame
void Update()
{
if (rb.IsSleeping() && !hasLanded && thrown)
{
hasLanded = true;
rb.useGravity = false;
rb.isKinematic = true;
SideValueCheck();
if (whosTurn == 1)
{
GameControl.MovePlayer(1);
}
else if (whosTurn == -1)
{
GameControl.MovePlayer(2);
}
whosTurn *= -1;
}
else if (rb.IsSleeping() && hasLanded && diceValue == 0)
{
RollAgain();
}
}
public void RollDice()
{
if (!thrown && !hasLanded)
{
IsDoneRolling = false;
thrown = true;
rb.useGravity = true;
rb.AddTorque(Random.Range(0,250), Random.Range(0,250), Random.Range(0,250));
}
else if (thrown && hasLanded)
{
Reset();
}
}
void Reset()
{
transform.position = initPosition;
thrown = false;
hasLanded = false;
rb.useGravity = false;
rb.isKinematic = false;
IsDoneRolling = true;
}
void RollAgain()
{
Reset();
IsDoneRolling = false;
thrown = true;
rb.useGravity = true;
rb.AddTorque(Random.Range(0,250), Random.Range(0,250), Random.Range(0,250));
}
void SideValueCheck()
{
diceValue = 0;
foreach (DiceSide side in diceSides)
{
if (side.OnGround())
{
diceValue = side.sideValue;
Debug.Log(diceValue + " has been rolled!");
}
}
}
}
PlayerPiece.cs(附加到两个玩家游戏对象预制件中的每一个):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerPiece : MonoBehaviour
{
public Route currentRoute;
int routePosition;
public bool isMoving;
public bool moveAllowed;
public static int steps = 0;
// Update is called once per frame
void Update()
{
if (!isMoving)
{
StartCoroutine(Move());
moveAllowed = false;
}
}
IEnumerator Move()
{
if (isMoving)
{
yield break;
}
isMoving = true;
while (steps > 0)
{
Debug.Log("Route position: "+routePosition);
routePosition++;
routePosition %= currentRoute.childNodeList.Count;
Vector3 nextPos = currentRoute.childNodeList[routePosition].position;
while (MoveToNextNode(nextPos)) { yield return null; }
yield return new WaitForSeconds(0.1f);
steps--;
}
isMoving = false;
}
bool MoveToNextNode(Vector3 goal)
{
return goal != (transform.position = Vector3.MoveTowards(transform.position, goal, 8f * Time.deltaTime));
}
}
GameControl.cs(附加到一个空的游戏对象):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameControl : MonoBehaviour
{
private static GameObject player1, player2;
public static int diceSideThrown = 0;
// Start is called before the first frame update
void Start()
{
player1 = GameObject.Find("Player1-Piece");
player2 = GameObject.Find("Player2-Piece");
player1.GetComponent<PlayerPiece>().moveAllowed = false;
player2.GetComponent<PlayerPiece>().moveAllowed = false;
}
// Update is called once per frame
void Update()
{
if (player1.GetComponent<PlayerPiece>().moveAllowed)
{
//Move the player 1 piece... code in PlayerPiece.cs
}
if (player2.GetComponent<PlayerPiece>().moveAllowed)
{
//Move the player 2 piece... code in PlayerPiece.cs
}
}
public static void MovePlayer(int playerToMove)
{
switch (playerToMove)
{
case 1:
player1.GetComponent<PlayerPiece>().moveAllowed = true;
break;
case 2:
player2.GetComponent<PlayerPiece>().moveAllowed = true;
break;
}
}
}
所以应该发生的是我单击按钮,Dice.cs 中的 RollDice() 函数触发(工作),它掷骰子并生成玩家必须移动(工作)的空间值,然后只有玩家1 应该移动该数量的空格(不起作用,显然因为这部分在 GameControl.cs 中没有连接,但是 PlayerPiece.cs 中的移动代码在我的非回合测试中被证明可以工作)。玩家 1 完成移动后,单击相同的按钮应该掷骰子,重复这些步骤,但只有玩家 2 应该移动新生成的空格数。
我知道所有部件都在那里,但我不知道如何让它们组合在一起以按预期工作。
非常感谢您的帮助。
【问题讨论】:
-
GetComponent并不便宜,考虑缓存一次并使用缓存的值。也许使用数组或列表而不是单个变量,这样您就可以拥有两个以上的玩家。投票决定何时搬入更新似乎不是最好的主意。最好根据某些事件触发运动,例如掷骰子。那么你只需要一个值来跟踪下一个应该移动的玩家的索引。 -
对...我是unity新手,所以你用的那些词的一半对我来说意义不大。我需要知道如何做你所建议的事情,就像你所建议的想法一样。您提出的事件建议本质上是实现的:当掷骰子时,它会设置允许玩家移动的开关。问题是,他们不动,因为我不知道如何让 GameControl 实现这一点。
-
你现在有了一些零件,虽然它们可能有点分散。为什么
movePlayer不让玩家直接移动而不是设置一个变量并希望它在下一次更新中被拾取? -
因为我不知道更好。我是新来的团结。我正在寻找一种让所有这些部分协同工作的方法。此刻,他们根本不动。感谢您的帮助。