auth and rc purchase dummy
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -457,7 +457,7 @@ SpriteRenderer:
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8305397236103417568}
|
||||
m_Enabled: 1
|
||||
m_Enabled: 0
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 0
|
||||
m_DynamicOccludee: 1
|
||||
|
||||
@@ -6952,6 +6952,10 @@ PrefabInstance:
|
||||
propertyPath: m_IsActive
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4641041899451829863, guid: c3a9beee82147c54b960a10faf404e0f, type: 3}
|
||||
propertyPath: m_Enabled
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5896139376663135640, guid: c3a9beee82147c54b960a10faf404e0f, type: 3}
|
||||
propertyPath: m_CollisionDetection
|
||||
value: 1
|
||||
|
||||
+3718
-20
File diff suppressed because it is too large
Load Diff
+2915
-41
File diff suppressed because it is too large
Load Diff
@@ -1,8 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class IntroSceneManager : MonoBehaviour
|
||||
{
|
||||
public void OnPlay(){
|
||||
LevelLoadManager.LoadLevel("MainMenu");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,471 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class LoginManager : MonoBehaviour
|
||||
{
|
||||
const string AuthBaseUrl = "http://vps.playpoolstudios.com:2612";
|
||||
const string PlayerPrefsAuthKey = "WalkInvest.AuthToken";
|
||||
|
||||
const int MIN_USERNAME_LENGTH = 3;
|
||||
const int MAX_USERNAME_LENGTH = 16;
|
||||
const int MIN_PASSWORD_LENGTH = 8;
|
||||
const int MAX_PASSWORD_LENGTH = 20;
|
||||
|
||||
[Header("Login")]
|
||||
[SerializeField] private TMP_InputField usernameInputLogin;
|
||||
[SerializeField] private TMP_InputField passwordInputLogin;
|
||||
[SerializeField] private Button btnLogin;
|
||||
[Header("Register")]
|
||||
[SerializeField] private TMP_InputField usernameInputRegister;
|
||||
[SerializeField] private TMP_InputField passwordInputRegister;
|
||||
[SerializeField] private Button btnRegister;
|
||||
|
||||
[Header("UI")]
|
||||
[SerializeField] private TMP_Text error_txt;
|
||||
|
||||
bool _authInProgress;
|
||||
|
||||
public static string AuthToken { get; private set; }
|
||||
|
||||
/// <summary>Latest user payload from the server. Reading this schedules a refresh (one in flight at a time).</summary>
|
||||
public static UserData CurrentUser
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance != null)
|
||||
instance.ScheduleUserDataRefreshOnRead();
|
||||
return _currentUser;
|
||||
}
|
||||
}
|
||||
|
||||
public static Action<UserData> OnUserDataUpdated;
|
||||
|
||||
static UserData _currentUser;
|
||||
bool _userDataReadRefreshPending;
|
||||
|
||||
[Serializable]
|
||||
class AuthApiResponse
|
||||
{
|
||||
public bool ok;
|
||||
public string error;
|
||||
public string token;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class AuthUserApiResponse
|
||||
{
|
||||
public bool ok;
|
||||
public string error;
|
||||
public UserData user;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class PurchaseRcApiResponse
|
||||
{
|
||||
public bool ok;
|
||||
public string error;
|
||||
}
|
||||
|
||||
public static LoginManager instance;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
error_txt.text = "";
|
||||
AuthToken = PlayerPrefs.GetString(PlayerPrefsAuthKey, "");
|
||||
|
||||
if(instance !=null){
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
btnLogin.onClick.AddListener(OnLogin);
|
||||
btnRegister.onClick.AddListener(OnRegister);
|
||||
|
||||
if (!string.IsNullOrEmpty(AuthToken))
|
||||
{
|
||||
SetBusy(true);
|
||||
StartCoroutine(ResumeSessionCoroutine());
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator ResumeSessionCoroutine()
|
||||
{
|
||||
yield return StartCoroutine(FetchUserDataCoroutine(null, true));
|
||||
ProceedToMainMenu();
|
||||
SetBusy(false);
|
||||
}
|
||||
|
||||
static void ProceedToMainMenu()
|
||||
{
|
||||
if (LevelLoadManager.instance != null)
|
||||
LevelLoadManager.LoadLevel("MainMenu");
|
||||
else
|
||||
SceneManager.LoadScene("MainMenu");
|
||||
}
|
||||
|
||||
void SetBusy(bool busy)
|
||||
{
|
||||
_authInProgress = busy;
|
||||
if (btnLogin != null) btnLogin.interactable = !busy;
|
||||
if (btnRegister != null) btnRegister.interactable = !busy;
|
||||
}
|
||||
|
||||
void OnLogin()
|
||||
{
|
||||
if (_authInProgress) return;
|
||||
|
||||
string username = usernameInputLogin.text;
|
||||
string password = passwordInputLogin.text;
|
||||
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
|
||||
{
|
||||
error_txt.text = "Please fill in all fields";
|
||||
return;
|
||||
}
|
||||
|
||||
if (username.Length < MIN_USERNAME_LENGTH || username.Length > MAX_USERNAME_LENGTH)
|
||||
{
|
||||
error_txt.text = "Username must be between " + MIN_USERNAME_LENGTH + " and " + MAX_USERNAME_LENGTH + " characters";
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.Length < MIN_PASSWORD_LENGTH || password.Length > MAX_PASSWORD_LENGTH)
|
||||
{
|
||||
error_txt.text = "Password must be between " + MIN_PASSWORD_LENGTH + " and " + MAX_PASSWORD_LENGTH + " characters";
|
||||
return;
|
||||
}
|
||||
|
||||
string json = "{\"username\":\"" + EscapeJsonString(username) + "\",\"password\":\"" + EscapeJsonString(password) + "\"}";
|
||||
StartCoroutine(AuthPostCoroutine(AuthBaseUrl + "/auth/login", json, "Signed in."));
|
||||
}
|
||||
|
||||
void OnRegister()
|
||||
{
|
||||
if (_authInProgress) return;
|
||||
|
||||
string username = usernameInputRegister.text;
|
||||
string password = passwordInputRegister.text;
|
||||
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
|
||||
{
|
||||
error_txt.text = "Please fill in all fields";
|
||||
return;
|
||||
}
|
||||
|
||||
if (username.Length < MIN_USERNAME_LENGTH || username.Length > MAX_USERNAME_LENGTH)
|
||||
{
|
||||
error_txt.text = "Username must be between " + MIN_USERNAME_LENGTH + " and " + MAX_USERNAME_LENGTH + " characters";
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.Length < MIN_PASSWORD_LENGTH || password.Length > MAX_PASSWORD_LENGTH)
|
||||
{
|
||||
error_txt.text = "Password must be between " + MIN_PASSWORD_LENGTH + " and " + MAX_PASSWORD_LENGTH + " characters";
|
||||
return;
|
||||
}
|
||||
|
||||
// Server register endpoint accepts username + password only (email field is optional UI-only).
|
||||
string json = "{\"username\":\"" + EscapeJsonString(username) + "\",\"password\":\"" + EscapeJsonString(password) + "\"}";
|
||||
StartCoroutine(AuthPostCoroutine(AuthBaseUrl + "/auth/register", json, "Account created."));
|
||||
}
|
||||
|
||||
static string EscapeJsonString(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s)) return s;
|
||||
return s.Replace("\\", "\\\\").Replace("\"", "\\\"");
|
||||
}
|
||||
|
||||
IEnumerator AuthPostCoroutine(string url, string jsonBody, string successMessage)
|
||||
{
|
||||
SetBusy(true);
|
||||
error_txt.text = "";
|
||||
|
||||
using (var request = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST))
|
||||
{
|
||||
byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonBody);
|
||||
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
|
||||
request.downloadHandler = new DownloadHandlerBuffer();
|
||||
request.SetRequestHeader("Content-Type", "application/json");
|
||||
|
||||
yield return request.SendWebRequest();
|
||||
|
||||
string text = request.downloadHandler != null ? request.downloadHandler.text : "";
|
||||
|
||||
if (request.result != UnityWebRequest.Result.Success &&
|
||||
request.result != UnityWebRequest.Result.ProtocolError)
|
||||
{
|
||||
error_txt.text = string.IsNullOrEmpty(request.error) ? "Network error" : request.error;
|
||||
SetBusy(false);
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
error_txt.text = "Empty response from server";
|
||||
SetBusy(false);
|
||||
yield break;
|
||||
}
|
||||
|
||||
AuthApiResponse resp = JsonUtility.FromJson<AuthApiResponse>(text);
|
||||
|
||||
if (resp.ok && !string.IsNullOrEmpty(resp.token))
|
||||
{
|
||||
AuthToken = resp.token;
|
||||
PlayerPrefs.SetString(PlayerPrefsAuthKey, resp.token);
|
||||
PlayerPrefs.Save();
|
||||
|
||||
yield return StartCoroutine(FetchUserDataCoroutine(null, true));
|
||||
ProceedToMainMenu();
|
||||
}
|
||||
else
|
||||
{
|
||||
error_txt.text = string.IsNullOrEmpty(resp.error) ? "Request failed" : resp.error;
|
||||
}
|
||||
}
|
||||
|
||||
SetBusy(false);
|
||||
}
|
||||
|
||||
static void ApplyUserData(UserData u)
|
||||
{
|
||||
_currentUser = u;
|
||||
OnUserDataUpdated?.Invoke(u);
|
||||
}
|
||||
|
||||
void ScheduleUserDataRefreshOnRead()
|
||||
{
|
||||
if (string.IsNullOrEmpty(AuthToken)) return;
|
||||
if (_userDataReadRefreshPending) return;
|
||||
_userDataReadRefreshPending = true;
|
||||
StartCoroutine(UserDataReadRefreshCoroutine());
|
||||
}
|
||||
|
||||
IEnumerator UserDataReadRefreshCoroutine()
|
||||
{
|
||||
try
|
||||
{
|
||||
yield return StartCoroutine(FetchUserDataCoroutine(null, true));
|
||||
}
|
||||
finally
|
||||
{
|
||||
_userDataReadRefreshPending = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>GET /auth/user; updates <see cref="CurrentUser"/> when successful. Callback (success, errorOrNull, userOrNull).</summary>
|
||||
public void GetUserData(Action<bool, string, UserData> onComplete)
|
||||
{
|
||||
StartCoroutine(FetchUserDataCoroutine(onComplete, true));
|
||||
}
|
||||
|
||||
/// <summary>GET /auth/rc-packs (no auth). Callback (success, errorOrNull, jsonOrNull).</summary>
|
||||
public void GetRcPacks(Action<bool, string, string> onComplete)
|
||||
{
|
||||
StartCoroutine(GetRcPacksCoroutine(onComplete));
|
||||
}
|
||||
|
||||
IEnumerator GetRcPacksCoroutine(Action<bool, string, string> onComplete)
|
||||
{
|
||||
string url = AuthBaseUrl + "/auth/rc-packs";
|
||||
using (var request = UnityWebRequest.Get(url))
|
||||
{
|
||||
request.downloadHandler = new DownloadHandlerBuffer();
|
||||
|
||||
yield return request.SendWebRequest();
|
||||
|
||||
string text = request.downloadHandler != null ? request.downloadHandler.text : "";
|
||||
|
||||
if (request.result != UnityWebRequest.Result.Success &&
|
||||
request.result != UnityWebRequest.Result.ProtocolError)
|
||||
{
|
||||
onComplete?.Invoke(false, string.IsNullOrEmpty(request.error) ? "Network error" : request.error, null);
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (request.responseCode < 200 || request.responseCode >= 300)
|
||||
{
|
||||
onComplete?.Invoke(false, string.IsNullOrEmpty(text) ? "Request failed (" + request.responseCode + ")" : text, null);
|
||||
yield break;
|
||||
}
|
||||
|
||||
onComplete?.Invoke(true, null, text);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>POST /auth/purchase-rc with <c>{"pack":"usd_5"|...}</c>. Refreshes profile on success. Callback (success, errorOrNull).</summary>
|
||||
public void PurchaseRcPack(string packId, Action<bool, string> onComplete)
|
||||
{
|
||||
StartCoroutine(PurchaseRcCoroutine(packId, onComplete));
|
||||
}
|
||||
|
||||
IEnumerator PurchaseRcCoroutine(string packId, Action<bool, string> onComplete)
|
||||
{
|
||||
if (string.IsNullOrEmpty(AuthToken))
|
||||
{
|
||||
onComplete?.Invoke(false, "Not signed in");
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (!RcPack.IsValid(packId))
|
||||
{
|
||||
onComplete?.Invoke(false, "Invalid pack (use " + RcPack.Usd5 + ", " + RcPack.Usd20 + ", or " + RcPack.Usd50 + ")");
|
||||
yield break;
|
||||
}
|
||||
|
||||
string json = "{\"pack\":\"" + EscapeJsonString(packId) + "\"}";
|
||||
string url = AuthBaseUrl + "/auth/purchase-rc";
|
||||
|
||||
using (var request = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST))
|
||||
{
|
||||
byte[] bodyRaw = Encoding.UTF8.GetBytes(json);
|
||||
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
|
||||
request.downloadHandler = new DownloadHandlerBuffer();
|
||||
request.SetRequestHeader("Content-Type", "application/json");
|
||||
request.SetRequestHeader("Authorization", "Bearer " + AuthToken);
|
||||
|
||||
yield return request.SendWebRequest();
|
||||
|
||||
string text = request.downloadHandler != null ? request.downloadHandler.text : "";
|
||||
|
||||
if (request.result != UnityWebRequest.Result.Success &&
|
||||
request.result != UnityWebRequest.Result.ProtocolError)
|
||||
{
|
||||
onComplete?.Invoke(false, string.IsNullOrEmpty(request.error) ? "Network error" : request.error);
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (request.responseCode < 200 || request.responseCode >= 300)
|
||||
{
|
||||
onComplete?.Invoke(false, string.IsNullOrEmpty(text) ? "Request failed (" + request.responseCode + ")" : text);
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
onComplete?.Invoke(false, "Empty response from server");
|
||||
yield break;
|
||||
}
|
||||
|
||||
PurchaseRcApiResponse resp = JsonUtility.FromJson<PurchaseRcApiResponse>(text);
|
||||
|
||||
if (resp != null && resp.ok)
|
||||
{
|
||||
bool refreshOk = false;
|
||||
string refreshErr = null;
|
||||
yield return StartCoroutine(FetchUserDataCoroutine((ok, err, u) =>
|
||||
{
|
||||
refreshOk = ok;
|
||||
refreshErr = err;
|
||||
}, true));
|
||||
|
||||
if (refreshOk)
|
||||
onComplete?.Invoke(true, null);
|
||||
else
|
||||
onComplete?.Invoke(false, string.IsNullOrEmpty(refreshErr) ? "Purchase ok but profile refresh failed" : refreshErr);
|
||||
}
|
||||
else
|
||||
{
|
||||
string err = resp != null && !string.IsNullOrEmpty(resp.error) ? resp.error : "Purchase failed";
|
||||
onComplete?.Invoke(false, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator FetchUserDataCoroutine(Action<bool, string, UserData> onComplete, bool applyToStatic)
|
||||
{
|
||||
if (string.IsNullOrEmpty(AuthToken))
|
||||
{
|
||||
onComplete?.Invoke(false, "Not signed in", null);
|
||||
yield break;
|
||||
}
|
||||
|
||||
string url = AuthBaseUrl + "/auth/user";
|
||||
using (var request = UnityWebRequest.Get(url))
|
||||
{
|
||||
request.downloadHandler = new DownloadHandlerBuffer();
|
||||
request.SetRequestHeader("Authorization", "Bearer " + AuthToken);
|
||||
|
||||
yield return request.SendWebRequest();
|
||||
|
||||
string text = request.downloadHandler != null ? request.downloadHandler.text : "";
|
||||
|
||||
if (request.result != UnityWebRequest.Result.Success &&
|
||||
request.result != UnityWebRequest.Result.ProtocolError)
|
||||
{
|
||||
onComplete?.Invoke(false, string.IsNullOrEmpty(request.error) ? "Network error" : request.error, null);
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (request.responseCode < 200 || request.responseCode >= 300)
|
||||
{
|
||||
onComplete?.Invoke(false, string.IsNullOrEmpty(text) ? "Request failed (" + request.responseCode + ")" : text, null);
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
onComplete?.Invoke(false, "Empty response from server", null);
|
||||
yield break;
|
||||
}
|
||||
|
||||
AuthUserApiResponse resp = JsonUtility.FromJson<AuthUserApiResponse>(text);
|
||||
|
||||
if (resp != null && resp.ok && resp.user != null)
|
||||
{
|
||||
if (applyToStatic)
|
||||
ApplyUserData(resp.user);
|
||||
onComplete?.Invoke(true, null, resp.user);
|
||||
}
|
||||
else
|
||||
{
|
||||
string err = resp != null && !string.IsNullOrEmpty(resp.error) ? resp.error : "Request failed";
|
||||
onComplete?.Invoke(false, err, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class UserData
|
||||
{
|
||||
public int id;
|
||||
public string username;
|
||||
public int cc;
|
||||
public int rc;
|
||||
public string created_at;
|
||||
public string last_logged_at;
|
||||
}
|
||||
|
||||
/// <summary>Typical <c>pack</c> ids for <see cref="LoginManager.PurchaseRcPack"/>; prefer <see cref="LoginManager.GetRcPacks"/> for the live list.</summary>
|
||||
public static class RcPack
|
||||
{
|
||||
public const string Usd5 = "usd_5";
|
||||
public const string Usd20 = "usd_20";
|
||||
public const string Usd50 = "usd_50";
|
||||
|
||||
public static bool IsValid(string packId)
|
||||
{
|
||||
return packId == Usd5 || packId == Usd20 || packId == Usd50;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CoinHelper{
|
||||
public static float Format(int coins){
|
||||
int whole = coins / 4;
|
||||
int fraction = coins % 4;
|
||||
return float.Parse(whole + "." + fraction);
|
||||
}
|
||||
|
||||
public static string FormatString(int coins){
|
||||
return Format(coins).ToString("N2");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class MainMenuManager : MonoBehaviour
|
||||
{
|
||||
[Header("Stats")]
|
||||
[SerializeField] private GameObject statsPanel;
|
||||
[SerializeField] private TMP_Text usernameText;
|
||||
[SerializeField] private TMP_Text ccText;
|
||||
[SerializeField] private TMP_Text rcText;
|
||||
|
||||
[Header("Screens")]
|
||||
public GameObject mainMenuScreen;
|
||||
public GameObject gameModesScreen;
|
||||
public GameObject dummyBuyScreen;
|
||||
|
||||
[Header("Dummy Buy")]
|
||||
public Button btnBuyUsd5;
|
||||
public Button btnBuyUsd20;
|
||||
public Button btnBuyUsd50;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if(LoginManager.instance==null){
|
||||
SceneManager.LoadScene(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
LoginManager.OnUserDataUpdated += OnUserUpdated;
|
||||
|
||||
usernameText.text = "";
|
||||
ccText.text = "";
|
||||
rcText.text = "";
|
||||
LoginManager.instance.GetUserData((success, error, user) => {
|
||||
if(success){
|
||||
OnUserUpdated(user);
|
||||
}
|
||||
});
|
||||
|
||||
btnBuyUsd5.onClick.AddListener(() => OnBuy(RcPack.Usd5));
|
||||
btnBuyUsd20.onClick.AddListener(() => OnBuy(RcPack.Usd20));
|
||||
btnBuyUsd50.onClick.AddListener(() => OnBuy(RcPack.Usd50));
|
||||
|
||||
}
|
||||
|
||||
void OnBuy(string packId){
|
||||
LoginManager.instance.PurchaseRcPack(packId, (success, error) => {
|
||||
if(success){
|
||||
OnUserUpdated(LoginManager.CurrentUser);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
LoginManager.OnUserDataUpdated -= OnUserUpdated;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void OnUserUpdated(UserData user){
|
||||
usernameText.text = user.username;
|
||||
ccText.text = CoinHelper.FormatString(user.cc) + " CC";
|
||||
rcText.text = CoinHelper.FormatString(user.rc) + " RC";
|
||||
}
|
||||
|
||||
|
||||
public void ShowMainMenuScreen(){
|
||||
statsPanel.SetActive(true);
|
||||
mainMenuScreen.SetActive(true);
|
||||
gameModesScreen.SetActive(false);
|
||||
dummyBuyScreen.SetActive(false);
|
||||
}
|
||||
|
||||
public void ShowGameModesScreen(){
|
||||
statsPanel.SetActive(true);
|
||||
mainMenuScreen.SetActive(false);
|
||||
gameModesScreen.SetActive(true);
|
||||
dummyBuyScreen.SetActive(false);
|
||||
}
|
||||
|
||||
public void ShowDummyBuyScreen(){
|
||||
statsPanel.SetActive(false);
|
||||
mainMenuScreen.SetActive(false);
|
||||
gameModesScreen.SetActive(false);
|
||||
dummyBuyScreen.SetActive(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d216f08d4b95494ba7875cca68b440a
|
||||
@@ -0,0 +1,45 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class TabGroup : MonoBehaviour
|
||||
{
|
||||
public Button[] buttons;
|
||||
public GameObject[] contents;
|
||||
public int selectedIndex = 0;
|
||||
|
||||
|
||||
void OnValidate(){
|
||||
if(buttons == null || buttons.Length == 0){
|
||||
buttons=GetComponentsInChildren<Button>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Awake()
|
||||
{
|
||||
SetSelectedIndex(selectedIndex);
|
||||
|
||||
for(int i=0; i < buttons.Length; i++)
|
||||
{
|
||||
int index = i;
|
||||
buttons[i].onClick.AddListener(() => SetSelectedIndex(index));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SetSelectedIndex(int index)
|
||||
{
|
||||
if(index < 0 || index >= buttons.Length) return;
|
||||
|
||||
selectedIndex = index;
|
||||
for(int i = 0; i < buttons.Length; i++)
|
||||
{
|
||||
buttons[i].targetGraphic.color = i == index ? buttons[i].colors.normalColor : buttons[i].colors.disabledColor;
|
||||
try{
|
||||
contents[i].SetActive(i == index);
|
||||
}catch{
|
||||
Debug.LogError("Content not found for index: " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d961ea20492fa0f448fbedacd3495911
|
||||
Reference in New Issue
Block a user