How i can optimizating my code in Unity3D - c#

I try optimizating my games, how i can optimizating my random generator?
PS: Game have occulison culling, dynamic batching, no rich text, GPU Instancing, LOD Groups on best population object (Berries, Logs, Leaves on tree, stick).
using static System.Random;
using UnityEngine;
public class StickGenerator : MonoBehaviour
{
[Header("Игровые объекты")] // game objects
public GameObject Object;
[Header("Лимит строений")] // is builded?
private bool objectBuilded = false;
[Header("Количество")] // how much
public int what;
[Header("Максимум блоков для рендера")] // max X and Z for render
public int maxRangeX;
public int maxRangeZ;
[Header("Рандомные координаты")] // random coordinations
private int randomPosX;
private int randomPosZ;
private void Start() // generation
{
if(objectBuilded == false)
{
System.Random randomPos = new System.Random();
for (int i = 0; i <= what; i++)
{
randomPosX = randomPos.Next(1, maxRangeX);
randomPosZ = randomPos.Next(1, maxRangeZ);
Instantiate(Object, new Vector3(randomPosX, 0.56f, randomPosZ), Quaternion.identity);
}
objectBuilded = true;
}
}
}

Try debugging with the profiler to see what kind of spikes you are getting, that way you can now where to optimize first.

Related

I want GameTipUI with a blank space for a certain amount of time and certain message for a certain amount of time using CoRoutine

I want GameTipUI with a blank space for a certain amount of time and certain message(==NormalGuideTip) for a certain amount of time using CoRoutine.
I was thinking of putting an 'if' in the CoRoutine to check the time,so make it easy to empty the message, and display the message again.
However, the message just keeps getting blank.
What could be the problem?
I wanted to repeat the randomly selected game tip message for 5 seconds and the blank message for 7 seconds.
And I wanted to use realtimeForGameTip to immediately display a special message(==UrgentGameTip ) according to a specific game action later and repeat the above process again.
bool isGameTipOn= true;
public GameObject gameTipTitle;
public GameObject gameTipMsg;
Color normalTipColor = new Color(255f, 255f, 255f, 220f);
Color UrgentTipColor = Color.green;
float timeBetGameTip = 7f; //
float timeOfGameMsg = 5f; //
public readonly WaitForSeconds m_waitForSecondsForGameTip = new WaitForSeconds(7f);
float realtimeForGameTip= 0f;
public string[] NormalGuideTips;
public string[] UrgentGuideTips;
private void Start()
{
#region GameTipSetUp
OnOffGameTip(true);
StartCoroutine("GameTipUI");
#endregion GameTipSetUp
}
public void OnOffGameTip(bool OnOff)
{
isGameTipOn = OnOff;
gameTipTitle.gameObject.SetActive(isGameTipOn);
gameTipMsg.gameObject.SetActive(isGameTipOn);
}
private void ResetGameTip()
{
if (!isGameTipOn) return;
realtimeForGameTip = 0f ;
int index = Random.Range(0, NormalGuideTips.Length);
string selectedMsg = NormalGuideTips[index];
Debug.Log(selectedMsg);
gameTipMsg.GetComponent<Text>().text = selectedMsg;
gameTipMsg.GetComponent<Text>().color = normalTipColor;
}
public void UrgentGameTip(string id)
{
if (!isGameTipOn) return;
=
int index = Random.Range(0, NormalGuideTips.Length);
string selectedMsg = UrgentGuideTips[index];
Debug.Log(selectedMsg);
gameTipMsg.GetComponent<Text>().text = selectedMsg;
gameTipMsg.GetComponent<Text>().color = UrgentTipColor;
realtimeForGameTip = timeOfGameMsg;
}
public void MakeTermBetGameTip()
{
gameTipMsg.GetComponent<Text>().text = " blank ";
}
IEnumerator GameTipUI()
{
while (isGameTipOn)
{
if(realtimeForGameTip < timeOfGameMsg)
{
Debug.Log(realtimeForGameTip);
realtimeForGameTip += Time.deltaTime;
continue;
}
MakeTermBetGameTip();
yield return new WaitForSeconds(m_waitForSecondsForGameTip);
ResetGameTip();
}
}

