Search Unity

Strange Unity Error: "IndexOutOfRangeException: Array index is out of range"

Discussion in '2D' started by TheWebExpert, Aug 14, 2017.

  1. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Code (CSharp):
    1.     public Sprite[] Preview1;
    2.      .
    3.      .
    4.      .
    5.     void PreviewLetter()
    6.       {
    7.         print("Preview1 Length: "+Preview1.Length);
    8.         if (Line == 1) Preview.sprite = Preview1[Loc1];
    9.         if (Line == 2) Preview.sprite = Preview2[Loc1];
    10.         if (Line == 3) Preview.sprite = Preview3[Loc1];
    11.         if (Line == 4) Preview.sprite = Preview4[Loc1];
    12.       }
    13.  
    I've initialized Preview1 in the inspector, and it contains 75 objects. When I first access the PreviewLetter function, I get Preview1.Length = 0 ... which is, I'm assuming, generating the error. However: The function actually works, and prints a second line. Here's what my console looks like:

    I have absolutely NO IDEA why the zero length is showing up at all; the variable isn't changed anywhere in the code, and the function continues to work, despite the error. I'd like to eliminate the error. Anyone have any clues??
     
  2. Deleted User

    Deleted User

    Guest

    It looks like you're trying to access an object in an array that doesn't exist, you can try this to find out what's missing:
    Code (csharp):
    1.  
    2. void PreviewLetter()
    3.     {
    4.         print("Preview1 Length: " + Preview1.Length);
    5.         if (Line == 1)
    6.         {
    7.             try
    8.             {
    9.                 Preview.sprite = Preview1[Loc1];
    10.             }
    11.             catch
    12.             {
    13.                 Debug.Log("Preview1[" + Loc1 + "] does not exist");
    14.             }
    15.            
    16.         }
    17.         if (Line == 3)
    18.         {
    19.             try
    20.             {
    21.                 Preview.sprite = Preview3[Loc1];
    22.             }
    23.             catch
    24.             {
    25.                 Debug.Log("Preview3[" + Loc1 + "] does not exist");
    26.             }
    27.         }
    28.         if (Line == 4)
    29.         {
    30.             try
    31.             {
    32.                 Preview.sprite = Preview4[Loc1];
    33.             }
    34.             catch
    35.             {
    36.                 Debug.Log("Preview4[" + Loc1 + "] does not exist");
    37.             }
    38.         }
    39.     }
    40. [/script]
     
  3. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    The problem is that the array actually has 75 members (set in the inspector), but comes up as zero length, then comes up as Length 75, as shown above. The member being accessed is there, it exists (I see it on the screen). The image is displayed properly; I'm just getting the error message as well.
     
  4. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Are you certain you have just one of these components in the scene? Is it possible that you have another one somewhere with nothing in the list that would cause the first message & error?

    Try including "GetInstanceID()" in your print statement to see if it's two unique objects.
     
  5. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Ok, when I printed the InstanceId, I get this:

    Code (CSharp):
    1. Preview1 Length: 0 31742
    2. UnityEngine.MonoBehaviour: print(Object)
    3.  
    4. IndexOutOfRangeException: Array index is out of range.
    5. RegisterYourName.PreviewLetter () (at Assets/Scripts/RegisterYourName.cs:170)
    6.  
    7. Preview1 Length: 75 31756
    8. UnityEngine.MonoBehaviour: print(Object)
    Additionally, I'm also receiving a NullReferenceException: Object reference not set to an instance of an object
    RegisterYourName.Update () (at Assets/Scripts/RegisterYourName.cs:124)

    The line reads as follows:

    Code (CSharp):
    1.             if (Temp == "@")
    2.               {
    3.                 if (Name.Length >= 1)
    4.                   {
    5.                   }
    6.               }
    Name has been defined as a string, and has a length of 2 (at the time I'm running this). The variable is declared locally, not public.
     
  6. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Ok, it *WAS* another DERP. The only one in the scene, huh? You were right. There was an object with the same piece of code - one I'd had earlier, but had never removed for whatever reason, and the two pieces of code were warring with each other. Getting rid of the obsolete reference solved both problems. Thanks once again!
     
    LiterallyJeff likes this.
  7. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Another (seemingly minor) question:

    I have a parallax script, as follows:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class ParallaxScroll1 : MonoBehaviour
    5.   {
    6.     public Renderer Foreground;
    7.     public Renderer Background;
    8.     public Renderer Cloud1;
    9.     public Renderer Cloud2;
    10.     public Renderer Cloud3;
    11.     public Renderer Middle;
    12.     public Renderer Stripe;
    13.     public float BackgroundSpeed = 0.02F;
    14.     public float CloudSpeed      = 0.06F;
    15.     public float ForegroundSpeed = 0.06F;
    16.     public float MiddleSpeed     = 0.06F;
    17.     public float StripeSpeed     = 0.06F;
    18.     public float Offset = 0;
    19.     Variables VarRef;
    20.     // Use this for initialization
    21.     void Start()
    22.       {
    23.         VarRef = gameObject.AddComponent<Variables>();
    24.       }
    25.     // Update is called once per frame
    26.     void Update()
    27.       {
    28.         VarRef.Load();
    29.         float BackgroundOffset = Offset;
    30.         float CloudOffset      = Offset;
    31.         float ForegroundOffset = Offset;
    32.         float MiddleOffset     = Offset;
    33.         float StripeOffset     = Offset * StripeSpeed;
    34.         Background.material.mainTextureOffset   = new Vector2(BackgroundOffset, 0);
    35.         Cloud1.material.mainTextureOffset       = new Vector2(CloudOffset, 0);
    36.         Cloud2.material.mainTextureOffset       = new Vector2(CloudOffset, 0);
    37.         Cloud3.material.mainTextureOffset       = new Vector2(CloudOffset, 0);
    38.         Foreground.material.mainTextureOffset   = new Vector2(ForegroundOffset, 0);
    39.         Middle.material.mainTextureOffset       = new Vector2(MiddleOffset, 0);
    40.         Stripe.material.mainTextureOffset       = new Vector2(StripeOffset, 0);
    41.       }
    42.   }
    43.  
    I've used this code before, and it works very well; I can control each of the 7 layers independently of each other, which is what I want. However, I've added a feature in this game to slow down or speed up the action. The controller which handles the foreground characters is working fine - but when I try to adjust the parallax, the entire set of images gets repositioned. Yes, they move more slowly (or more quickly, as the case may be), but I don't want the position to reset. I want to speed up/slow down the progress without changing the location.

    I tried this:

    Code (CSharp):
    1. float BackgroundOffset = Offset * (BackgroundSpeed * Multiplier);
    Where Multiplier is a float variable set to 0.25F or 1.00F, depending on the speed. But whenever I change the speed, the images "jump" to a new position. How can I speed this up WITHOUT resetting the position?
     
  8. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    So if I'm understanding this script correctly, the intention is to set the one variable "Offset", and have all the layers change position based on that offset * their own speed multiplier?

    If that's the case then you only need to slow down your changes to Offset, and the rest of the offsets will change slower as well.

    Just a tip, you can simplify your logic by creating a class to hold your layer data, and looping through a list of that class like this:
    Code (CSharp):
    1. using System;
    2.  
    3. [Serializable] public class Layer {
    4.     public string name;
    5.     public Renderer renderer;
    6.     public float speed = 1f;
    7.     public float currentOffsetX;
    8. }
    9.  
    10. public List<Layer> layers;
    11.  
    12. public float Offset { get; set; }
    13.  
    14. private void Update() {
    15.     foreach(Layer layer in layers) {
    16.         layer.currentOffsetX = Offset * layer.speed;
    17.         layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
    18.     }
    19. }
    20.  
    That way it's really easy to add new layers and change speeds in the inspector.
     
  9. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    So you're suggesting I try something like

    Code (CSharp):
    1. float BackgroundOffset = (Offset * Multiplier) * BackgroundSpeed;
    ??

    I don't see how that would be any different. I'm not sure what the Vector2.right is for, since I'm not using it currently. However, I don't see how this is moving anything at all... since Offset is 0, the result should always be zero. Hmm. Let me check my other code...
     
  10. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Vector2.right is the same as "new Vector2(1,0)". When multiplied by a float, it makes a Vector2 with the float as the X, and 0 as the Y.

    Maybe I misinterpreted what your original script is trying to do, but in my script example, the only variable you would change at runtime would be Offset, which would be the camera's offset from the starting point. As the camera moves, all the layers move at different speeds according to how much the camera moves with just "Offset * layer.speed".

    Could you describe what you imagine "Offset", "BackgroundSpeed", and "Multiplier" to be representing?
     
  11. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    BackgroundSpeed, CloudSpeed, MiddleSpeed (etc.) should be the speed for each layer. Offset, I thought was how much the image was being offset from its original position (i.e., how many pixels left). And multiplier SHOULD be the number I use to make it faster or slower. I want slow, normal and fast.

    Maybe this will help: In my game controller, I have the following:

    Code (CSharp):
    1.     void FixedUpdate()
    2.       {
    3.         if (VarRef.Started[VarRef.CurrPlayer] == true && VarRef.EndScene[VarRef.CurrPlayer] == false && VarRef.GameOver[VarRef.CurrPlayer] == false)
    4.           {
    5.             XPos += BackgroundSpeed;
    6.             Parallax.Offset = XPos;
    7.           }
    8.       }
    9.  
     
  12. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    I still need help with this... it's a little thing, but it's annoying!
     
  13. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    If you take another look at my reply above, that script would be able to move all the layers at different speeds, based on the current Offset.

    If you want to then speed up / slow down that offset change overall, something like this maybe?
    Code (CSharp):
    1. using System;
    2. public class Example : MonoBehaviour {
    3.     [Serializable]
    4.     public class Layer {
    5.         public string name;
    6.         public Renderer renderer;
    7.         public float speed = 1f;
    8.         public float currentOffsetX;
    9.     }
    10.  
    11.     public float parallaxSpeed;
    12.     public List<Layer> layers;
    13.  
    14.     public float Offset { get; private set; }
    15.  
    16.     private void Update() {
    17.         foreach(Layer layer in layers) {
    18.             layer.currentOffsetX = Offset * layer.speed;
    19.             layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
    20.         }
    21.     }
    22.  
    23.     public void ChangeOffsetBy(float delta) {
    24.         Offset += delta * parallaxSpeed;
    25.     }
    26. }
    So you would be using "ChangeOffsetBy" to shift the parallax incrementally, which would take into account parallaxSpeed. The "Offset" would then change slower/faster according to the speed, making each layer also reflect the speed change.
     
  14. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Both your pieces of code look useful & intriguing, but I'm not sure how to integrate it into what I have. I have:

    Code (CSharp):
    1.     public Renderer Foreground;
    2.     public Renderer Background;
    3.     public Renderer Cloud1;
    4.     public Renderer Cloud2;
    5.     public Renderer Cloud3;
    6.     public Renderer Middle;
    7.     public Renderer Stripe;
    These are passed in from the Inspector, referring to the specific objects to be scrolled. How would I put these into the layer list? Also, what about their individual speeds? Thanks!
     
  15. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    This part of the script here:
    Code (CSharp):
    1. [Serializable] public class Layer {
    2.     public string name;
    3.     public Renderer renderer;
    4.     public float speed = 1f;
    5.     public float currentOffsetX;
    6. }
    7.  
    8. public List<Layer> layers;
    Defines a new class called Layer, and then makes a public List of Layers. Since I used the [Serializable] attribute, that class's public variables can be shown in the inspector. So you will be able to add to the list as you would any other list, and configure all the variables for each layer. Then your script will have a nice list of Layers to work with, loop through, etc.

    Then in the Update, you see:
    Code (CSharp):
    1. private void Update() {
    2.     foreach(Layer layer in layers) {
    3.         layer.currentOffsetX = Offset * layer.speed;
    4.         layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
    5.     }
    6. }
    Where I loop through the list of layers, having access to all the variables for each layer configured in the inspector.
     
  16. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    I created the class:

    Code (CSharp):
    1. using System;
    2. [Serializable] public class Layer
    3.   {
    4.     public string name;
    5.     public Renderer renderer;
    6.     public float speed = 1f;
    7.     public float currentOffsetX;
    8.   }
    9. public List<Layer> layers;
    10.  
    but it says "Unexpected symbol `List', expecting `class', `delegate', `enum', `interface', `partial', or `struct'.
    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class ParallaxScroll1 : MonoBehaviour
    7.   {
    8.     public Renderer Foreground;
    9.     public Renderer Background;
    10.     public Renderer Cloud1;
    11.     public Renderer Cloud2;
    12.     public Renderer Cloud3;
    13.     public Renderer Middle;
    14.     public Renderer Stripe;
    15.     public float BackgroundSpeed = 0.02F;
    16.     public float CloudSpeed      = 0.06F;
    17.     public float ForegroundSpeed = 0.06F;
    18.     public float MiddleSpeed     = 0.06F;
    19.     public float StripeSpeed     = 0.06F;
    20.     Variables VarRef;
    21.     // Use this for initialization
    22.     void Start()
    23.       {
    24.         VarRef = gameObject.AddComponent<Variables>();
    25.       }
    26.     // Update is called once per frame
    27.     public float Offset { get; set; }
    28.     private void Update()
    29.       {
    30.         foreach(Layer layer in layers)
    31.           {
    32.             layer.currentOffsetX = Offset * layer.speed;
    33.             layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
    34.           }
    35.       }
    36.   }
    Also, in the ParallaxScroll1.cs code, it says that 'layers' does not exist in the current context.
     
  17. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Layer would be an inner class to ParallaxScroll, like this:
    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class ParallaxScroll1 : MonoBehaviour {
    7.     [Serializable]
    8.     public class Layer {
    9.         public string name;
    10.         public Renderer renderer;
    11.         public float speed = 1f;
    12.         public float currentOffsetX;
    13.     }
    14.  
    15.     public List<Layer> layers;
    16.  
    17.     public float Offset { get; set; }
    18.  
    19.     Variables VarRef;
    20.     // Use this for initialization
    21.     void Start() {
    22.         VarRef = gameObject.AddComponent<Variables>();
    23.     }
    24.     // Update is called once per frame
    25.     private void Update() {
    26.         foreach(Layer layer in layers) {
    27.             layer.currentOffsetX = Offset * layer.speed;
    28.             layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
    29.         }
    30.     }
    31. }
     
  18. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    That makes much more sense. The only remaining question is, where do I call the ChangeOffsetBy function? What do I pass to it?
     
  19. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    You can have this script manage the offset if you like, or you can have another class do that. You're passing in the change in offset between last frame and this frame, or any other amount you want to change the offset by for whatever reason.

    So if you're tracking the camera horizontal movement, you would keep a variable of the last position, and each frame get the difference between last and current and pass that into ChangeOffsetBy. Using a function allows you to have a different class interface with the parallax if necessary, but you could also do it all directly inside the parallax class.
     
  20. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Unfortunately, I don't understand your answer. Here's what I have:

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class ParallaxScroll1 : MonoBehaviour
    7.   {
    8.     [Serializable] public class Layer
    9.       {
    10.         public string name;
    11.         public Renderer renderer;
    12.         public float speed = 1f;
    13.         public float currentOffsetX;
    14.       }
    15.     public List<Layer> layers;
    16.     public float Offset { get; set; }
    17.     public float ParallaxSpeed;
    18.     Variables VarRef;
    19.     // Use this for initialization
    20.     void Start()
    21.       {
    22.         VarRef = gameObject.AddComponent<Variables>();
    23.       }
    24.     // Update is called once per frame
    25.     private void Update()
    26.       {
    27.         VarRef.Load();
    28.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] ==  0.25F) ParallaxSpeed =  0.05F; //Slow
    29.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] ==  1.00F) ParallaxSpeed =  0.00F; //Normal
    30.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] == 15.00F) ParallaxSpeed = 15.00F; //Fast
    31.         foreach(Layer layer in layers)
    32.           {
    33.             layer.currentOffsetX = Offset * layer.speed;
    34.             layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
    35.           }
    36.       }
    37.     public void ChangeOffsetBy(float delta)
    38.       {
    39.         Offset += delta * ParallaxSpeed;
    40.       }
    41.   }
    I can detect the user's input to change the speed (I'm already doing that). Once the speed has been changed, the parallax needs to change with it.

    So, on update, it checks the speed, and changes the ParallaxSpeed accordingly. I could add a line calling ChangeOffsetBy just before the "foreach," but I don't have a value to put in for delta. Can you show me what you mean? I'm lost on this.
     
  21. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Generally you wouldn't link parallax directly to player input. Parallax is a perspective illusion, and works best when linked to camera movement. I don't know the type of game you're building, but in general you would use input to move the player, the camera would follow the player around, and the parallax would change based on the camera's movement.

    Without player input, this is what it would look like:
    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class ParallaxScroll1 : MonoBehaviour {
    7.     [Serializable]
    8.     public class Layer {
    9.         public string name;
    10.         public Renderer renderer;
    11.         public float speed = 1f;
    12.         public float currentOffsetX;
    13.     }
    14.     public List<Layer> layers;
    15.     public float Offset { get; private set; }
    16.     public float ParallaxSpeed;
    17.  
    18.     float lastCameraX;
    19.  
    20.     // Use this for initialization
    21.     void Start() {
    22.         lastCameraX = Camera.main.transform.position.x;
    23.     }
    24.     // Update is called once per frame
    25.     private void Update() {
    26.         UpdateOffset();
    27.  
    28.         foreach(Layer layer in layers) {
    29.             layer.currentOffsetX = Offset * layer.speed;
    30.             layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
    31.         }
    32.     }
    33.  
    34.     private void UpdateOffset() {
    35.         float currentCameraX = Camera.main.transform.position.x;
    36.         ChangeOffsetBy(currentCameraX - lastCameraX);
    37.         lastCameraX = currentCameraX;
    38.     }
    39.  
    40.     public void ChangeOffsetBy(float delta) {
    41.         Offset += delta * ParallaxSpeed;
    42.     }
    43. }
    That way no matter what your game is doing, or how you're processing inputs, the parallax will work as the camera moves. Again I don't know how your game is supposed to work, but that's the idea.
     
    Last edited: Aug 29, 2017
  22. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    This game is different. You, the player, actually remain still (except for up & down), while the background moves from right to left, giving you the illusion that you're moving. The enemies spawn on the right and gradually move left, giving you time to avoid them or destroy them.

    What I'm trying to do is to speed things up on key input, or slow things down. Slow, Normal, Fast. The enemies are already responding to this code exactly as I wanted; it's only the background that isn't.

    I looked at your code above, and came up with this:

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class ParallaxScroll1 : MonoBehaviour
    7.   {
    8.     [Serializable] public class Layer
    9.       {
    10.         public string name;
    11.         public Renderer renderer;
    12.         public float speed = 1f;
    13.         public float currentOffsetX;
    14.       }
    15.     public List<Layer> layers;
    16.     public float Offset { get; set; }
    17.     public float ParallaxSpeed;
    18.     float LastSpeed;
    19.     Variables VarRef;
    20.     // Use this for initialization
    21.     void Start()
    22.       {
    23.         VarRef = gameObject.AddComponent<Variables>();
    24.         VarRef.Load();
    25.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] ==  0.25F) LastSpeed =   0.05F; //Slow
    26.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] ==  1.00F) LastSpeed =   0.00F; //Normal
    27.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] == 15.00F) LastSpeed = 275.00F; //Fast
    28.       }
    29.     // Update is called once per frame
    30.     private void Update()
    31.       {
    32.         VarRef.Load();
    33.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] ==  0.25F) ParallaxSpeed =   0.05F; //Slow
    34.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] ==  1.00F) ParallaxSpeed =   0.00F; //Normal
    35.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] == 15.00F) ParallaxSpeed = 275.00F; //Fast
    36.         foreach(Layer layer in layers)
    37.           {
    38.             layer.currentOffsetX = Offset * layer.speed;
    39.             layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
    40.           }
    41.       }
    42.     private void UpdateOffset()
    43.       {
    44.         float CurrentSpeed = ParallaxSpeed;
    45.         ChangeOffsetBy(ParallaxSpeed - CurrentSpeed);
    46.         LastSpeed = CurrentSpeed;
    47.       }
    48.     public void ChangeOffsetBy(float delta)
    49.       {
    50.         Offset += delta * ParallaxSpeed;
    51.       }
    52.   }
    I know the last speed chosen, so maybe using that will do what I want. The problem is, although the background SEEMS to be changing speed, it doesn't seem to be doing very much. The slow isn't much slower and the fast isn't much faster. I'm probably missing something easy here, but I'm close....
     
  23. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Ah okay, I think I understand better now what you're trying to do.

    Instead of keeping track of the LastSpeed and subtracting, try getting rid of LastSpeed altogether, and instead call "ChangeOffsetBy(ParallaxSpeed)".

    You may want to try doing "ChangeOffsetBy(ParallaxSpeed * Time.deltaTime)". That way ParallaxSpeed is framerate independent, so it will represent "units per second". You will need to increase/tweak your speed values to compensate though.

    You can also remove ParallaxSpeed from "Offset += delta * ParallaxSpeed;" It's no longer necessary.

    Also, in the code you just posted, I dont see where you call "UpdateOffset". Since you're seeing movement I assume you call it somewhere on your end.

    I imagine something like this:
    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class ParallaxScroll1 : MonoBehaviour {
    7.     [Serializable]
    8.     public class Layer {
    9.         public string name;
    10.         public Renderer renderer;
    11.         public float speed = 1f;
    12.         public float currentOffsetX;
    13.     }
    14.     public List<Layer> layers;
    15.     public float Offset { get; set; }
    16.     public float ParallaxSpeed;
    17.  
    18.     Variables VarRef;
    19.  
    20.     // Use this for initialization
    21.     void Start() {
    22.         VarRef = gameObject.AddComponent<Variables>();
    23.         UpdateParallaxSpeed();
    24.     }
    25.  
    26.     // Update is called once per frame
    27.     private void Update() {
    28.         UpdateParallaxSpeed();
    29.         UpdateOffset();
    30.         foreach(Layer layer in layers) {
    31.             layer.currentOffsetX = Offset * layer.speed;
    32.             layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
    33.         }
    34.     }
    35.  
    36.     private void UpdateParallaxSpeed() {
    37.         VarRef.Load();
    38.         if(VarRef.CurrSpeed1[VarRef.CurrPlayer] == 0.25F)
    39.             ParallaxSpeed = 0.05F; //Slow
    40.         if(VarRef.CurrSpeed1[VarRef.CurrPlayer] == 1.00F)
    41.             ParallaxSpeed = 0.00F; //Normal
    42.         if(VarRef.CurrSpeed1[VarRef.CurrPlayer] == 15.00F)
    43.             ParallaxSpeed = 275.00F; //Fast
    44.     }
    45.  
    46.     private void UpdateOffset() {
    47.         float CurrentSpeed = ParallaxSpeed;
    48.         ChangeOffsetBy(ParallaxSpeed * Time.deltaTime);
    49.         LastSpeed = CurrentSpeed;
    50.     }
    51.     public void ChangeOffsetBy(float delta) {
    52.         Offset += delta;
    53.     }
    54. }
     
    Last edited: Aug 29, 2017
  24. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Ok, I've changed the code:

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class ParallaxScroll1 : MonoBehaviour
    7.   {
    8.     [Serializable] public class Layer
    9.       {
    10.         public string name;
    11.         public Renderer renderer;
    12.         public float speed = 1F;
    13.         public float currentOffsetX;
    14.       }
    15.     public List<Layer> layers;
    16.     public float Offset { get; set; }
    17.     public float ParallaxSpeed;
    18.     Variables VarRef;
    19.     // Use this for initialization
    20.     void Start()
    21.       {
    22.         VarRef = gameObject.AddComponent<Variables>();
    23.         UpdateParallaxSpeed();
    24.       }
    25.     // Update is called once per frame
    26.     private void Update()
    27.       {
    28.         VarRef.Load();
    29.         UpdateParallaxSpeed();
    30.         UpdateOffset();
    31.         foreach(Layer layer in layers)
    32.           {
    33.             layer.currentOffsetX = Offset * layer.speed;
    34.             layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
    35.           }
    36.       }
    37.     private void UpdateParallaxSpeed()
    38.       {
    39.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] ==  0.25F) ParallaxSpeed =  0.00F; //Slow
    40.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] ==  1.00F) ParallaxSpeed =  2.00F; //Normal
    41.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] == 15.00F) ParallaxSpeed = 15.00F; //Fast
    42.       }
    43.     private void UpdateOffset()
    44.       {
    45.         ChangeOffsetBy(ParallaxSpeed * Time.deltaTime);
    46.       }
    47.     public void ChangeOffsetBy(float delta)
    48.       {
    49.         Offset += delta;
    50.       }
    51.   }
    No matter what I do, though, the "slow" doesn't seem to slow it at all; and the fast is very jerky, not smooth. I've tried lower numbers & higher ones, but I'm still not getting the right effect.
     
  25. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    I'm not sure what would be causing that. You should try outputting some values in the console and seeing what looks wrong. Double check what you expect the speeds to be, the offset, etc.

    Just FYI, I am going to be gone for the next 5 days so hopefully you can figure this out, or worst case start a new thread.
     
  26. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Here's my current code:

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class ParallaxScroll1 : MonoBehaviour
    7.   {
    8.     [Serializable] public class Layer
    9.       {
    10.         public string name;
    11.         public Renderer renderer;
    12.         public float speed = 1F;
    13.         public float currentOffsetX;
    14.       }
    15.     public List<Layer> layers;
    16.     public float Offset { get; set; }
    17.     public float ParallaxSpeed;
    18.     Variables VarRef;
    19.     // Use this for initialization
    20.     void Start()
    21.       {
    22.         VarRef = gameObject.AddComponent<Variables>();
    23.         //UpdateParallaxSpeed();
    24.       }
    25.     // Update is called once per frame
    26.     private void Update()
    27.       {
    28.         VarRef.Load();
    29.         UpdateParallaxSpeed();
    30.         foreach(Layer layer in layers)
    31.           {
    32.             layer.currentOffsetX = (Offset * layer.speed) / ParallaxSpeed;
    33.             layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
    34.           }
    35.       }
    36.     private void UpdateParallaxSpeed()
    37.       {
    38.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] ==  0.25F) ParallaxSpeed = 200.00F; //Slow
    39.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] ==  1.00F) ParallaxSpeed = 100.00F; //Normal
    40.         if (VarRef.CurrSpeed1[VarRef.CurrPlayer] == 15.00F) ParallaxSpeed =  20.00F; //Fast
    41.       }
    42.   }
    This seems to work better; the background is slowed down or sped up. There is a "jump" in the scenery when you do this, but...
     
  27. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    The jump is due to the way you're handling the Offset.

    The Offset represents the total offset so far. So if you change the ParallaxSpeed, the total Offset will change, not just the rate of change from then on. That's why I was using a separate method to add into the Offset incrementally. You need to apply speed changes to all future changes in Offset. Not to the total offset already applied.