IndexOutOfRange on a loop in Unity - c#

I'm trying to figure out how to get rid of my IndexOutOfRange error in Unity. I've tried a couple of different things, but I'm at a loss.
Its just that when I press tab, I cycle through my Game Objects array as planned, but then when you get to the last one, it throws that. I'd like for it to cycle back to the beginning, if possible. I've been plugging at this for probably 2 days now.
This is what I have so far (I only included the important variables, cause this script is huge)
int currentWindow = 0;
public GameObject theUI;
public GameObject[] windows;
void Update()
{
//Toggle Menu
if (Input.GetKeyDown(KeyCode.Escape))
{
if (theUI.activeInHierarchy)
{
theUI.SetActive(false);
}
else
{
theUI.SetActive(true);
windows[0].SetActive(true);
Refresh();
}
}
//Toggle Between Windows
if (theUI.activeInHierarchy)
{
if (Input.GetKeyDown(KeyCode.Tab))
{
ToggleWindow(currentWindow);
}
}
}
public void ToggleWindow(int windowNumber)
{
if (windowNumber == currentWindow)
{
windows[windowNumber].SetActive(!windows[windowNumber].activeInHierarchy);
Refresh();
currentWindow++;
windows[currentWindow].SetActive(!windows[currentWindow].activeInHierarchy);
}
}
If anyone has any insight as to what to do, please help! I've followed a few different things, but because my windows[] array is a GameObject rather than an int or anything else, it's made it quite difficult to figure out how to fix it using other sources.

currentWindow++;
windows[currentWindow]....
There is no check whatsoever if that index exceeds the array size.
For a simple wrap around you can use the remainder operator % often called 'modulo' (though only same for positive values)
currentWindow = (currentWindow + 1) % windows.Length;
So if the currentWindow reaches windows.Length it simply starts from 0 again.

Related

I want to activate a same animation for few different objects trough FOR loop. Animation don't sync and go in random intervals. Here is the code:

So, firstly, my scene is made out of 9 empty objects each one having spikes that have animation to pop out of the floor. I am making a game where you should avoid spikes and other projectiles. I tested this first with sprite renderer and changing colors, it worked perfectly. But when I want to activate animations using trigger (animations start from empty game state and go to their animations, then after it finishes they return to normal). I've looked trough every thing I could think of and I could not solve this. It always starts animations for 4-6 different animations and start them at the same time, but for some reason: AFTER FIRST SHOWING, every single time after first time spikes appear, 2/3 out of 4/6 always show late but start at same time. Weirdly first time it always works greatly. Any thoughts on what may cause this?
void Update()
{
if (spikeTimer > 0)
spikeTimer -= Time.deltaTime;
if (spikeTimer<0)
{
Function();
spikeTimer = spikeCooldown;
}
}
public void Function()
{
int x = Random.Range(4, 6);
List<int> included = new List<int>();
while (included.Count < x)
{
int y = Random.Range(1, 10);
if (!included.Contains(y))
{
included.Add(y);
}
}
foreach (int i in included)
{
print("aktiviran je broj" + i);
Spikes[i - 1].GetComponent<Spike>().ActivateSpike();
}
}
Now this is the ActivateSpike method that all Spikes in the scene contain
public void ActivateSpike()
{
SpriteRenderer sr = gameObject.GetComponent<SpriteRenderer>();
if (sr.color != Color.black)
{
sr.color = Color.black;
}
else
sr.color = Color.red;
/* Animator animator = gameObject.GetComponent<Animator>();
animator.SetTrigger("Activate");*/
}
You can see that I tried changing the sprite to square and changing its color, and it works perfectly...

How to make a list of gameObjects disappear animated? (or how to fix weird behaviour when setting alpha value)