How to stop tile animation in Unity TileSystem?

I'm trying to understand tileSystem build in Unity, and i don't know how to stop animation in AnimatedTiles.
Once animation is started, there is no way i can think of to stop this. I'm working on Unity 2018.3.2f1, but i think that TileSystem is similar in next versions.
Only code in AnimatedTile handling animation is:
public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
{
tileData.transform = Matrix4x4.identity;
tileData.color = Color.white;
if (m_AnimatedSprites != null && m_AnimatedSprites.Length > 0)
{
tileData.sprite = m_AnimatedSprites[0];
tileData.colliderType = m_TileColliderType;
}
}
public override bool GetTileAnimationData(Vector3Int location, ITilemap tileMap, ref TileAnimationData tileAnimationData)
{
if (m_AnimatedSprites.Length > 0)
{
tileAnimationData.animatedSprites = m_AnimatedSprites;
tileAnimationData.animationSpeed = Random.Range(m_MinSpeed, m_MaxSpeed);
tileAnimationData.animationStartTime = m_AnimationStartTime;
return true;
}
return false;
}
I want to stop animation after some time (like 3 seconds) or after last frame. Any help would be appritiated!
So after some time a got workaround and it looks like this :
public class TileBump : MonoBehaviour
{
public Transform m_GridParent;
public GameObject m_TileMap_Prefab;
public AnimatedTile m_tilePrefabAnimated;
public Tile m_tilePrefabStatic;
private Tilemap map;
void Start()
{
StartCoroutine(EStart());
}
public IEnumerator EStart()
{
GameObject t = Instantiate(m_TileMap_Prefab, m_GridParent);
map = t.GetComponent<Tilemap>();
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
map.SetTile(new Vector3Int(i, j, 0), m_tilePrefabAnimated);
StartCoroutine(Operation(new Vector3Int(i, j, 0)));
yield return new WaitForSeconds(0.3f);
}
}
}
public IEnumerator Operation(Vector3Int x)
{
yield return new WaitForSeconds(m_tilePrefabAnimated.m_AnimatedSprites.Length / m_tilePrefabAnimated.m_AnimationSpeed);
map.SetTile(x, m_tilePrefabStatic);
}
}
BUT. What i understood here is that tiles are not for that. Every tile in TileMap refer to ScriptableObject, so every animation will be same in every frame.
However if someone need this kind of effect, its one way to do it.

how GetComponentInChildren in unity

I have a problem:
How to assign [] status to rend[]
public GameObject[] Obj;
private bool[] Status;
private MeshRenderer[] rend;
private void Start ()
{
for (int i = 0; i < Obj.Length; i++)
{
rend[i] = GetComponentInChildren<MeshRenderer>();
Status[i] = rend[i];
}
}
Accorting to Object.bool you can try this way:
public GameObject[] Obj ;
private bool[] Status;
private MeshRenderer[] rend;
void Start () {
for (int i = 0; i < Obj.Length; i++)
{
rend[i] = Obj[i].GetComponentInChildren<MeshRenderer>();
Status[i] = rend[i] != null;
}
}
Your question is very unclear so I can just guess what you are trying to archieve:
I'ld say you want to find the first MeshRenderer under your GameObjects in Obj and get an array Status saying whether they are enabled or not.
You are currently allways searching for MeshRenderer in the GameObject this script is attached to instead of looking in the Obj GameObjects. You have to get it using
Obj[i].GetComponentInChildren<MeshRenderer>();
you probably don't initailize your arrays -> you cannot just assign values using Status[i] = and rend[i] = if the arrays were never initialized using new. You can either do that in start once you have the size of Obj
public GameObject[] Obj;
private bool[] Status;
private MeshRenderer[] rend;
private void start()
{
Status = new bool[Obj.Length];
rend = new MeshRenderer[Obj.Length];
// ...
}
but I would prefer using a List<bool> and List<MeshRenderer> instead so you can simply add and remove values later (while an array has a fixed length).
Finally I guess you want to know whether the component MeshRenderer is enabled so you can assign rend[i].enabled
all together
something like
public GameObject[] Obj ;
// Using List here you can already initialize it here
// which would be possible using an array
private List<bool> Status = new List<bool>();
private List<MeshRenderer> rend = new List<MeshRenderer>();
private void Start(){
for (int i = 0; i < Obj.Length; i++)
{
rend.Add(Obj[i].GetComponentInChildren<MeshRenderer>());
bool existsAndEnabled = rend[i] != null && rend[i].enabled;
Status.Add(existsAndEnabled);
}
}
Note that it is still possible that for one of the GameObjects in Obj there is no MeshRenderer found so I say Status shall also be false if there was none.

