Friday, August 25, 2017

unity - Tile manipulation script doesn't work in build but works in editor


I have 100 cubes which makes a plane, and I have a script that moves those cubes in random patterns according to random chosen methods.


For example, in the method LeftPartFalls, only the cubes on the left part of the plane change materials, then fall down, then change materials again, then rise back up.



In the other methods I do the same actions but in the different patterns like:



  • only the right part falls

  • only the first, second, third, fourth and fifth lines fall


This all works fine when I test it in the Unity editor.


But when I build it for Android, it does the changing color and falling down things but not in the pattern that I wanted. Instead I get a kind of mosaic pattern, and I noticed it does that it does this in 2 random-looking mosaic patterns. For example, the first might look like this:


Example of random mosaic pattern


And after the cubes that are low in that screenshot rise back up, the pattern reverses, with the cubes that were high taking their turn to fall. And then the cycle repeats.


Why is this behaviour different on Android than in editor, and how can I fix it?





This is one of my methods to make a pattern of cubes change colour, fall, and rise:


void LeftPartFalls()
{
if (LeftPartMat)
{
for (int i = 0; i < Mathf.Min(5, FirstLine.Length); i++) // COLOR CHANGE
{
FirstLine[i].gameObject.GetComponent().material = greyMAT;
SecondLine[i].gameObject.GetComponent().material = greyMAT;

ThirdLine[i].gameObject.GetComponent().material = greyMAT;
FourthLine[i].gameObject.GetComponent().material = greyMAT;
FiftLine[i].gameObject.GetComponent().material = greyMAT;
SixthLine[i].gameObject.GetComponent().material = greyMAT;
SeventhLine[i].gameObject.GetComponent().material = greyMAT;
EighthLine[i].gameObject.GetComponent().material = greyMAT;
NinthLine[i].gameObject.GetComponent().material = greyMAT;
TenthLine[i].gameObject.GetComponent().material = greyMAT;
}
}

if (!LeftPartMat)
{
for (int i = 0; i < Mathf.Min(5, FirstLine.Length); i++) // COLOR CHANGE 2
{
FirstLine[i].gameObject.GetComponent().material = whiteMAT;
SecondLine[i].gameObject.GetComponent().material = whiteMAT;
ThirdLine[i].gameObject.GetComponent().material = whiteMAT;
FourthLine[i].gameObject.GetComponent().material = whiteMAT;
FiftLine[i].gameObject.GetComponent().material = whiteMAT;
SixthLine[i].gameObject.GetComponent().material = whiteMAT;

SeventhLine[i].gameObject.GetComponent().material = whiteMAT;
EighthLine[i].gameObject.GetComponent().material = whiteMAT;
NinthLine[i].gameObject.GetComponent().material = whiteMAT;
TenthLine[i].gameObject.GetComponent().material = whiteMAT;
}
}

if (LeftPartFall) // FALL DOWN
{
for (int i = 0; i < Mathf.Min(5, FirstLine.Length); i++)

{
FirstLine[i].gameObject.transform.position = Vector3.Lerp(FirstLine[i].transform.position, new Vector3(FirstLine[i].transform.position.x, -4f, FirstLine[i].transform.position.z), t);
SecondLine[i].gameObject.transform.position = Vector3.Lerp(SecondLine[i].transform.position, new Vector3(SecondLine[i].transform.position.x, -4f, SecondLine[i].transform.position.z), t);
ThirdLine[i].gameObject.transform.position = Vector3.Lerp(ThirdLine[i].transform.position, new Vector3(ThirdLine[i].transform.position.x, -4f, ThirdLine[i].transform.position.z), t);
FourthLine[i].gameObject.transform.position = Vector3.Lerp(FourthLine[i].transform.position, new Vector3(FourthLine[i].transform.position.x, -4f, FourthLine[i].transform.position.z), t);
FiftLine[i].gameObject.transform.position = Vector3.Lerp(FiftLine[i].transform.position, new Vector3(FiftLine[i].transform.position.x, -4f, FiftLine[i].transform.position.z), t);
SixthLine[i].gameObject.transform.position = Vector3.Lerp(SixthLine[i].transform.position, new Vector3(SixthLine[i].transform.position.x, -4f, SixthLine[i].transform.position.z), t);
SeventhLine[i].gameObject.transform.position = Vector3.Lerp(SeventhLine[i].transform.position, new Vector3(SeventhLine[i].transform.position.x, -4f, SeventhLine[i].transform.position.z), t);
EighthLine[i].gameObject.transform.position = Vector3.Lerp(EighthLine[i].transform.position, new Vector3(EighthLine[i].transform.position.x, -4f, EighthLine[i].transform.position.z), t);
NinthLine[i].gameObject.transform.position = Vector3.Lerp(NinthLine[i].transform.position, new Vector3(NinthLine[i].transform.position.x, -4f, NinthLine[i].transform.position.z), t);

TenthLine[i].gameObject.transform.position = Vector3.Lerp(TenthLine[i].transform.position, new Vector3(TenthLine[i].transform.position.x, -4f, TenthLine[i].transform.position.z), t);
}
}
if (!LeftPartFall) // RISE UP
{
for (int i = 0; i < Mathf.Min(5, FirstLine.Length); i++)
{
FirstLine[i].gameObject.transform.position = Vector3.Lerp(FirstLine[i].transform.position, new Vector3(FirstLine[i].transform.position.x, 0f, FirstLine[i].transform.position.z), t);
SecondLine[i].gameObject.transform.position = Vector3.Lerp(SecondLine[i].transform.position, new Vector3(SecondLine[i].transform.position.x, 0f, SecondLine[i].transform.position.z), t);
ThirdLine[i].gameObject.transform.position = Vector3.Lerp(ThirdLine[i].transform.position, new Vector3(ThirdLine[i].transform.position.x, 0f, ThirdLine[i].transform.position.z), t);

FourthLine[i].gameObject.transform.position = Vector3.Lerp(FourthLine[i].transform.position, new Vector3(FourthLine[i].transform.position.x, 0f, FourthLine[i].transform.position.z), t);
FiftLine[i].gameObject.transform.position = Vector3.Lerp(FiftLine[i].transform.position, new Vector3(FiftLine[i].transform.position.x, 0f, FiftLine[i].transform.position.z), t);
SixthLine[i].gameObject.transform.position = Vector3.Lerp(SixthLine[i].transform.position, new Vector3(SixthLine[i].transform.position.x, 0f, SixthLine[i].transform.position.z), t);
SeventhLine[i].gameObject.transform.position = Vector3.Lerp(SeventhLine[i].transform.position, new Vector3(SeventhLine[i].transform.position.x, 0f, SeventhLine[i].transform.position.z), t);
EighthLine[i].gameObject.transform.position = Vector3.Lerp(EighthLine[i].transform.position, new Vector3(EighthLine[i].transform.position.x, 0f, EighthLine[i].transform.position.z), t);
NinthLine[i].gameObject.transform.position = Vector3.Lerp(NinthLine[i].transform.position, new Vector3(NinthLine[i].transform.position.x, 0f, NinthLine[i].transform.position.z), t);
TenthLine[i].gameObject.transform.position = Vector3.Lerp(TenthLine[i].transform.position, new Vector3(TenthLine[i].transform.position.x, 0f, TenthLine[i].transform.position.z), t);
}
}
}


