Search Unity

Change Sprite Based on Menu Selection

Discussion in '2D' started by j0hns0usa, May 3, 2017.

  1. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    I am really new at this and building a 2D air hockey game for a final project. I've got the menu built and can go through and get the game started, however, I wanted to allow users to select the team they'd like to play as. I only have 4 options and proper assets for each based on Player 1/Player 2 (8 assets total).

    How can I make it so that the sprite for each player is modified in scene 1 based on menu selections from scene 0?
     
  2. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    Two options that come to mind are:

    1. Use a gameobject (and a script) that use "DontDestroyOnLoad" to store the selection you've made. If this is in scene 0, it will also continue to live in scene 1 , where you can reference your data for the sprites.
    2. Use a couple of static variables for the chosen for the teams and look those up in the next scene.
     
    vakabaka likes this.
  3. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    5,343
    vakabaka likes this.
  4. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    I understand what you're referencing, but could you provide an example?
    I went to the link, but it isn't really clear what I should choose next from PlayerPrefs..
     
  5. vakabaka

    vakabaka

    Joined:
    Jul 21, 2014
    Posts:
    1,017
    as example for PlayerPrefs:
    You have a player. In the menu this player can select one team. If team is selected you can save its state in the PlayerPrefs:
    Code (CSharp):
    1. PlayerPrefs.SetInt ("PlayerOne", 2);
    2. //or PlayerPrefs.SetString ("P1", "red");
    3. //or something other
    Now you will have saved variable. In the next scene you can check the saved variable and "spawn/place/change" needed team.
    Code (CSharp):
    1. void Start {
    2. //to avoid error if no variable was saved
    3. if (PlayerPrefs.HasKey ("PlayerOne")) {
    4. if (PlayerPrefs.GetInt("PlayerOne") == 2) {
    5. //place team 2
    6. }
    7. } else {
    8. //place default team
    9. }
     
  6. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    I think I understand a little bit better now. So in the menu I have created, there are 4 button options for each player at different levels of the menu. I would attach that script to each button of the menu and connect it to the asset somehow?

     
  7. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
  8. vakabaka

    vakabaka

    Joined:
    Jul 21, 2014
    Posts:
    1,017
    you can make script, something like:
    Code (CSharp):
    1. public string team;
    2.  
    3. public void SetTeam () {
    4. PlayerPrefs.SetString ("playersTeam", team);
    5. }
    then add this script to every buttons gameobject (which changes the team). Change string "team" depended on button. Add new event (click + in on click), choose the needed button and select SetTeam () funktion. Now if you click the button, the function should be started and save the variable in the PlayerPrefs. Maybe you will need adjust script for the second player (boolean or something similar)
     
  9. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    It seems you got some good help while I was away. I'm not sure what kind of example I can really write for my scenario.
    If you had/did make a gameobject that used DontDestroyOnLoad, it would have a script and inside that script you'd have a variable for the team. That object would persist to the next level and you could look it up.
    It's almost the same thing (a script with some variables) for the static variable, except that that could be with or without DontDestroyOnLoad, since the static variables are part of the class instead of the object/instance of the class. :)
     
  10. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
  11. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    Actually, I think this is the route I am taking.

    Just to be sure, I am using the PlayerPrefs.SetInt in the first scene, and checking it against PlayerPrefs.GetInt in the next, correct?
     
  12. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    I've got the set int side of it done in scene 0:

    Code (CSharp):
    1. public int team;
    2. public void SetTeam() {
    3.  
    4.         PlayerPrefs.SetInt ("Player One", team);
    5.  
    6. }
    upload_2017-5-7_9-5-25.png

    How do I check it in the next scene with get int and apply the asset I want to the sprite?
     
  13. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    Use:
    Code (csharp):
    1.  
    2. int team = PlayerPrefs.GetInt("team");
    3.  
    as for applying the sprite, I guess you need to know player1 or player2 and then use the team variable as an index in an array to get the sprite you want to apply.
     
  14. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    Here's what I have in my playerOneGet script:
    Code (CSharp):
    1. public class playerOneGet : MonoBehaviour {
    2.  
    3.     void Start() {
    4.      
    5.         if (PlayerPrefs.HasKey ("Player One")) {
    6.             if (PlayerPrefs.GetInt ("Player One") == 1) {
    7.                 Sprite devils1 = Resources.Load ("Devils1", typeof(Sprite)) as Sprite;
    8.                 GameObject player01 = new GameObject ("player01");
    9.                 SpriteRenderer rend = player01.AddComponent(typeof(SpriteRenderer)) as SpriteRenderer;
    10.                 rend.sprite = devils1;
    11.             }
    12.         }
    13.         if (PlayerPrefs.HasKey ("Player One")) {
    14.             if (PlayerPrefs.GetInt ("Player One") == 2) {
    15.                 Sprite rangers1 = Resources.Load ("Rangers1", typeof(Sprite)) as Sprite;
    16.                 GameObject player01 = new GameObject ("player01");
    17.                 SpriteRenderer rend = player01.AddComponent (typeof(SpriteRenderer)) as SpriteRenderer;
    18.                 rend.sprite = rangers1;
    19.             }
    20.         }
    21.         if (PlayerPrefs.HasKey ("Player One")) {
    22.             if (PlayerPrefs.GetInt ("Player One") == 3) {
    23.                 Sprite flyers1 = Resources.Load ("Flyers1", typeof(Sprite)) as Sprite;
    24.                 GameObject player01 = new GameObject ("player01");
    25.                 SpriteRenderer rend = player01.AddComponent (typeof(SpriteRenderer)) as SpriteRenderer;
    26.                 rend.sprite = flyers1;
    27.             }
    28.         }
    29.         if (PlayerPrefs.HasKey ("Player One")) {
    30.             if (PlayerPrefs.GetInt ("Player One") == 2) {
    31.                 Sprite islanders1 = Resources.Load ("Islanders1", typeof(Sprite)) as Sprite;
    32.                 GameObject player01 = new GameObject ("player01");
    33.                 SpriteRenderer rend = player01.AddComponent (typeof(SpriteRenderer)) as SpriteRenderer;
    34.                 rend.sprite = islanders1;
    35.             }
    36.         }
    37.     }
    38. }
    But I'm not positive that I want to create a new GameObject, if that's what it is doing.. I just want to replace the already existing "player01" gameObject
     
  15. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
  16. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    If you made 2 arrays of the sprites you want to use , for player 1 and player 2 (in the same order)
    you could simplify it a little bit and say:
    if player 1:
    Code (csharp):
    1.  
    2. rend.sprite = player1Sprites[team]; // after you got team with GetInt in playerPrefs
    3.  
    does that make sense?

    Your way is working, too, right?
     
  17. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    No, my way is NOT working.
     
  18. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    I don't think I'm connecting everything together properly. I really have no idea what I'm doing.

    How do I know that when scene 1 starts after scene 0, that it is even grabbing the correct int from the SetInt script that I have?
     
  19. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    Okay, baby steps here. When you load scene one just do:
    Code (csharp):
    1.  
    2. void Start() {
    3.    int p = PlayerPrefs.GetInt("Player One");
    4.    print("p = " + p);
    5.   }
    6.  
    let's see if that works.
     
  20. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    Do I add that as a New Component? Where am I putting that script?
     
  21. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    Ok, I found where to put it and checked the console.

    It prints "p = 0" no matter what selection I make.

    For each of the buttons and the SetInt script, I have made the team variable 1-4 for each: 1, 2, 3 ,4..
     
  22. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    maybe you need something like this, if you don't have it already?
    buttons call to a function:
    Code (csharp):
    1.  
    2. void SetTeam(int num) {
    3.    PlayerPrefs.SetInt("Player One", num);
    4.    }
    5.  
    I'm not sure how you were setting it before..
    Set the OnClick in the inspector to call this function and supply the parameter in the inspector
     
  23. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    This is how I was doing it:
    upload_2017-5-7_11-28-54.png
    I set that Team variable.
    How would I utilize it in the On Click () section above?
     
  24. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    You said you have buttons, let's say you put the function I wrote in Player One Set
    then you add a new On Click event (Is this script on each team button?)
    you would add the event, then drag the button where the game object goes, then choose the method i wrote and then you'd have a field to enter a value and you put the team # there.

    Please explain if that's different from your setup.
     
  25. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    That last image is from a button. I put that script you see with the team variable on each button. Are you saying instead of as a separate component, I should put the playerOneSet script in the On Click events?
     
  26. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    Ah okay, on each button fair enough.. That's virtually the same thing I was saying in a slightly different way.
    So, if you have that team # set there, instead of passing it in from the OnClick (which was my suggestion), you just need to call a method (like the one I wrote) but instead of it taking an int parameter, use the one you set in the script
     
  27. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    Wait, so instead of an int, what an I using?

    Where it says: "Team 1" in the picture, should it be something else?
     
  28. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    I feel like we've got round in a circle, instead of int as a parameter, get OnClick to call
    Code (csharp):
    1.  
    2. public int Team = 1;  // set in the inspector for different choices.
    3. public void SetTeam() {
    4.    PlayerPrefs.SetInt("Player One", Team);
    5.    }
    6.  
    Not sure why this wasn't working before, because I swear you had this I thought already.
    Then when you load the next scene and do:
    Code (csharp):
    1.  
    2. int p = PlayerPrefs.GetInt("Player One");
    3.  
    You should get whichever one you set.
     
  29. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    I think I'm pickin' up what you're puttin' down:
    upload_2017-5-7_11-58-46.png
    My testOut script:
    Code (CSharp):
    1. public class testOut : MonoBehaviour {
    2.  
    3.     public int Team = 1;  // set in the inspector for different choices.
    4.     public void SetTeam() {
    5.         PlayerPrefs.SetInt("Player One", Team);
    6.     }
    7. }
    8.  
     
  30. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    Okay so when you choose "SetTeam" from the drop down and try to pick a team & go to the next scene..what happens?.. <DrumRoll> ? lol
     
  31. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    p = 0
     
  32. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    Just to note: There was only 1 small difference between this solution and passing the variable to the method , as describe earlier, and that is:
    in the 'passing the variable' example, you could have had 1 script on 1 object , and each button could reference that object, its method and assign the variable in the inspector there.
    This other solution just has x number of script instances.. really not a huge deal, just explaining. :)
     
  33. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    SetTeam is not in the dropdown:
    upload_2017-5-7_12-6-11.png
     
  34. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    Alright, well I am prepared to feel a bit silly here:
    try to add:
    Code (csharp):
    1.  
    2. PlayerPrefs.Save();
    3.  
    re-run the test & does that fix? To my knowledge, which may be corrected just now, that isn't required simply between scenes, but I guess we'll see.
     
  35. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    Oh , wait what?
    You have to attach the gameobject that has the script with SetTeam on it attached.
    Then the dropdown will have it.
    Script on gameobject, gameobject in slot for OnClick..
     
  36. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    This may sound silly, but what gameobject? The object in which I ultimately want the sprite changed for? Or the button that I am trying to register the value from?
     
  37. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    Not silly, put the script on the button.
    Set the value to match which team that button would represent.
    Then drag the button into the gameobject slot of OnClick , and you'll see the method in the dropdown.
     
  38. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    Like this?:
    upload_2017-5-7_12-22-27.png
     
  39. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    Here we go, ignore the previous:
    upload_2017-5-7_12-25-39.png
     
  40. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    This passes the correct value to scene 1 from scene 0.

    Now, I need that value to translate to a different asset in the spriterenderer
     
  41. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    right on.. Well, if you want to use resources.Load I guess you could have a string array with the names in the same order?
    You could re-write Get/Set Int to Get/Set String and save the team there.
    or you could just have an array of Sprites in a script that are ordered the same as the buttons from the first scene.
    Whatever works for ya.
     
  42. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    I should create two different scripts for each player in terms of the testOut script correct?
    The console only prints the number of player two since it's using the same script.
     
  43. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    How could I write a script to use an array from the assets in Resources.Load ?
     
  44. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    You could add a second method for player 2 in the testOut script and on the player 2 buttons assign that function instead of the first one. Change the key you save and add a second variable for player 2's team. Same thing.
     
  45. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    Dunno about writing an array for Resources.Load other than an array of strings - I've not used that much, but the examples I've seen are always looking things up by string.
    Edit: looked it up, sure enough, string is how it's done.
     
  46. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    I've added a second method for player 2 that continues down the int values: 5,6,7,8 since I used 1,2,3,4 for player one.
    Hope that make sense.
    As far as this goes, I can't use the script I had before somehow?:
    Code (CSharp):
    1. public class playerOneGet : MonoBehaviour {
    2.  
    3.     void Start() {
    4.  
    5.         if (PlayerPrefs.HasKey ("Player One")) {
    6.             if (PlayerPrefs.GetInt ("Player One") == 1) {
    7.                 Sprite devils1 = Resources.Load ("Devils1", typeof(Sprite)) as Sprite;
    8.                 GameObject player01 = new GameObject ("player01");
    9.                 SpriteRenderer rend = player01.AddComponent(typeof(SpriteRenderer)) as SpriteRenderer;
    10.                 rend.sprite = devils1;
    11.             }
    12.         }
    13.         if (PlayerPrefs.HasKey ("Player One")) {
    14.             if (PlayerPrefs.GetInt ("Player One") == 2) {
    15.                 Sprite rangers1 = Resources.Load ("Rangers1", typeof(Sprite)) as Sprite;
    16.                 GameObject player01 = new GameObject ("player01");
    17.                 SpriteRenderer rend = player01.AddComponent (typeof(SpriteRenderer)) as SpriteRenderer;
    18.                 rend.sprite = rangers1;
    19.             }
    20.         }
    21.         if (PlayerPrefs.HasKey ("Player One")) {
    22.             if (PlayerPrefs.GetInt ("Player One") == 3) {
    23.                 Sprite flyers1 = Resources.Load ("Flyers1", typeof(Sprite)) as Sprite;
    24.                 GameObject player01 = new GameObject ("player01");
    25.                 SpriteRenderer rend = player01.AddComponent (typeof(SpriteRenderer)) as SpriteRenderer;
    26.                 rend.sprite = flyers1;
    27.             }
    28.         }
    29.         if (PlayerPrefs.HasKey ("Player One")) {
    30.             if (PlayerPrefs.GetInt ("Player One") == 2) {
    31.                 Sprite islanders1 = Resources.Load ("Islanders1", typeof(Sprite)) as Sprite;
    32.                 GameObject player01 = new GameObject ("player01");
    33.                 SpriteRenderer rend = player01.AddComponent (typeof(SpriteRenderer)) as SpriteRenderer;
    34.                 rend.sprite = islanders1;
    35.             }
    36.         }
    37.     }
    38. }
     
  47. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    Oh yea for sure you can. WHen I wrote before the idea of simplifying that script, I thought yours was working, but it could just be a bit shorter.
    Try it like that & see what happens.
    Just 1 small note, you can wrap all four options inside 1 check to "If(PlayerPrefs.HasKey" instead of 4 of those..
    or maybe even 0 check for has key, unless you can start your game without picking a team at all ;)
     
  48. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    Well I had it set to play with preset teams, but had to add more functionality for the project, so I thought giving a player, team options, would be simple. But it's proving not to be the case for my skill set
     
  49. j0hns0usa

    j0hns0usa

    Joined:
    Apr 2, 2017
    Posts:
    43
    The other issue is, when I tell it "new GameObject", is it really creating a new object or updating the already existing player01 game object?
     
  50. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,713
    new would be making a new one. You're just naming it "Player one"

    You didn't say if this loading is working or not - is it?