Unity Crashing on Play, most likely infinite While loop, but cannot locate issue

thanks for reading.
I'm currently building a small memory card game in Unity using C#. I have the main portion of code finished but when I press the play button on a certain scene Unity freezes.
I believe it is due to an infinite While loop, but I can not find the issue. I would really appreciate any help anyone can offer. I will leave my code below. Thanks in advance.
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEngine;
public class Pairs : MonoBehaviour {
public Sprite[] face; //array of card faces
public Sprite back;
public GameObject[] deck; //array of deck
public Text pairsCount;
private bool deckSetUp = false;
private int pairsLeft = 13;
// Update is called once per frame
void Update () {
if (!deckSetUp)
{
SetUpDeck();
}
if (Input.GetMouseButtonUp(0)) //detects left click
{
CheckDeck();
}
}//Update
void SetUpDeck()
{
for (int ix = 0; ix < 2; ix++)
{
for(int i = 1; i < 14; i++)//sets up card value (2-10 JQKA)
{
bool test = false;
int val = 0;
while (!test)
{
val = Random.Range(0, deck.Length);
test = !(deck[val].GetComponent<Card>().SetUp);
}//while
//sets up cards
deck[val].GetComponent<Card>().Number = i;
deck[val].GetComponent<Card>().SetUp = true;
}//nested for
}//for
foreach (GameObject crd in deck)
{
crd.GetComponent<Card>().setUpArt();
}
if (!deckSetUp)
{
deckSetUp = true;
}
}//SetUpDeck
public Sprite getBack()
{
return back;
}//getBack
public Sprite getFace(int i)
{
return face[i - 1];
}//getFace
void CheckDeck()
{
List < int > crd = new List<int>();
for(int i = 0; i < deck.Length; i++)
{
if(deck[i].GetComponent<Card>().State == 1)
{
crd.Add(i);
}
}
if(crd.Count == 2)
{
CompareCards(crd);
}
}//CheckDeck
void CompareCards(List<int> crd)
{
Card.NO_TURN = true; //stops cards turning
int x = 0;
if(deck[crd[0]].GetComponent<Card>().Number ==
deck[crd[1]].GetComponent<Card>().Number)
{
x = 2;
pairsLeft--;
pairsCount.text = "PAIRS REMAINING: " + pairsLeft;
if(pairsLeft == 0) // goes to home screen when game has been won
{
SceneManager.LoadScene("Home");
}
}
for(int j = 0; j < crd.Count; j++)
{
deck[crd[j]].GetComponent<Card>().State = x;
deck[crd[j]].GetComponent<Card>().PairCheck();
}
}//CompareCards
}
I believe the issue lies in the while(!test) but i do not know why test never become true.
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class Card : MonoBehaviour {
public static bool NO_TURN = false;
[SerializeField]
private int cardState; //state of card
[SerializeField]
private int cardNumber; //Card value (1-13)
[SerializeField]
private bool _setUp = false;
private Sprite back; //card back (Green square)
private Sprite face; //card face (1-10 JQKA)
private GameObject pairsManager;
void Begin()
{
cardState = 1; //cards face down
pairsManager = GameObject.FindGameObjectWithTag("PairsManager");
}
public void setUpArt()
{
back = pairsManager.GetComponent<Pairs>().getBack();
face = pairsManager.GetComponent<Pairs>().getFace(cardNumber);
turnCard();//turns the card
}
public void turnCard() //handles turning of card
{
if (cardState == 0)
{
cardState = 1;
}
else if(cardState == 1)
{
cardState = 0;
}
if (cardState == 0 && !NO_TURN)
{
GetComponent<Image>().sprite = back; // shows card back
}
else if (cardState == 1 && !NO_TURN)
{
GetComponent<Image>().sprite = face; // shows card front
}
}
//setters and getters
public int Number
{
get {return cardNumber;}
set { cardNumber = value;}
}
public int State
{
get { return cardState; }
set { cardState = value; }
}
public bool SetUp
{
get { return _setUp; }
set { _setUp = value; }
}
public void PairCheck()
{
StartCoroutine(pause ());
}
IEnumerator pause()
{
yield return new WaitForSeconds(1);
if (cardState == 0)
{
GetComponent<Image>().sprite = back;
}
else if (cardState == 1)
{
GetComponent<Image>().sprite = face;
}
}
}
Thank you for reading, I will post a link to the github repository if that helps.
github repository
Your deck array has at least one card in it that has _setUp set to true which would make it go in a infinite loop.
The reason it goes in a infinite loop is because it will have set all available _setUp to true and it would keep looking for _setUp that are set to false and it will never find any.
The reason you need at least 26 object that have _setUp to false is because in the nested for loop you loop 13 times and then you do that twice which gives a total of 26 loops. So you need at least 26 objects.
What you can do to make sure that they're all false is to set them all to false before entering the for loop
for(int i = 0; i < deck.Length; i++)
{
deck[i].GetComponent<Card>().SetUp = false;
}