This is the enumerator part, that chooses the random method:


private IEnumerator enumerator(float waitTime)
{
while (true)
{
RandomInt = Random.Range(1, 6);
if (RandomInt == 1)
{
LeftPartCalls = true;

LeftPartMat = true;
}
if (RandomInt == 2)
{
RightPartCalls = true;
RightPartMat = true;
}
if (RandomInt == 3)
{
VerticalStripeCalls = true;

VerticalStripeMat = true;
}
if (RandomInt == 4)
{
UpLeftDownRightCalls = true;
UpLeftDownRightMat = true;
}
if (RandomInt == 5)
{
UpRightDownLeftCalls = true;

UpRightDownLeftMat = true;
}
if (RandomInt == 6)
{
HorizontalStripeCalls = true;
HorizontalStripeMat = true;
}
if (RandomInt == 7)
{
CenterCalls = true;

CenterMat = true;
}
if (RandomInt == 8)
{
EdgeCalls = true;
EdgeMat = true;
}
if (RandomInt == 9)
{
SkewCalls = true;

SkewMat = true;
}
if (RandomInt == 10)
{
HorizontalWayCalls = true;
HorizontalWayMat = true;
}


yield return new WaitForSeconds(MoveT);

if (RandomInt == 1)
LeftPartFall = true;
if (RandomInt == 2)
RightPartFall = true;
if (RandomInt == 3)
VerticalStripeFall = true;
if (RandomInt == 4)
UpLeftDownRightFall = true;
if (RandomInt == 5)
UpRightDownLeftFall = true;

if (RandomInt == 6)
HorizontalStripeFall = true;
if (RandomInt == 7)
CenterFall = true;
if (RandomInt == 8)
EdgeFall = true;
if (RandomInt == 9)
SkewFall = true;
if (RandomInt == 10)
HorizontalWayFall= true;


t = 0f;
t += Time.deltaTime / 0.7f;

yield return new WaitForSeconds(3);
LeftPartFall = false;
LeftPartMat = false;
RightPartMat = false;
RightPartFall = false;
VerticalStripeMat = false;

VerticalStripeFall = false;
UpLeftDownRightFall = false;
UpLeftDownRightMat = false;
UpRightDownLeftFall = false;
UpRightDownLeftMat = false;
HorizontalStripeFall = false;
HorizontalStripeMat = false;
CenterFall = false;
CenterMat = false;
EdgeFall = false;

EdgeMat = false;
SkewFall = false;
SkewMat = false;
HorizontalWayFall = false;
HorizontalWayMat = false;
yield return new WaitForSeconds(4);
LeftPartCalls = false;
RightPartCalls = false;
VerticalStripeCalls = false;
UpLeftDownRightCalls = false;

UpRightDownLeftCalls = false;
HorizontalStripeCalls = false;
CenterCalls = false;
EdgeCalls = false;
SkewCalls = false;
HorizontalWayCalls = false;

if (MoveT >= 1.3f)
{
MoveT -= 0.7f;

}
if (MoveT <= 1.3f)
{
MoveT -= 0.6f;
}
if (MoveT <= 0.7f)
{
MoveT = 0.7f;
}
yield return new WaitForSeconds(MoveT);

}
}

