Search Unity

Checking A List

Discussion in 'Scripting' started by DRRosen3, Nov 4, 2014.

  1. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    I have two scripts. One called "BaseMonster" and another called "MonstersMoves". Both are attached the to prefab for the monster. I'm trying to have "MonstersMoves" read "BaseMonster" and dig into a List inside the "BaseMonster" script. It needs to see if that List already contains a move and if it does NOT, and the "Level" variable that's also in "BaseMonster" is a certain level then add the move to the list. (The moves are scrips themselves. What I'm resulting in...is that it just keeps adding the move to the list non-stop. What am I doing wrong? The C# code below is from the "MonstersMoves" script.

    Code (CSharp):
    1. public List<BaseMove> moves;
    2.      void Awake(){
    3.          moves = gameObject.GetComponent<BaseMonster>().monstersMoves;
    4.      }
    5.      void Update(){
    6.          SetupMoves(gameObject.GetComponent<BaseMonster>().Level);
    7.      }
    8.      private void SetupMoves(int level){
    9.          if(level == 1 && !moves.Contains(new Scratch())){
    10.              moves.Add(new Scratch());
    11.          }
     
  2. willemsenzo

    willemsenzo

    Joined:
    Nov 15, 2012
    Posts:
    585
    The reason why the move is getting added non stop is because you call SetupMoves in the update function which essentially means you call that function every frame. Also, it's better to make a reference to BaseMonster once in the start function instead of calling gameObject.GetComponent every frame in the update function.
     
  3. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    I figured it needs to be in the Update function so that way when the monster levels up to a level where he'd gain a new move, it would be added to the list since the method is called every frame. And shouldn't the line of code that says: "!moves.Contains(new Scratch())" make the fact that it's in Update not a problem? I mean, if it returns true (in that the List<T> DOES contain the move), the "if statement" isn't completed and it shouldn't return right?
     
  4. willemsenzo

    willemsenzo

    Joined:
    Nov 15, 2012
    Posts:
    585
    You're correct my bad for not reading so well. Seems like this is not the source of your problem. Did you (for debugging purposes) try to check if moves.Contains(new Scratch()) and see what happens?
     
  5. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    Alright. So I just tried the code two different ways for debugging purposes. The first way I tried it:
    Code (CSharp):
    1.     private void SetupMoves(int level){
    2.         if(level == 1 && !moves.Contains(new Scratch())){
    3.             Debug.Log("Moves DOES contain Scratch");
    4.         }else{
    5.             Debug.Log("Moves does not contain Scratch");
    6.             moves.Add(new Scratch());
    7.         }
    This returned "Moves DOES contain Scratch" every frame and did not add it to the List<T>.

    The second way I tried it:
    Code (CSharp):
    1.     private void SetupMoves(int level){
    2.         if(level == 1 && moves.Contains(new Scratch())){
    3.             Debug.Log("Moves DOES contain Scratch");
    4.         }else{
    5.             Debug.Log("Moves does not contain Scratch");
    6.             moves.Add(new Scratch());
    7.         }
    This returned "Moves does not contain Scratch" every frame and added it to the List<T> repeatedly every frame.

    I'm stumped. :(
     
  6. willemsenzo

    willemsenzo

    Joined:
    Nov 15, 2012
    Posts:
    585
    Forgive me for not fully understanding what you're trying to do, but for as far I can tell the 'moves' list stores BaseMove objects am I right? So if the moves list stores BaseMove objects, why are you trying to see if it contains Scratch objects? Isn't list.Contains only looking for types that match with the type the list itself stores (in this case BaseMove)? Once again forgive me for my ignorance, I've used list.Contains but not the way you're trying to use it so maybe I'm missing something.
     
  7. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    Sorry, I should have elaborated on that. Scratch derives from BaseMove. I use BaseMove like a base class and I create all the attacks (in their own scripts) and they all derive from BaseMove.

    I THINK the problem has something to do with the fact that I'm checking to see if the List<T> contains a NEW instance of Scratch. However, when I try to write that line like this:
    Code (CSharp):
    1. if(level >= 1 && !moves.Contains(Scratch())){
    ...it returns these three errors:
    1. error CS0119: Expression denotes a `type', where a `variable', `value' or `method group' was expected
    2. error CS1502: The best overloaded method match for `System.Collections.Generic.List<BaseMove>.Contains(BaseMove)' has some invalid arguments
    3. error CS1503: Argument `#1' cannot convert `object' expression to type `BaseMove'
     
    Last edited: Nov 4, 2014
  8. willemsenzo

    willemsenzo

    Joined:
    Nov 15, 2012
    Posts:
    585
    DRRosen3 likes this.
  9. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    That's it! Thanks @willemsenzo ! This worked it out:
    Code (CSharp):
    1. public List<BaseMove> moves;
    2. public int level;
    3. public Scratch scratch = new Scratch();
    4.  
    5.     void Awake(){
    6.         moves = gameObject.GetComponent<BaseMonster>().monstersMoves;
    7.         level = gameObject.GetComponent<BaseMonster>().Level;
    8.     }
    9.  
    10.     void Update(){
    11.         SetupMoves(level);
    12.     }
    13.  
    14.     private void SetupMoves(int level){
    15.         if(level >= 1 && !moves.Contains(scratch)){
    16.             moves.Add(scratch);
    17.         }
    18. }
    Now the issue I'm having (which might not be an issue during actual (compiled) run-time is that when I adjust the monster's level in the inspector manually (while the game is playing) it doesn't add the rest of the moves (that the monster learns at higher levels) to the list.
     
  10. willemsenzo

    willemsenzo

    Joined:
    Nov 15, 2012
    Posts:
    585
    That might have something to do because scratch is already on the list so Contains returns always true (hence the function never adds another scratch).
     
    Last edited: Nov 4, 2014
  11. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    Nah...I mean the rest of the moves. Here's the code in entirety:
    Code (CSharp):
    1.  
    2. public List<BaseMove> moves;
    3. public int level;
    4. public Scratch scratch = new Scratch();
    5. public Growl growl = new Growl();
    6. public Fireball fireball = new Fireball();
    7. public Powerup powerup = new Powerup();
    8.  
    9. void Awake(){
    10.         moves = gameObject.GetComponent<BaseMonster>().monstersMoves;
    11.         level = gameObject.GetComponent<BaseMonster>().Level;
    12.     }
    13.  
    14. void Update(){
    15.         SetupMoves(level);
    16.     }
    17.  
    18. private void SetupMoves(int level){
    19.         if(level >= 1 && !moves.Contains(scratch)){
    20.             moves.Add(scratch);
    21.         }
    22.         if(level >= 1 && !moves.Contains(growl)){
    23.             moves.Add(growl);
    24.         }
    25.         if(level >= 7 && !moves.Contains(fireball)){
    26.             moves.Add(fireball);
    27.         }
    28.         if(level >= 10 && !moves.Contains(powerup)){
    29.             moves.Add(powerup);
    30.         }
    31.     }
    32.  
    33. }
    At Play the Monster is level 1. When I cranked the level up to 7 fireball wasn't added. Then I cranked it up to 10 and fireball still wasn't added and neither was powerup.
     
  12. willemsenzo

    willemsenzo

    Joined:
    Nov 15, 2012
    Posts:
    585
    You're never changing the value of level except in the Awake function just once so it always stays at level = 1. You are checking every update if level changes but you never change it. Another tip, don't use Awake to initialize your variables because it might cause an error when you try to access a script that isn't loaded already, use start function instead.

    Edit: Sorry for another suggestion lol. Make a reference to the BaseMonster script so you don't have to call GetComponent every time you want to access the Level property on it. Then in update just get the value of Level through the reference you made.
     
    DRRosen3 likes this.
  13. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    Yup! I just realized it as you posted your reply that I was never updating level. Thanks for the tip about awake. Never thought of that.
     
  14. willemsenzo

    willemsenzo

    Joined:
    Nov 15, 2012
    Posts:
    585
    No problem you seem like a nice person to me who actually uses his brain and is willing to learn from others. I'm glad I could be of help.
     
    DRRosen3 likes this.
  15. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    Well...it seems I'm re-approaching this problem. What I'm now experiencing is...uhm...I guess you could say when I "despawn" the monster (the player has killed it), and "respawn" it...it adds all the moves to the list all over again. For example:

    Monster A has 2 moves in his list: Scratch & Growl...
    Monster A dies...
    Monster A respawns...
    Monster A now has 4 moves in his list: Scratch & Growl...AND...Scratch & Growl...

    Nothing about the code has changed...it's still written as is:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class MonsterMoves : MonoBehaviour {
    6.  
    7.     public List<BaseMove> moves;
    8.     public int level;
    9.     public Scratch scratch = new Scratch();
    10.     public Growl growl = new Growl();
    11.     public FireBall fireball = new FireBall();
    12.     public PowerUp powerup = new PowerUp();
    13.  
    14.     void Start(){
    15.         moves = gameObject.GetComponent<Monster>().monstersMoves;
    16.         level = gameObject.GetComponent<Monster>().level;
    17.     }
    18.  
    19.     void Update(){
    20.         level = gameObject.GetComponent<Monster>().level;
    21.         SetupMoves(level);
    22.     }
    23.  
    24.     private void SetupMoves(int level){
    25.         if(level >= 1 && !moves.Contains(scratch)){
    26.             moves.Add(scratch);
    27.         }
    28.         if(level >= 1 && !moves.Contains(growl)){
    29.             moves.Add(growl);
    30.         }
    31.         if(level >= 7 && !moves.Contains(fireball)){
    32.             moves.Add(fireball);
    33.         }
    34.         if(level >= 10 && !moves.Contains(powerup)){
    35.             moves.Add(powerup);
    36.         }
     
    Last edited: Dec 20, 2014