Cardboard Magnet Detection

I got some trouble with my unity cardboard app. May some of you guys can help me.
I have build a little Island with Animations and A second island as a main menu.
So when the apps starts, you see the Island from above and the Logo of the App.
When the user pull down the magnet button on side the app will starts another level.
I used this scripts:
http://www.andrewnoske.com/wiki/Unity_-_Detecting_Google_Cardboard_Click
Detecting Google Cardboard Magnetic Button Click - Singleton Implementation
CardboardMagnetSensor.cs and CardboardTriggerControlMono.cs
I created a script in my asset folder(CardboardMagnetSensor.cs) like in the description from Link. Than I created a second script(CardboardTriggerControlMono.cs) like in the discription an dragged it onto my CardboardMain in may Projekt.
The CardboardTriggerControlMono.cs looks like:
using UnityEngine;
using System.Collections;
public class CardboardTriggerControlMono : MonoBehaviour {
public bool magnetDetectionEnabled = true;
void Start() {
CardboardMagnetSensor.SetEnabled(magnetDetectionEnabled);
// Disable screen dimming:
Screen.sleepTimeout = SleepTimeout.NeverSleep;
}
void Update () {
if (!magnetDetectionEnabled) return;
if (CardboardMagnetSensor.CheckIfWasClicked()) {
Debug.Log("Cardboard trigger was just clicked");
Application.LoadLevel(1);
CardboardMagnetSensor.ResetClick();
}
}
}
The CarboardMagnetSensor:
using UnityEngine;
using System.Collections.Generic;
public class CardboardMagnetSensor {
// Constants:
private const int WINDOW_SIZE = 40;
private const int NUM_SEGMENTS = 2;
private const int SEGMENT_SIZE = WINDOW_SIZE / NUM_SEGMENTS;
private const int T1 = 30, T2 = 130;
// Variables:
private static bool wasClicked; // Flips to true once set off.
private static bool sensorEnabled; // Is sensor active.
private static List<Vector3> sensorData; // Keeps magnetic sensor data.
private static float[] offsets; // Offsets used to detect click.
// Call this once at beginning to enable detection.
public static void SetEnabled(bool enabled) {
Reset();
sensorEnabled = enabled;
Input.compass.enabled = sensorEnabled;
}
// Reset variables.
public static void Reset() {
sensorData = new List<Vector3>(WINDOW_SIZE);
offsets = new float[SEGMENT_SIZE];
wasClicked = false;
sensorEnabled = false;
}
// Poll this once every frame to detect when the magnet button was clicked
// and if it was clicked make sure to call "ResetClick()"
// after you've dealt with the action, or it will continue to return true.
public static bool CheckIfWasClicked() {
UpdateData();
return wasClicked;
}
// Call this after you've dealt with a click operation.
public static void ResetClick() {
wasClicked = false;
}
// Updates 'sensorData' and determines if magnet was clicked.
private static void UpdateData() {
Vector3 currentVector = Input.compass.rawVector;
if (currentVector.x == 0 && currentVector.y == 0 && currentVector.z == 0) {
return;
}
if(sensorData.Count >= WINDOW_SIZE) sensorData.RemoveAt(0);
sensorData.Add(currentVector);
// Evaluate model:
if(sensorData.Count < WINDOW_SIZE) return;
float[] means = new float[2];
float[] maximums = new float[2];
float[] minimums = new float[2];
Vector3 baseline = sensorData[sensorData.Count - 1];
for(int i = 0; i < NUM_SEGMENTS; i++) {
int segmentStart = 20 * i;
offsets = ComputeOffsets(segmentStart, baseline);
means[i] = ComputeMean(offsets);
maximums[i] = ComputeMaximum(offsets);
minimums[i] = ComputeMinimum(offsets);
}
float min1 = minimums[0];
float max2 = maximums[1];
// Determine if button was clicked.
if(min1 < T1 && max2 > T2) {
sensorData.Clear();
wasClicked = true; // Set button clicked to true.
// NOTE: 'wasClicked' will now remain true until "ResetClick()" is called.
}
}
private static float[] ComputeOffsets(int start, Vector3 baseline) {
for(int i = 0; i < SEGMENT_SIZE; i++) {
Vector3 point = sensorData[start + i];
Vector3 o = new Vector3(point.x - baseline.x, point.y - baseline.y, point.z - baseline.z);
offsets[i] = o.magnitude;
}
return offsets;
}
private static float ComputeMean(float[] offsets) {
float sum = 0;
foreach(float o in offsets) {
sum += o;
}
return sum / offsets.Length;
}
private static float ComputeMaximum(float[] offsets) {
float max = float.MinValue;
foreach(float o in offsets) {
max = Mathf.Max(o, max);
}
return max;
}
private static float ComputeMinimum(float[] offsets) {
float min = float.MaxValue;
foreach(float o in offsets) {
min = Mathf.Min(o, min);
}
return min;
}
}
And my steps:
http://www.directupload.net/file/d/3887/mtjygjan_jpg.htm
(sorry I´m not able to upload pictures here)
How ever, it wont work. When I start the app and pull down the magnet, nothing happens. May I did something wrong with switching the level over level index?
I use a nexus 4 and 5 for testing the app
Thanks allot and greetz to you!
Phillip
If you are using the Google Cardboard SDK for Unity, it currently has a bug that prevents Unity from seeing the magnet (and gyro, and accelerometer). That is probably why your script is not working. Until the bug is fixed, there is no good workaround, but you can instead use the property Cardboard.CardboardTriggered to detect if the magnet was pulled.
Update for Unity 5: The sensor bug is gone. Cardboard SDK does not block the sensors.

Categories

Resources