Answer



It still doesn't look like we have enough information here to identify why your game behaves differently on Android, but I'd like to recommend we start with a clean slate to hopefully make the code simpler to understand, more concise, with less room for bugs to creep in. I'll build this up in pieces so it's easier to follow:


First, let's generate your plane of cubes by script, and store it in a 2D array so we don't need to juggle ten different variables to store all the lines:


public class FallingFloor : MonoBehaviour {

public Vector2Int size = new Vector2Int(10, 10);
public float spacing = 1f;
public MeshRenderer tilePrefab;

MeshRenderer[,] tiles;

void CreateFloor() {
// Define our tiles array in the appropriate size.
tiles = new MeshRenderer[size.x, size.y];

// Spawn the floor centered around this object's position.
Vector3 origin = transform.position + new Vector3(size.x, 0, size.y) * -0.5f * spacing;

// For each row, and each column, instantiate a tile.

for(int x = 0; x < size.x; x++) {
for(int y = 0; y < size.y; y++) {
tiles[x, y] = Instantiate(
tilePrefab,
new Vector3(x, 0, y) * spacing + origin,
Quaternion.identity
);
}
}
}


// ...

With all the tiles in one variable, it's easy to define functions that select different patterns of tiles. Let's follow the convention that our tile selection functions will populate a list with the desired tiles:


void SelectLeftHalf(List pattern) {
pattern.Clear();
for(int x = 0; x < size.x/2; x++) {
for(int y = 0; y < size.y; y++) {
pattern.Add(tiles[x, y]);
}

}
}

void SelectEverySecondRow(List pattern) {
pattern.Clear();
for(int x = 0; x < size.x; x++) {
for(int y = 0; y < size.y; y += 2) {
pattern.Add(tiles[x, y]);
}
}

}

void SelectCross(List pattern) {
pattern.Clear();
// Make sure we don't go out of bounds on non-square maps.
int limit = Mathf.Min(size.x, size.y);
for(int x = 0; x < limit; x++) {
pattern.Add(tiles[x, x]);
int y = size.y - 1 - x;
// Don't double-add the middle tile in the case of odd sizes.

if(x != y)
pattern.Add(tiles[x, y]);
}
}

// ...

Now we can simplify the falling and colour-changing animations to single functions each that act on a selected pattern of tiles:


void ChangeAllMaterials(List pattern, Material material) {
foreach(var renderer in pattern)

renderer.sharedMaterial = material;
}

IEnumerator SlideAllBlocks(List pattern, float startHeight, float endHeight, float duration) {
float progress = 0f;
while(progress < 1f) {
progress = Mathf.Clamp01(progress + Time.deltaTime/duration);

// Compute a height to move to, with an ease-out curve.
float height = Mathf.Lerp(startHeight, endHeight, 1 - (1 - progress) * (1 - progress));


// Set all blocks in the pattern to this height.
foreach(var renderer in pattern) {
var position = renderer.transform.position;
position.y = height;
renderer.transform.position = position;
}

// Wait one frame, then resume.
yield return null;

}
}

// ...

And our master loop can then just select a pattern, call these functions on it in our desired sequence, and repeat:


public Material fallingMaterial;
public Material risingMaterial;
public float fallSeconds = 3f;
public float fallHeight = -4f;

public float riseSeconds = 4f;

IEnumerator AnimationLoop(float moveSeconds) {
// Prep our variable for tracking the pattern of tiles we're acting on.
// Since this is a local variable, we can control exactly who gets to act on it,
// so anything that changes the pattern should be easy to track down.
var pattern = new List();

while(true) {
// Each cycle, select a randomly-chosen pattern of blocks.

int selection = Random.Range(1, 6);

switch(selection) {
case 1 : SelectLeftHalf(pattern); break;
case 2 : SelectRightHalf(pattern); break;
case 3 : SelectEverySecondRow(pattern); break;
case 4 : SelectEverySecondColumn(pattern); break;
case 5 : SelectCross(pattern); break;
}


// Change the material of all blocks in this pattern.
ChangeAllMaterials(pattern, fallingMaterial);

// Wait before we start to fall.
yield return new WaitForSeconds(moveSeconds);

// Chain control to our sliding method until the fall is complete.
yield return SlideAllBlocks(pattern, 0, fallHeight, fallSeconds);

// Done falling. Reset the materials and rise back up.

ChangeAllMaterials(pattern, risingMaterial);

// Chain control to our sliding method until the fall is complete.
yield return SlideAllBlocks(pattern, fallHeight, 0f, riseSeconds);

// Everything has risen and reset. Now adjust our moveSeconds for next cycle:
if (moveSeconds >= 1.3f) {
moveSeconds -= 0.7f;
} else if (moveSeconds <= 1.3f) {
moveSeconds = Mathf.Max(moveSeconds - 0.6f, 0.7f);

}

// Wait before starting the next cycle & choosing a new pattern.
yield return new WaitForSeconds(moveSeconds);
}
}

Now we don't need to rely on a small army of bool variables to coordinate all our actions. You should find an approach something like this makes your game behave more predictably, and makes it less laborious to add or change behaviour.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...