Graphics.DrawMesh has wired offset while scaling in Unity, why? - unity3d

I'm implementing after image effect currently and I meet a problem with Graphics.DrawMesh. The code shows below
public class AfterImage3DByCombine : MonoBehaviour
{
public class AfterImange
{
public Mesh mesh;
public Material material;
// public Matrix4x4 matrix;
public float duration;
public float time;
}
protected SkinnedMeshRenderer[] skinRenderers;
protected MeshFilter[] filters;
protected int filtersCount = 0;
public bool IncludeMeshFilter = true;
public Material EffectMaterial;
public float Duration = 5;
public float Interval = 0.2f;
public float FadeoutTime = 1;
private float mTime = 5;
private List<AfterImange> mAfterImageList = new List<AfterImange>();
protected virtual void Awake()
{
skinRenderers = GetComponentsInChildren<SkinnedMeshRenderer>();
if (IncludeMeshFilter)
{
filters = GetComponentsInChildren<MeshFilter>();
filtersCount = filters.Length;
}
}
//call from another place to have after image effect
public void Play()
{
if (skinRenderers.Length + filtersCount <= 0)
{
return;
}
mTime = Duration;
StartCoroutine(AddAfterImage());
}
IEnumerator AddAfterImage()
{
while (mTime > 0)
{
CreateImage();
yield return new WaitForSeconds(Interval);
mTime -= Interval;
}
yield return null;
}
void CreateImage()
{
CombineInstance[] combineInstances = new CombineInstance[skinRenderers.Length + filtersCount];
int index = 0;
for (int i = 0; i < skinRenderers.Length; i++)
{
var render = skinRenderers[i];
var mesh = new Mesh();
render.BakeMesh(mesh);
combineInstances[index] = new CombineInstance
{
mesh = mesh,
transform = render.gameObject.transform.localToWorldMatrix,
subMeshIndex = 0
};
index++;
}
for (int i = 0; i < filtersCount; i++)
{
var render = filters[i];
var temp = (render.sharedMesh != null) ? render.sharedMesh : render.mesh;
var mesh = (Mesh)Instantiate(temp);
combineInstances[index] = new CombineInstance
{
mesh = mesh,
transform = render.gameObject.transform.localToWorldMatrix,
subMeshIndex = 0
};
index++;
}
Mesh combinedMesh = new Mesh();
combinedMesh.CombineMeshes(combineInstances, true, true);
mAfterImageList.Add(new AfterImange
{
mesh = combinedMesh,
material = new Material(EffectMaterial),
time = FadeoutTime,
duration = FadeoutTime,
});
}
void LateUpdate()
{
bool needRemove = false;
foreach (var image in mAfterImageList)
{
image.time -= Time.deltaTime;
if (image.material.HasProperty("_Color"))
{
Color color = Color.red;
color.a = Mathf.Max(0, image.time / image.duration);
image.material.SetColor("_Color", color);
}
Matrix4x4 mat = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one * 2f);
//public static void DrawMesh(Mesh mesh, Matrix4x4 matrix, Material material, int layer, Camera camera, int submeshIndex, MaterialPropertyBlock properties, ShadowCastingMode castShadows);
Graphics.DrawMesh(image.mesh, Matrix4x4.identity, image.material, gameObject.layer, null, 0, null, false);
if (image.time <= 0)
{
needRemove = true;
}
}
if (needRemove)
{
mAfterImageList.RemoveAll(x => x.time <= 0);
}
}
}
Since my prefab has 0.5 times scaling while it's running, then I pass a matrix with two times scaling Matrix4x4 mat = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one * 2f); into
Graphics.DrawMesh.
Then, the mesh created by Graphics.DrawMesh isn't in its original position, there is an offset between original mesh and created mesh.
And if I passed Matrix4x4.Identity into Graphics.DrawMesh, the created mesh will have 0.5 times scaling, which looks smaller than original mesh.
Why there is an offset and how could I eliminate the offset without chaning the prefab's scale?

Related

How to enable Trajectory on a ball when being pulled?