I am trying to make a list of gameObjects disappear when the player enters a room, the best way I could think about doing it, was changing the material alpha frame by frame. If there is an alternative to this method that is more performatic, please tell! (not that I noticed any bad performance as this seems simple enough)
I expect the player to enter a room and all of the gameObjects in that list to disappear at the same time and at the same rate (as if they were all just one object having their transparency changed in runtime) but what happens is (I've made a video: https://youtu.be/z1pz2Te_hDg ) that some gameObjects change before others, some disappear way faster than expected and just in the end after the others, it all looks weird.
Changing the alpha of only one object at a time seems fine, but since I need to loop through all of the materials, I can't simply put all objects as a child of one gameObject.
I've tried to change the alpha without making a custom shader with an alpha property by accessing the default alpha in the default "HDPR/Lit" shader and it behaves the same.
This problem seems easy, I feel like I am doing something stupidly wrong but I've been at this for a couple of weeks.
Here is my "RoomTransparencyController" script:
bool transparent = false;
public float enhance = 5;
private struct ShaderPropertyIDs {
public int AlphaRef;
}
private ShaderPropertyIDs shaderProps;
public List<GameObject> gameObjectList;
public List<Material> materialList;
void Start() {
foreach(GameObject obj in gameObjectList) {
foreach(Material mat in obj.GetComponent<MeshRenderer>().materials) {
materialList.Add(mat);
}
}
// Cache property IDs
shaderProps = new ShaderPropertyIDs() {
AlphaRef = Shader.PropertyToID("AlphaRef"),
};
}
void Update() {
UpdateChildsAlpha3(transparent);
}
private void OnTriggerEnter(Collider col) {
if(col.tag == "Player") {
transparent = true;
}
}
private void OnTriggerExit(Collider col) {
if(col.tag == "Player") {
transparent = false;
}
}
void UpdateChildsAlpha3(bool transparent) {
foreach(Material mat in materialList) {
mat.SetFloat("AlphaRef", Mathf.Clamp(mat.GetFloat("AlphaRef") + Time.deltaTime * enhance * (transparent ? -1 : 1), 0, 1));
}
}
PS: This script should mainly contain props and specific walls from a room so there is a script in every room with its gameObject list for better organization. So I thought that each room having its script was the best way to organize and replicate.
If you want the objects to be gone, then use a for loop with Destroy() on all the objects, and if you want them to stop being visible, just use SetActive(). If you want them to work, but just stop being visible, you can disable the renderer component.
It will be much better if you try to use some tweens to solve this problem. Like doTween or LeanTween, where they have some better-optimized way to reduce alpha or anything. Try to play around with it.

Logic error adding 2 variables together in Unity Engine

This sounds dumb, but I can't get 2 simple variables to add to each other, I have set points to add to 100 in the inspector. Everything would seem to work fine but when I all AddPoints from another script I Always get a debug log of 5. No matter what I set pointsToAdd to it always comes out as 5. I've tried score++; and that comes out just fine, I also tried to write a Debug.log just to make sure pointsToAdd wasn't set to something weird and it always returned 0! I don't know what in the world is happening. I must have screwed something up somehow.
private float score = 0;
public float pointsToAdd; // Setting in the editor
public void AddPoints()
{
score += pointsToAdd;
Debug.Log(score);
}
And the script that's calling AddPoints contains:
public LevelManager levelManager; // I'm setting in the editor
void OnCollisionEnter2D(Collision2D other)
{
if (other.transform.CompareTag("Wall"))
{
levelManager.AddPoints();
}
Edit: I've been testing for a few days now, with every chance I get completely unpredictable results until I set my score and Text UI to static variables, what about static variables changes the way that works?
Going to need a little more information on this one.
However I don't know how you are doing it in the other script, I am assuming its not this script causing the problem, most likely the other. I would personally do:
OtherScript:
pS.AddPoints(100f);
PointsScript
private float score;
public void AddPoints(float pointsToAdd)
{
score += pointsToAdd;
}

Why is my game lagging huge when I call a method?

I've been messing around trying to create an analog style scoring system for my game that I am building with Unity3D and I've noticed a huge lag when I call AnalogScoreProcessing() from the updateScore() function:
/******************************** Update Score ********************************/
public void updateScore (int newScore)
{
// Send the old score/new score to AnalogScoreProcessing()
if (oldScore != newScore)
{
AnalogScoreProcessing(oldScore, newScore);
}
// Display GUI score
oldScore = newScore;
guiText.text = "" + oldScore;
}
/*************************** Analog Scoring System ****************************/
void AnalogScoreProcessing(int oldScore, int newScore){
for(int i = oldScore; i <= newScore; i++){
print (i);
}
}
Do I have to create a new thread or a co-routine to complete the looping task while the remaining parts of updateScore() are carried out? I've never done any threading but I have used co-routines. I'm just not sure what I should be using here.
The easiest solution is to use coroutines here.
You basically want the players to see the effect of counting up right?
So say you want to display a count up to the user being +1 to the user ever few frames or so so the count up will be perceivable.
Try...
I would do it like this
int current =0;
int target = 0;
float percentateOfTarget = 0;
float step = 0.1f;
IEnumerable AnalogScoreProcessing()
{
while(current <= target)
{
current = (int)Math.Ceiling(Mathf.Lerp(current, target, percentateOfTarget));
return yield new WaitForSeconds(step);
percentageOfTarget += step;
// Display GUI score
guiText.text = "" + current;
}
}
public void updateScore (int newScore)
{
// Send the old score/new score to AnalogScoreProcessing()
if (oldScore != newScore)
{
StopCoroutine("AnalogScoreProcessing");
current = oldScore;
target = newScore;
StartCoroutine("AnalogScoreProcessing");
}
}
Please be aware this code is pulled directly out of my head so youll probably have to tweek some things here and there but should give you something close to what you desire.
You could/should even scale the GUIText up while the coroutine running for an even more dramatic effect. Let me know how it goes.
As I side note coroutines are not separate threads in unity they are ran on unity's main thread.
Well i dont understandt the Logic behind the function, but cant you just print the score once it changes?
if (oldScore != newScore)
{
//AnalogScoreProcessing(oldScore, newScore);
Debug.log(newScore);
}
Also you have to set the GUI calls inside the
OnGUI()
function inside your file.
If there is a large difference between oldScore and newScore then the print function in AnalogScoreProcessing will be run many times.
You might want to look at using a tween to change the displayed value, as you cannot display more than one value per frame anyway. Or if you're printing to the console then... why are you doing that?
edit: have moved quick and dirty solution a more appropriate question/answer

How to return an enemy to original position after losing aggro [issues[

So basically I have an enemy that, once you get close enough, will chase you around and try to attack you. Once you get far enough away, it will run back to where it was originally.
The issue I'm having is that once it runs back to where its starting point is, but doesn't quite hit the point, and keeps falling over and trying to get to that exact point..
Here's what I have for code for that section:
if (inAggroRange()) {
//In aggro range
if (!inAttackRange()) {
chase();
} else {
animation.CrossFade(animationAttack.name);
attack();
if (animation[animationAttack.name].time > 0.9 * animation[animationAttack.name].length) {
impacted = false;
}
}
} else if (!inAggroRange()){
//Go back to home position
if (!(transform.position == enemyHomePosition)) {
animation.CrossFade(animationRun.name);
transform.LookAt(enemyHomePosition);
controller.SimpleMove(transform.forward * speed);
} else {
//Enemy is at home position
animation.CrossFade(animationIdle.name);
}
}
just use
private readonly float maxDistanceToHomePosition = 0.3f; // change this value as you like
...
if((transform.position - enemyHomePosition).magnitude > maxDistanceToHomePosition)
{
...
}
...
the way you are doing it, the enemy is trying to reach one specific point but without a megaton of luck it will always be just a bit over, then turn around and try again. Much like a golf player trying to hit the whole but alyways hitting to hard.
edit: also think about using != for 'not equal', in my opinion thats a bit easier to read

Categories