is using list of vector3 the best method for boardgame movement?
Ive seen a few forums but very little material on the style im looking for, i dont want the player to just move forward through the list. I want there to be interesections where you chose a direction, even if you want to go back the way you came. and the moment you do that things become super complex so im hoping someone will be kind enough to even just point me in the right direction. ive been stuck on this for a whlle. Ive already made rolling dice but i made a simple script version to base this concept on. i basically want that when you roll a 4(or whatever) the player is awarded the ability to move essentially 4 unity on the path. but i get lost when the idea that it wont be straight lines in any axis so i cant just increment my way through it i need what im guessing is a list of vector3
so i made a little code snippet as a bases, im still trying to wrap my head around c# so forgive my dumbness
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SimpleTest : MonoBehaviour
{
public int diceAmount = 0;
public int amountMoved = 0;
private List<Vector3> Rolls = new List<Vector3>(); //<im guessing
// Update is called once per frame
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
diceAmount = Random.Range(1, 6);
}
}
//im assuming i need some sort of for loop for each roll but i dont know how to properly call it
}
If you are moving in steps you could make them Local movements rather than World movements. Player relativity is much easier than working in the world space.
I'm not really understanding what you are asking... what is it you are trying to store? The positions of the board tiles that the player can move to?
Basically want to create a path and have the player move down incrimentally based on the dice roll value. It will be on a 3d map so it will be neither straight nor flat. So I was hoping I could place empty object along a path in my level and have the player Navigate along them based on the dice value.... I dunno it's hard to explain cuase I have grasped just how to do it.
Answer by sharat · Oct 16, 2015 at 11:54 PM
Okay, so there's a few things you seem to be asking(assuming you're doing a Mario Party style board). First, for the visual locations of the "playspaces" you probably should just have scene objects with a PlaySpace component on them. The physical locations should only affect the art and not any of the intersections logic.
For the gameplay logic, there are several different ways you can move forward depending on your plans for the game. One way would be to just to have each playspace have a link to the nodes it can reach from there. In most cases you'll have just 1(or 2 if you include backward movement). For intersections you'll have more possible nodes. In order to keep the player going in the same direction, you can store the previous location the player was on, and make sure that when they move forward they choose a different space than where they were. Then you just do a loop for the dice roll to move forward one space at a time(with some sort of special logic for intersections with more than one possible location).
Sample Code:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
class PlaySpace : MonoBehaviour
{
public List<PlaySpace> connectedSpaces = new List<PlaySpace>();
};
public class PlayerToken : MonoBehaviour
{
// Assign to starting tile in editor!
public PlaySpace currentTile;
// Keep track of where you came from so you can backtrack. As per NewPath's suggestion, a Stack will let you backtrack more than 1 space in the case of an intersection.
public Stack<PlaySpace> travelledTiles = new Stack<PlaySpace>();
// How many squares you need to move
public int numSpacesToMove = 0;
// This is just a placeholder for movement animation. You can change this however you like
public float movementSpeed = 1.0f;
// How far in the move animation you are
private float movementProgress = 0.0f;
// The last dice roll, you probably don't need to store this except for UI hooks
public int diceAmount = 0;
// Are we waiting at an intersection?
public bool atIntersection = false;
void Update()
{
// Really, you only want to do this when you are finished moving
// i.e. after all interesection logic is done and the animation has completed
// That's why I added numSpacesToMove == 0
if (Input.GetButtonDown("Fire1") && numSpacesToMove == 0)
{
diceAmount = Random.Range(1, 6);
numSpacesToMove += diceAmount;
}
if (atIntersection)
{
// Some sort of choice input here!
}
// Update movement
if (numSpacesToMove != 0 && !atIntersection)
{
// Do animation for movement. (movementProgress is the animation progress toward reaching the next tile. You'd probably want to replace it with waiting for real animations at some point.)
movementProgress += movementSpeed * Time.deltaTime;
// Try to find the next square to go to in this direction
PlaySpace nextSquare = FindNextSquare();
// Depending on how fast the animation is, we may have reached multiple new tiles
while(nextSquare != null && movementProgress >= 1.0f && numSpacesToMove != 0)
{
movementProgress -= 1.0f;
if (numSpacesToMove < 0)
{
// If moving backward, we just remove the last tile and set ourselves there
currentTile = travelledTiles.Pop();
numSpacesToMove++;
}
else
{
// If moving forward, we need to remember where we were in case we move backward later, as well as to limit our options for moving forward.
travelledTiles.Push(currentTile);
currentTile = nextSquare;
numSpacesToMove--;
}
// If we haven't reached the end of the squares we're trying to move. Find the next one in the list
if (numSpacesToMove != 0)
nextSquare = FindNextSquare();
else
nextSquare = null;
}
// If we're at either an end point or a decision point, we stop at this tile
if (nextSquare == null)
{
if (!atIntersection && numSpacesToMove != 0)
{
// If we're not at an intersection, we must have run out of spaces to go!
Debug.Log("Dead end at " + currentTile.name + " had " + numSpacesToMove + " squares left!");
numSpacesToMove = 0;
}
movementProgress = 0.0f;
transform.position = currentTile.transform.position;
}
else
{
// Simple interpolation for when we are between two tiles
transform.position = Vector3.Lerp(currentTile.transform.position, nextSquare.transform.position, movementProgress);
}
}
}
// Figure out where we're going and where we came from!
PlaySpace FindNextSquare()
{
PlaySpace prevSquare = null, nextSquare = null;
if (travelledTiles.Count > 0)
prevSquare = travelledTiles.Peek(); // Look at the last tile you were at.
// If going backwards, we don't have a choice
if (numSpacesToMove < 0)
nextSquare = prevSquare;
else
{
// Here we keep a list of all tiles we can go to from our current tile, excluding the previous square
List<PlaySpace> availableSquares = new List<PlaySpace>();
foreach(PlaySpace space in currentTile.connectedSpaces)
{
if(space != prevSquare)
availableSquares.Add(space);
}
// If we have exactly one square, then we can keep moving
if (availableSquares.Count == 1)
nextSquare = availableSquares[0];
// But if we are at an intersection, we have to stop movement and wait for intersection input
else if (availableSquares.Count > 1)
{
atIntersection = true;
return null;
}
}
return nextSquare;
}
}
thats right where im stuck, ill try and discribe it breifly but basically if i roll a 4 the object will go to the fourth square and when i roll a two. ins$$anonymous$$d of going to the 6th square it goes to the 2nd. it just keep reseting itself. i tried to create a value that incremented with no luck. this is basically the short and skinny of what i got
i = dicevalue;
transform.position = locationsPoints [i].transform.position;
do you know how i could change it, i dont want it to slimply either add or subtract the dice value. cuase one intersection breaks the numeric connection between the dice and the board, i feel like it so simple and i just cant see it! anyways i dont blame yah if your too busy to take a shot at it, your answer was still pretty helpful
I added a bunch of sample code above. You want to have a tree structure for your points rather than a simple array. @NewPath has a simple example of that in his answer. $$anonymous$$y answer has a version that's a component assu$$anonymous$$g you'd want to move these points in the editor and just use the transform value for the locations..
hey heres a weird question, am i supposed to break the classes up so theyre there own script? i thought the name of the script had to match the class otherwise theres issues that arise with unity. ( i know c# normally allows multiple classes in a single script.)
im getting an error message for each "public" that occurs before it inherits from monodevelop, unexpected symbol "public" needs a "type"
edit
im actually chasing errors here, first it told me that the name "nextSquare" didnt exsist so i created a public PlaySpace nextSquare, and now its telling me Playspace doesnt contain a position. which is dumb cuase it looks like its set up to drop them in through the inspector but i can till i get rid of the compiling errors..
oh wow! look at how much youve done here! i am gunna give this a whirl when i get on my desktop. I cant tell you how awesome it is to see someone take this much time to help someone, thanks! ill let you know how it ends up
I debated saying anything, as youve done alot for me here. but ive struggled with trying to figure out how to do this for so long. and now that someone has helped me, its so close. i know i the problem im having is becuase I$$anonymous$$ doing something wrong, and youve given me the answer i just need to understand a few aspects.
so things ive done:
deleted the "public" before the $$anonymous$$onoDevelop inheritance
seperated the classes into seperate scripts "PlayerToken" + "PlaySpace"
added public playSpace nextSquare;(becuase it kept telling me it didnt exsist)
its the else statement on line 90 thats given me problems, it keeps saying it doesnt have a position for nextSpace or currentTile.
i feel like it has everything to do with playspace, i might not be using this funtion properally. Im really not fimiliar with Icollections. my 3d objects in the world each have a script on them making them "PlaySpace" class and have been draged into the lplaySpace list but yet they dont get pulled into the equation. Am i assigning them incorrectly?
every roll dice comes to the dead end print out, seems like it doesnt know where or if theres even another object to move to.
this is a shot in the dark, youve totally already gone above and beyond on the subject. Im just posting this incase you do get a chance or maybe someone has the answer
Sounds like the problem is that you aren't filling in the connections between the PlaySpaces in the editor. If you look at the PlaySpace in the inspector you should see something that says Connected Spaces with a size of 0. You can change that size number to a 2(or however many you want). Then you'll have some empty slots that say None(PlaySpace). You can then drag another PlaySpace object into that slot.
I'd recommend looking at some of the Intro to Unity tutorials to learn how to use Lists in the editor and other things. It's easy to get overwhelmed, so it may be better to just do a basic runthrough of a tutorial even if it's for a different game-type than you have in $$anonymous$$d. Good luck!
Answer by NewPath · Oct 17, 2015 at 12:25 PM
Based on your comments, I believe for the board tiles you want a simple undirected graph structure. Each node would look something vaguely like this:
public class Node
{
public Transform Position { get; set; }
public ICollection<Node> Nodes { get; set; }
}
This handles decisions about intersections easily, if there's only one link don't give them an option, if there's more than one, let them chose. To hold the player's movements, I would use a standard stack (found in System.Collections.Generic):
var movements = new Stack<Node>();
So as the player traverses the graph, push each node on the stack. If they want to backtrack, you just pop the stack however many times.