So I have made a Trajectory for my ball.
This is the code...
{
[Header("Line renderer veriables")]
public LineRenderer line;
[Range(2, 30)]
public int resolution;
Rigidbody rb;
[Header("Formula variables")]
public Vector3 velocity;
public float yLimit;
private float g;
[Header("Linecast variables")]
[Range(2, 30)]
public int linecastResolution;
public LayerMask canHit;
public Rigidbody ballRigid;
private void Start()
{
rb = GetComponent<Rigidbody>();
g = Mathf.Abs(Physics.gravity.y);
}
private void Update()
{
RenderArc();
}
private void RenderArc()
{
line.positionCount = resolution + 1;
line.SetPositions(CalculateLineArray());
}
private Vector3[] CalculateLineArray()
{
Vector3[] lineArray = new Vector3[resolution + 1];
var lowestTimeValueX = MaxTimeX() / resolution;
var lowestTimeValueZ = MaxTimeZ() / resolution;
var lowestTimeValue = lowestTimeValueX > lowestTimeValueZ ? lowestTimeValueZ : lowestTimeValueX;
for (int i = 0; i < lineArray.Length; i++)
{
var t = lowestTimeValue * i;
lineArray[i] = CalculateLinePoint(t);
}
return lineArray;
}
private Vector3 HitPosition()
{
var lowestTimeValue = MaxTimeY() / linecastResolution;
for (int i = 0; i < linecastResolution + 1; i++)
{
RaycastHit rayHit;
var t = lowestTimeValue * i;
var tt = lowestTimeValue * (i + 1);
if (Physics.Linecast(CalculateLinePoint(t), CalculateLinePoint(tt), out rayHit, canHit))
return rayHit.point;
}
return CalculateLinePoint(MaxTimeY());
}
private Vector3 CalculateLinePoint(float t)
{
float x = rb.velocity.x * t;
float z = rb.velocity.z * t;
float y = (rb.velocity.y * t) - (g * Mathf.Pow(t, 2) / 2);
return new Vector3(x + transform.position.x, y + transform.position.y, z + transform.position.z);
}
private float MaxTimeY()
{
var v = rb.velocity.y;
var vv = v * v;
var t = (v + Mathf.Sqrt(vv + 2 * g * (transform.position.y - yLimit))) / g;
return t;
}
private float MaxTimeX()
{
if (IsValueAlmostZero(velocity.x))
SetValueToAlmostZero(ref velocity.x);
var x = rb.velocity.x;
var t = (HitPosition().x - transform.position.x) / x;
return t;
}
private float MaxTimeZ()
{
if (IsValueAlmostZero(velocity.z))
SetValueToAlmostZero(ref velocity.z);
var z = rb.velocity.z;
var t = (HitPosition().z - transform.position.z) / z;
return t;
}
private bool IsValueAlmostZero(float value)
{
return value < 0.0001f && value > -0.0001f;
}
private void SetValueToAlmostZero(ref float value)
{
value = 0.0001f;
}
public void SetVelocity(Vector3 velocity)
{
this.velocity = velocity;
}
}
I have a slingshot With a objectholder(which holds the ball). Also I have a robot arm that pulls the objectholder with its clawhand . The arm pulls it but The ball is in kinematic until the claw opens. The objectholder contains springs joints so its able to go back to its place and make a elastic effect and throw the ball. Now with this code when I pull the trajectory doesnt appear until i let go and it picks a target by itself and just follows the line. What i want is when I pull it the trajectory shows and the user is able to pick the target or move the trajectory. Note: (If i get rid of rb.velocity and replace it with velocity, then when i pull it it shows the trajectory and I can change the target but when i open my claw and the ball shoots, it doesnt follow the trajectory, its like the trajectory follows the ball. Can someone helps? This code makes the ball follows the line so its good I just have that problem.
My other code when clawhand opens and closes and ball is kinematic or not:
public class open2close : MonoBehaviour
{
public float speed;
private Animation anim;
[SerializeField] bool isClosed;
private bool isKinematic;
public Transform rightClaw;
public Vector3 offset;
public Rigidbody Rb2;
public Rigidbody ball_Rigid;
void Start()
{ Debug.Log(transform.position);
Console.WriteLine("test");
anim = gameObject.GetComponent<Animation>();
Rb2 = Rb2.GetComponent<Rigidbody>();
ball_Rigid = ball_Rigid.GetComponent<Rigidbody>();
//Rb2.isKinematic = true;
}
void Update()
{
// Debug.Log(transform.position);
if (Input.GetKey(KeyCode.X))
{
anim.Play("clawopen");
isClosed = false;
Rb2.isKinematic = false;
ball_Rigid.isKinematic = false;
}
if (Input.GetKey(KeyCode.Y))
{
anim.Play("clawclose");
isClosed = true;
Rb2.isKinematic = true;
ball_Rigid.isKinematic = true;
}
}
private void OnTriggerStay(Collider spring2)
{
Rigidbody colRb = spring2.attachedRigidbody;
if (isClosed && spring2.transform.gameObject.tag == "Player")
{
spring2.transform.position = rightClaw.transform.position + offset;
}
}
private void OnTriggerExit(Collider spring2)
{
Rigidbody colRb = spring2.attachedRigidbody;
if (isClosed && spring2.transform.gameObject.tag == "Player")
{
colRb.WakeUp();
}
}
}

Sewing up two meshes

Good afternoon! I'm trying to sew up two meshes. I do this as follows: first I convert the sprite into a mesh, then I duplicate the resulting mesh, shift it along the "z" axis, invert it, and then sew it up. But I faced such a problem: he sews rectangular meshes well, but in circular meshes there are some defects on the sides. So, how can you sew up these sides? (Materials and code)
public class ConvertSpriteInMesh : MonoBehaviour
{
public Sprite sprite;
private MeshDraft meshDraft = new MeshDraft();
private Mesh mesh;
void Start()
{
GetComponent<MeshFilter>().mesh = SpriteToMesh(sprite);
SewingUp();
}
/// <summary>
/// Sewing up nets
/// </summary>
private void SewingUp()
{
mesh = GetComponent<MeshFilter>().mesh;
meshDraft = new MeshDraft(mesh);
int leftVertical = mesh.vertices.Length / 2; // getting the beginning of the left vertical of the mesh
int index = mesh.vertices.Length;
for (int i = 0; i < leftVertical - 1; i++)
{
meshDraft.AddQuad(mesh.vertices[i], mesh.vertices[i+1], mesh.vertices[i + leftVertical + 1],mesh.vertices[i+leftVertical],
index);
index += 4;
}
GetComponent<MeshFilter>().mesh = meshDraft.ToMesh(); // assign the resulting mesh
}
/// <summary>
/// Convert Sprite to Mesh
/// </summary>
/// <param name="_sprite"></param>
/// <returns></returns>
private Mesh SpriteToMesh(Sprite _sprite)
{
// declaring variables
Mesh mesh = new Mesh();
Vector3[] _verticles;
int[] _triangle;
// assigning values
_verticles = Array.ConvertAll(_sprite.vertices, i => (Vector3)i);
_triangle = Array.ConvertAll(_sprite.triangles, i => (int)i);
// changing the size of the array
Array.Resize(ref _verticles, _verticles.Length * 2);
Array.Resize(ref _triangle, _triangle.Length * 2);
// adding another side
for (int i = 0; i < _verticles.Length / 2; i++)
{
_verticles[_verticles.Length / 2 + i] = new Vector3(_verticles[i].x, _verticles[i].y, 0.5f);
}
for (int i = 0; i < _triangle.Length / 2; i++)
{
_triangle[_triangle.Length / 2 + i] = _triangle[i] + (_verticles.Length / 2);
}
// invert the second side
for(int i = _triangle.Length / 2; i < _triangle.Length; i += 3) {
var temp = _triangle[i];
_triangle[i] = _triangle[i + 1];
_triangle[i + 1] = temp;
}
// assigning the mesh
mesh.vertices = _verticles;
mesh.triangles = _triangle;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
return mesh;
}
}
public partial class MeshDraft {
public string name = "";
public List<Vector3> vertices = new List<Vector3>();
public List<int> triangles = new List<int>();
public List<Vector3> normals = new List<Vector3>();
public List<Vector4> tangents = new List<Vector4>();
public List<Vector2> uv = new List<Vector2>();
public List<Vector2> uv2 = new List<Vector2>();
public List<Vector2> uv3 = new List<Vector2>();
public List<Vector2> uv4 = new List<Vector2>();
public List<Color> colors = new List<Color>();
public MeshDraft(Mesh mesh) {
name = mesh.name;
vertices.AddRange(mesh.vertices);
triangles.AddRange(mesh.triangles);
normals.AddRange(mesh.normals);
tangents.AddRange(mesh.tangents);
uv.AddRange(mesh.uv);
uv2.AddRange(mesh.uv2);
uv3.AddRange(mesh.uv3);
uv4.AddRange(mesh.uv4);
colors.AddRange(mesh.colors);
}
public void AddQuad(Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3, int index, Color color = default(Color)) {
vertices.Add(v0);
vertices.Add(v1);
vertices.Add(v2);
vertices.Add(v3);
Vector3 normal0 = Vector3.Cross(v2 - v1, v3 - v1).normalized;
Vector3 normal1 = Vector3.Cross(v1 - v0, v2 - v0).normalized;
normals.Add(normal0);
normals.Add(normal0);
normals.Add(normal1);
normals.Add(normal1);
colors.Add(color);
colors.Add(color);
colors.Add(color);
colors.Add(color);
triangles.Add(index);
triangles.Add(index + 1);
triangles.Add(index + 2);
triangles.Add(index);
triangles.Add(index + 2);
triangles.Add(index + 3);
}
public Mesh ToMesh() {
var mesh = new Mesh { name = name };
mesh.SetVertices(vertices);
mesh.SetTriangles(triangles, 0);
mesh.SetNormals(normals);
mesh.SetTangents(tangents);
mesh.SetUVs(0, uv);
mesh.SetUVs(1, uv2);
mesh.SetUVs(2, uv3);
mesh.SetUVs(3, uv4);
mesh.SetColors(colors);
return mesh;
}
Successful stitching (screen)
Bad stitching (screen)
I was given an answer on another forum, who is interested, I will leave a link here - https://www.cyberforum.ru/unity/thread2823987.html

Unity AI need to move a GameObject towards another one by a given distance

I'm currently trying to develop an AI for my game that needs to move every minion towards the enemy minions by a specific distance, what I'm currently doing is calculating the distance between all the enemy minions, after that I'll calculate the angle between the current minion and the closest one, and after that I'll apply the formula:
x = minion.x + cos(angle) * distance;
z = minion.z + sin(angle) * distance;
The problem is that the movement seems random, it doesn't always move towards the enemy but instead, it moves randomly
I'll provide the code below
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyAI : MonoBehaviour {
private float tolerance = 1.2f;
public NavMeshSurface navMesh;
private List<GameObject> board;
private List<Vector3> minionDesiredLocations;
private int currentMinionIndex = 0;
private enum State {
Draw,
Place,
GetBoard,
Move,
MinionMoving
}
private State state = State.Draw;
public GameObject PlaceCard(List<GameObject> hand)
{
//Generate a random integer to see what card to play
int randomIndex = (int) UnityEngine.Random.Range(0, hand.Count - 1);
Debug.Log("AI Generated Index: " + randomIndex);
return hand[randomIndex];
}
private bool MoveMinion(GameObject minion, List<GameObject> enemyMinions)
{
NavMeshAgent minionAgent = minion.GetComponent<NavMeshAgent>();
Card minionCard = minion.transform.Find("Card").GetComponent<Card>();
Vector3 maPosition = minion.transform.position;
//Finding the closest position of the enemy minion
float minDistance = 100.0f;
Vector3 closestMinionPosition = Vector3.negativeInfinity;
foreach (GameObject enemyMinion in enemyMinions)
{
//Calculating distance beetween the enemy AI minion and the enemy
float distance = Vector3.Distance(minion.transform.position, enemyMinion.transform.position);
if (distance <= minDistance)
{
minDistance = distance;
//Attacking the minion is close to the one
if (minDistance <= minionCard.cardRange)
{
float xRange = UnityEngine.Random.Range(-tolerance, tolerance);
float yRange = UnityEngine.Random.Range(-tolerance, tolerance);
closestMinionPosition = enemyMinion.transform.position + new Vector3(xRange, 0, yRange);
minionDesiredLocations[currentMinionIndex] = closestMinionPosition;
minionAgent.SetDestination(closestMinionPosition);
NavMeshHit hit;
if (NavMesh.SamplePosition(closestMinionPosition, out hit, 1.0f, NavMesh.AllAreas))
{
minionDesiredLocations[currentMinionIndex] = hit.position;
minionAgent.SetDestination(hit.position);
return true;
}
}
else
{
//Calculating angle beetween the minion and the target
float angle = GetAngle(minion.transform.position, enemyMinion.transform.position);
float randomDistance = UnityEngine.Random.Range((float)minionCard.cardRange / 2, (float)minionCard.cardRange * 2);
randomDistance = 1.0f;
float x = minion.transform.position.x + (float)Math.Cos(angle) * randomDistance;
float z = minion.transform.position.z + (float)Math.Sin(angle) * randomDistance;
closestMinionPosition = new Vector3(x, 0, z);
NavMeshHit hit;
if (NavMesh.SamplePosition(closestMinionPosition, out hit, 3.0f, NavMesh.AllAreas))
{
minionDesiredLocations[currentMinionIndex] = hit.position;
minionAgent.SetDestination(hit.position);
return true;
}
}
}
}
return false;
}
public bool PerformTurn(GameController gameController)
{
switch (state)
{
case State.Draw:
currentMinionIndex = 0;
gameController.drawCard(1);
state = State.Place;
break;
case State.Place:
//Getting the hand
List<GameObject> hand = gameController.GetHand(1);
//Generate a random integer to see what card to play
int randomIndex = (int)UnityEngine.Random.Range(0, hand.Count - 1);
gameController.PlaceMinion(randomIndex);
state = State.GetBoard;
break;
case State.GetBoard:
board = gameController.GetBoard(1);
minionDesiredLocations = GenerateActualLocations(board);
currentMinionIndex = 0;
state = State.Move;
break;
case State.Move:
//If we have moved all minions
if (currentMinionIndex >= board.Count)
{
Debug.Log("[IA] Passing turn");
state = State.Draw;
gameController.NextPlayer();
return true;
}
else if(MoveMinion(board[currentMinionIndex], gameController.GetBoard(0)))
{
gameController.SetCameraTo(board[currentMinionIndex].transform.position);
MoveMinion(board[currentMinionIndex], gameController.GetBoard(0));
state = State.MinionMoving;
}
break;
case State.MinionMoving:
Vector3 actualMinionPosition = board[currentMinionIndex].transform.position;
Vector3 desiredMinionLocation = minionDesiredLocations[currentMinionIndex];
actualMinionPosition = new Vector3(actualMinionPosition.x, 0, actualMinionPosition.z);
desiredMinionLocation = new Vector3(desiredMinionLocation.x, 0, desiredMinionLocation.z);
if (actualMinionPosition == desiredMinionLocation)
{
Debug.Log("Next Minion");
currentMinionIndex++;
state = State.Move;
}
//Debug lines
if (Input.GetKey(KeyCode.P))
{
Debug.Log("Next Minion");
currentMinionIndex++;
state = State.Move;
}
break;
}
//Continue turn proccessing
return false;
}
private List<Vector3> GenerateActualLocations(List<GameObject> board)
{
List<Vector3> l = new List<Vector3>();
foreach (GameObject minion in board)
{
l.Add(minion.transform.position);
}
return l;
}
private float GetAngle(Vector3 minion, Vector3 target)
{
return Vector3.Angle(minion, target);
}
}
Thanks for the help, I've finally found a solution.
What I've done was calling
agent.SetDestination(enemyMinion.transform.position)
After that I've stored the starting position of the agent, and inside of the logic loop, check the distance between the starting position and the actual position, whenever the distance is greater than the distance that the minion can walk, I'll simply stop the NavMeshAgent
Here's the updated code in case someone needs it
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyAI : MonoBehaviour {
private float tolerance = 1.2f;
public NavMeshSurface navMesh;
private List<GameObject> board;
private List<Vector3> minionDesiredLocations;
private Vector3 startMinionLocation;
private int currentMinionIndex = 0;
private enum State {
Draw,
Place,
GetBoard,
Move,
MinionMoving
}
private State state = State.Draw;
public GameObject PlaceCard(List<GameObject> hand)
{
//Generate a random integer to see what card to play
int randomIndex = (int) UnityEngine.Random.Range(0, hand.Count - 1);
Debug.Log("AI Generated Index: " + randomIndex);
return hand[randomIndex];
}
private bool MoveMinion(GameObject minion, List<GameObject> enemyMinions)
{
NavMeshAgent minionAgent = minion.GetComponent<NavMeshAgent>();
Card minionCard = minion.transform.Find("Card").GetComponent<Card>();
Vector3 maPosition = minion.transform.position;
//Finding the closest position of the enemy minion
float minDistance = 100.0f;
Vector3 closestMinionPosition = Vector3.negativeInfinity;
foreach (GameObject enemyMinion in enemyMinions)
{
//Calculating distance beetween the enemy AI minion and the enemy
float distance = Vector3.Distance(minion.transform.position, enemyMinion.transform.position);
if (distance <= minDistance)
{
minDistance = distance;
//Attacking the minion is close to the one
float xRange = UnityEngine.Random.Range(-tolerance, tolerance);
float yRange = UnityEngine.Random.Range(-tolerance, tolerance);
closestMinionPosition = enemyMinion.transform.position + new Vector3(xRange, 0, yRange);
minionDesiredLocations[currentMinionIndex] = closestMinionPosition;
minionAgent.SetDestination(closestMinionPosition);
NavMeshHit hit;
if (NavMesh.SamplePosition(closestMinionPosition, out hit, 1.0f, NavMesh.AllAreas))
{
minionDesiredLocations[currentMinionIndex] = hit.position;
minionAgent.isStopped = false;
minionAgent.SetDestination(hit.position);
startMinionLocation = minion.transform.position;
return true;
}
}
}
return false;
}
public bool PerformTurn(GameController gameController)
{
switch (state)
{
case State.Draw:
currentMinionIndex = 0;
gameController.drawCard(1);
state = State.Place;
break;
case State.Place:
//Getting the hand
List<GameObject> hand = gameController.GetHand(1);
//Generate a random integer to see what card to play
int randomIndex = (int)UnityEngine.Random.Range(0, hand.Count - 1);
gameController.PlaceMinion(randomIndex);
state = State.GetBoard;
break;
case State.GetBoard:
board = gameController.GetBoard(1);
minionDesiredLocations = GenerateActualLocations(board);
currentMinionIndex = 0;
state = State.Move;
break;
case State.Move:
//If we have moved all minions
if (currentMinionIndex >= board.Count)
{
Debug.Log("[IA] Passing turn");
state = State.Draw;
gameController.NextPlayer();
return true;
}
else if(MoveMinion(board[currentMinionIndex], gameController.GetBoard(0)))
{
gameController.SetCameraTo(board[currentMinionIndex].transform.position);
MoveMinion(board[currentMinionIndex], gameController.GetBoard(0));
state = State.MinionMoving;
}
break;
case State.MinionMoving:
Vector3 actualMinionPosition = board[currentMinionIndex].transform.position;
float distance = Vector3.Distance(startMinionLocation, actualMinionPosition);
Card card = board[currentMinionIndex].transform.Find("Card").GetComponent<Card>();
NavMeshAgent agent = board[currentMinionIndex].GetComponent<NavMeshAgent>();
if (distance >= card.cardRange)
{
agent.isStopped = true;
currentMinionIndex++;
state = State.Move;
}
//Debug lines
if (Input.GetKey(KeyCode.P))
{
Debug.Log("Next Minion");
currentMinionIndex++;
state = State.Move;
}
break;
}
//Continue turn proccessing
return false;
}
private List<Vector3> GenerateActualLocations(List<GameObject> board)
{
List<Vector3> l = new List<Vector3>();
foreach (GameObject minion in board)
{
l.Add(minion.transform.position);
}
return l;
}
private float GetAngle(Vector3 minion, Vector3 target)
{
return Vector3.Angle(minion, target);
}
}

Unity player freezing due to script but without error

My unity player keeps on freezing after a while, I know what script is causing it (if it is indeed a script that is causing it). since there's only one script I've edited when it started freezing. But I can't figure out WHY it is freezing!
Here is the script that is causing it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour {
//public GameObject allPlayersPrefab;
public GameObject allPlayers;
public Transform playerRed;
public Transform playerGreen;
//public Transform playerPurple;
//public Transform playerYellow;
//Tail redTail;
//Tail greenTail;
//Tail purpleTail;
//Tail yellowTail;
public float secondsBetweenGaps = 2f;
public float secondsToGap = .25f;
public float snakeSpeed = 3f;
public float turnSpeed = 200f;
public int biggerPickupDuration = 3;
public int smallerPickupDuration = 3;
public int speedPickupDuration = 2;
public int invinciblePickupDuration = 3;
public int maxPickups = 3;
public int spawnPickupThreshold = 5;
private GameObject[] currPickups;
public GameObject[] pickupTypes;
public Transform pickupsParent;
public int players = 2;
[HideInInspector]
public int alive;
public bool enableKeys = false;
public GameObject prefabTail;
public GameObject settingsMenu;
public GameObject startingPanel;
public Text scoreText;
public Text radiusText;
public Text speedText;
public Text winText;
private bool hasEnded = false;
[HideInInspector]
public bool playerWon = false;
public bool running;
public Snake[] snakes;
ButtonManager buttonManager;
Pickup[] pickups;
void Start() {
//InstantiateNewPlayers();
playerRed = allPlayers.transform.FindChild("Red");
playerGreen = allPlayers.transform.FindChild("Green");
snakes = allPlayers.GetComponentsInChildren<Snake>(true);
alive = players;
//redTail = playerRed.GetComponentInChildren<Tail>();
//greenTail = playerGreen.GetComponentInChildren<Tail>();
//purpleTail = playerPurple.GetComponentInChildren<Tail>();
//yellowTail = playerYellow.GetComponentInChildren<Tail>();
buttonManager = FindObjectOfType<ButtonManager>();
pickups = FindObjectsOfType<Pickup>();
playerRed.gameObject.SetActive(false);
playerGreen.gameObject.SetActive(false);
//playerPurple.gameObject.SetActive(false);
//playerYellow.gameObject.SetActive(false);
winText.enabled = false;
foreach(Snake snake in snakes) {
snake.scoreText.enabled = false;
}
}
void Update() {
if(Input.GetKey(KeyCode.Escape)) {
foreach(Snake snake in snakes) {
snake.score = 0;
snake.scoreText.text = "0";
}
buttonManager.anima.Play("BackToSettings");
playerWon = true;
ResetGame();
buttonManager.restartButt.gameObject.SetActive(false);
buttonManager.StopAllCoroutines();
buttonManager.countDownText.enabled = false;
winText.enabled = false;
foreach(Snake snake in snakes) {
snake.scoreText.enabled = false;
}
}
if(alive == 1 && !hasEnded) {
Transform lastPlayer;
foreach(Snake child in snakes) {
if(!child.dead) {
lastPlayer = child.transform.parent;
if(child.score >= int.Parse(scoreText.text)) {
Win(lastPlayer.name);
AllPlayersDead();
} else
AllPlayersDead();
break;
}
}
}
if(alive == 0) {
if(hasEnded)
return;
buttonManager.restartButt.gameObject.SetActive(true);
hasEnded = true;
running = false;
}
foreach(Snake child in snakes) {
if(child.score >= int.Parse(scoreText.text)) {
AllPlayersDead();
Win(child.transform.parent.name);
}
}
}
public void AllPlayersDead() {
if(hasEnded)
return;
buttonManager.restartButt.gameObject.SetActive(true);
hasEnded = true;
running = false;
}
void Win(string winningPlayer) {
foreach(Snake snake in snakes) {
snake.score = 0;
snake.scoreText.text = "0";
}
Debug.Log("Win got called");
winText.gameObject.SetActive(true);
winText.enabled = true;
winText.text = winningPlayer + " wins!";
playerWon = true;
running = false;
}
public void PlayerDied() {
foreach(Snake child in snakes) {
if(!child.dead) {
child.score += 1;
}
}
}
public IEnumerator SpawnPickups() {
while(enabled) {
Debug.Log("SpawnPickups running...");
if(running) {
if(pickupsParent.childCount < maxPickups) {
int type = Random.Range(0, pickupTypes.Length);
float X = Random.Range(-7f, 7f);
float Y = Random.Range(-3f, 3f);
Vector3 spawnPos = new Vector3(X, Y, 0);
/*GameObject newPickup = */Instantiate(pickupTypes[type], spawnPos, Quaternion.Euler(0, 0, 0), pickupsParent);
Debug.Log("SpawnPickups instantiated new pickup...");
yield return new WaitForSeconds(spawnPickupThreshold);
}
}
}
}
public void ResetGame() {
Debug.Log("Resetting everything...");
for(int i = 0; i < players; i++) {
Transform currPlayer = allPlayers.transform.GetChild(i);
currPlayer.GetComponentInChildren<Tail>().points.Clear();
currPlayer.GetComponentInChildren<Snake>().dead = false;
currPlayer.GetComponentInChildren<Snake>().invincible = false;
currPlayer.GetComponentInChildren<Snake>().posInformer.position = new Vector3(-20, 0, 0);
if(playerWon) {
currPlayer.GetComponentInChildren<Snake>().score = 0;
playerWon = false;
}
//currPlayer.GetComponentInChildren<LineRenderer>().positionCount = 0;
currPlayer.GetComponentInChildren<LineRenderer>().numPositions = 0;
List<Vector2> list = new List<Vector2>();
list.Add(new Vector2(0, 5));
list.Add(new Vector2(0, 6));
StopAllCoroutines();
for(int i2 = 0; i2 < pickups.Length; i2++) {
pickups[i2].StopAllCoroutines();
}
foreach(Transform pickup in pickupsParent) {
Destroy(pickup.gameObject);
}
currPlayer.GetComponentInChildren<EdgeCollider2D>().points = list.ToArray();
foreach(Transform child in currPlayer) {
if(child.CompareTag("PrefabTail")) {
Destroy(child.gameObject);
}
}
currPlayer.gameObject.SetActive(false);
currPlayer.GetComponentInChildren<Tail>().enabled = true;
Destroy(GameObject.FindWithTag("PrefabTail"));
turnSpeed = int.Parse(radiusText.text) * 10;
snakeSpeed = float.Parse(speedText.text);
alive = players;
hasEnded = false;
running = false;
}
Debug.Log("Resetting done.");
}
}
I do have a small suspection that the freezing has something to do with the SpawnPickups method and/or the part where it destroys the pickups in the ResetGame method.
Thanks!
Your method SpawnPickups is doing this.
When you call this coroutine, and enable is true and running is false, you never reach a "yield" instruction, so your while(enabled) is indeed a while(true)
Coroutines are not threads, they run on the main thread and if you block a coroutine like this one, you are blocking the game.
public IEnumerator SpawnPickups() {
while(enabled) {
Debug.Log("SpawnPickups running...");
if(running) {
if(pickupsParent.childCount < maxPickups) {
int type = Random.Range(0, pickupTypes.Length);
float X = Random.Range(-7f, 7f);
float Y = Random.Range(-3f, 3f);
Vector3 spawnPos = new Vector3(X, Y, 0);
/*GameObject newPickup = */Instantiate(pickupTypes[type], spawnPos, Quaternion.Euler(0, 0, 0), pickupsParent);
Debug.Log("SpawnPickups instantiated new pickup...");
yield return new WaitForSeconds(spawnPickupThreshold);
}
//Here you need some yield in case running is true but you reached maxPickups (this one is not necessary if you put the next one)
}
//Here you need some yield in case running is false
//yield return null; //this should be enough to prevent your game from freezing
}
}

Switching active states of two GameObjects in Unity3D

With Unity3D I am trying to create a scene with an alpha texture as a silhouette, which upon looking up is added, then looking down removes.
Currently I have the exposure of an equirectangular image changing on look up, but my silhouette object says I have not assigned it to an instance:
As you can see from the console, it is eventualy recognised, but I cannot set the active state. This is the current state of my code being applied to the scene:
using UnityEngine;
using System.Collections;
public class switchScript : MonoBehaviour {
public Cardboard cb;
public Renderer leftEyeDay;
public Renderer rightEyeDay;
private GameObject[] dayObjects;
public GameObject nightObject;
void Start () {
MeshFilter filter = GetComponent(typeof (MeshFilter)) as MeshFilter;
if (filter != null) {
Mesh mesh = filter.mesh;
Vector3[] normals = mesh.normals;
for (int i=0;i<normals.Length;i++)
normals[i] = -normals[i];
mesh.normals = normals;
for (int m=0;m<mesh.subMeshCount;m++)
{
int[] triangles = mesh.GetTriangles(m);
for (int i=0;i<triangles.Length;i+=3)
{
int temp = triangles[i + 0];
triangles[i + 0] = triangles[i + 1];
triangles[i + 1] = temp;
}
mesh.SetTriangles(triangles, m);
}
}
}
// Update is called once per frame
void Update () {
float xAngle = cb.HeadPose.Orientation.eulerAngles.x;
if (isLookingUp (xAngle)) {
var exposureValue = getExposureValue (xAngle);
leftEyeDay.material.SetFloat ("_Exposure", exposureValue);
rightEyeDay.material.SetFloat ("_Exposure", exposureValue);
toggleNight ();
} else {
leftEyeDay.material.SetFloat ("_Exposure", 1F);
rightEyeDay.material.SetFloat ("_Exposure", 1F);
toggleNight ();
}
}
public bool isLookingUp (float xAngle) {
return xAngle > 270 && xAngle < 340;
}
public float getExposureValue (float xAngle) {
var _xAngle = Mathf.Clamp (xAngle, 320, 340);
return ScaleValue (320.0F, 340.0F, 0.3F, 1.0F, _xAngle);
}
public float ScaleValue (float from1, float to1, float from2, float to2, float v) {
return from2 + (v - from1) * (to2 - from2) / (to1 - from1);
}
void toggleDay() {
print (nightObject);
nightObject = GameObject.FindGameObjectWithTag ("Night");
nightObject.SetActive (false);
}
void toggleNight() {
print (nightObject);
nightObject = GameObject.FindGameObjectWithTag ("Night");
nightObject.SetActive (true);
}
}
GameObject.FindGameObjectWithTag ("Night") returns null when the whole object is set to !active. Just toggle the scripts on that object instead of the whole GO.
Ok, if anyone needs this, this is an easy way to create scene switch:
void Awake() {
silhouetteObject = GameObject.FindGameObjectWithTag ("Night");
silhouetteObject.GetComponent<Renderer>().enabled = false;
}