i'm currently working on a Unity project in which i need to update 8 Slider values from a JSON file. I tested the loading part and everything works but when i apply the values to the sliders, they dont behave like i thought they would.
I have a OnButton function that: 1. Triggers JSON Loading -> 2. Passes the loaded JSON values to static variables -> 3. Calls a function to update the sliders.
Now here is the problem: On Button press, only one slider at a time gets updated, top to bottom and I do not understand why. So in order for every time you load a json file, you have to press the LOAD button up to 8 times, before every slider is updated. I use the same LoadSliders function for when the UI loads and it works there.
Thanks for your help!
using UnityEngine;
using UnityEngine.UI;
.
.
.
public void UpdateSettings(BoidPresetSaveData loadedSave)
{
maxSpeed = loadedSave.maxSpeed;
maxForce = loadedSave.maxForce;
arriveRadius = loadedSave.arriveRadius;
desiredSeparation = loadedSave.desiredSeparation;
neighbourDistance = loadedSave.neighbourDistance;
//Weights
separation = loadedSave.separation;
alignment = loadedSave.alignment;
cohesion = loadedSave.cohesion;
wander = loadedSave.wander;
avoidWalls = loadedSave.avoidWalls;
}
public void LoadSliders()
{
maxSpeedSlider.value = maxSpeed;
maxForceSlider.value = maxForce;
arriveRadiusSlider.value = arriveRadius;
desiredSeperationSlider.value = desiredSeparation;
neighbourDistanceSlider.value = neighbourDistance;
separationSlider.value = separation;
alignmentSlider.value = alignment;
cohesionSlider.value = cohesion;
wanderSlider.value = wander;
avoidWallsSlider.value = avoidWalls;
}
And the OnButton function isnt very fancy either:
public void LoadPreset()
{
var loadKey = presetDropdown.captionText.text;
if (!SaveManager.SaveExists(loadKey,folderKey))
{
Debug.Log("Preset file does not exist.");
return;
}
BoidPresetSaveData loadedSave = SaveManager.Load<BoidPresetSaveData>(loadKey, folderKey);
BoidSettings.instance.UpdateSettings(loadedSave);
BoidSettings.instance.LoadSliders();
}
Ok, i found out, that the slider.value call also invokes the OnSliderChange event. With this in mind, the code above is not functional because you created a kind of a loop there.
Also I lied that this works on Gui load, i just did not test enough.
I had to split up the UpdateSettings function, so that every slider gets its own OnSliderChange method. So the functional code looks like this:
public void UpdateMaxSpeed()
{
maxSpeed = maxSpeedSlider.value;
}
public void UpdateMaxForce()
{
maxForce = maxForceSlider.value;
}
public void UpdateArriveRadius()
{
arriveRadius = arriveRadiusSlider.value;
}public void UpdateDesiredSeparation()
{
desiredSeparation = desiredSeperationSlider.value;
}
public void UpdateNeighbourDistance()
{
neighbourDistance = neighbourDistanceSlider.value;
}
public void UpdateSeparation()
{
separation = separationSlider.value;
}
public void UpdateAlignment()
{
alignment = alignmentSlider.value;
}
public void UpdateCohesion()
{
cohesion = cohesionSlider.value;
}
public void UpdateWander()
{
wander = wanderSlider.value;
}
public void UpdateAvoidWalls()
{
avoidWalls = avoidWallsSlider.value;
}
There may be a cleaner method for this, but I do not know enough about C# and Unity to give an educated guess about this.
Related
I'm creating a calculator in Unity and faced with a problem.So I need to change bool value to write second number of my calculator.
My script attached to all the buttons(GameObjects) in the scene.
I need to change this value to true to write second number of calculator.
private bool input_second_num;
public void Input(){
if (calculate_label.text.Length < 15 && !input_second_num)
{
calculate_label.text += btnNumber;
first_num = long.Parse(calculate_label.text);
}
esle if (calculate_label.text.Length < 15 && input_second_num)
{
calculate_label.text += btnNumber;
second_num = long.Parse(calculate_label.text);
}
}
//Calls when clicking on action button
public void Action()
{
input_second_num = true;
calculate_label.text = " ";
}
At first input_second_num is false to write first number at first.When I'm changing input_second_num to true in another function clicking on action button and then trying to input second num, input_second_num is anyways false and I'm typing number for first_number.
Why is it so happening?
It's difficult to answer with the code posted and my initial observations require more than will fit into a comment.
You have posted two functions with the same signature public void Input(). I can't see how this code builds without issues; I must therefore assume that they are declared in different class types.
This function is incorrect:
public void Input()
{
else if (calculate_label.text.Length < 15 && input_second_num)
{
calculate_label.text += btnNumber;
second_num = long.Parse(calculate_label.text);
print("Second: " + second_num);
}
}
You're starting an if block statement with an else - is there code missing?
You state that you declared input_second_num as
private static input_second_num;
There is no data type assigned again I can't see how your code builds without issues.
Please revisit your question and show us more of your class code.
I am trying to configure this type of game where I have 6 players connected to the same room. On game start, the Master Client (first player turn) starts where the UI button should be enabled only to him and it should be disabled to all other players and after the first player click the button it will get disabled and for the 2nd player alone it should be enabled and so on to all other players.
So i have this idea where a loop should iterate through the list of players when a button is clicked by the first or master client then getNext() that is the next player as per the actor number. The problem is how do i put in code?
I was also recommended to use Custom properties but it has been a huge problem to me since i don't understand them. Watched some of the tutorials and also some documentation but I seem not to understand.
I am currently not using photonview component.
let me just write a short code of what i mean;
public class GameManager : MonoBehaviourPunCallbacks
{
private ExitGames.Client.Photon.Hashtable _myCustomProperties = new ExitGames.Client.Photon.Hashtable();
private void Start()
{
//onstart the master client should only be the one t view the button and click it
//his name should be displayed when it his turn
if (PhotonNetwork.IsMasterClient)
{
Player_Name.text = PhotonNetwork.MasterClient.NickName + " " + "it's your turn";
button.SetActive(true);
}
}
//onclcik the Button
public void TurnButton()
{
for(int i = 0; i<PhotonNetwork.Playerlist.length; i++)
{
//so every click of the button a loop should iterate and check the player if is the next to see the button and click it
//a name should also be displayed on his turn as per his nickname
}
}
}
There is no need for custom player properties here.
I would rather use room properties for that
public class GameManager : MonoBehaviourPunCallbacks
{
private const string ACTIVE_PLAYER_KEY = "ActivePlayer";
private const string ACTIVE_ME_FORMAT = "{0}, you it's your turn!!";
private const string ACTIVE_OTHER_FORMAT = "Please wait, it's {0}'s turn ...";
private Room room;
[SerializeField] private Button button;
[SerializeField] private Text Player_Name;
#region MonoBehaviourPunCallbacks
private void Awake()
{
button.onClick.AddListener(TurnButton):
button.gameObject.SetActive(false);
Player_Name.text = "Connecting ...";
// Store the current room
room = PhotonNetwork.CurrentRoom;
if (PhotonNetwork.IsMasterClient)
{
// As master go active since usually this means you are the first player in this room
// Get your own ID
var myId = PhotonNetwork.LocalPlayer.ActorNumber;
// and se it to active
SetActivePlayer(myId);
}
else
{
// Otherwise fetch the active player from the room properties
OnRoomPropertiesUpdate(room.CustomProperties);
}
}
// listen to changed room properties - this is always called if someone used "SetCustomProperties" for this room
// This is basically the RECEIVER and counter part to SetActivePlayer below
public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
{
// Maybe another property was changed but not the one we are interested in
if(!propertiesThatChanged.TryGetValue(ACTIVE_PLAYER_KEY, out var newActiveID)) return;
// if we got a value but it's not an int something is wrong in general
if(!(newActiveID is int newActvieIDValue))
{
Debug.LogError("For some reason \"ACTIVE_PLAYER_KEY\" is not an int!?");
return;
}
// otherwise apply the ID
ApplyActivePlayer(newActvieIDValue);
}
// Optional but might be important (?)
// In the rare case that the currently active player suddenly leaves for whatever reason
// as the master client you might want to handle this and go to the next player then
//public override void OnPlayerLeftRoom (Player otherPlayer)
//{
// if(!PhotonNetwork.IsMasterClient) return;
//
// if(!propertiesThatChanged.TryGetValue(ACTIVE_PLAYER_KEY, out var currentActiveID) && currentActiveID is int currentActiveIDValue) return;
//
// if(currentActiveIDValue != otherPlayer.ActorNumber) return;
//
// var nextPlayer = Player.GetNextFor(currentActiveIDValue);
// var nextPlayerID = nextPlayer.ActorNumber;
// SetActivePlayer(nextPlayerID);
//}
#endregion MonoBehaviourPunCallbacks
// Called via onClick
private void TurnButton()
{
// this gets the next player after you sorted by the actor number (=> order they joined the room)
// wraps around at the end
var nextPlayer = Player.GetNext();
// Get the id
var nextPlayerID = nextPlayer.ActorNumber;
// and tell everyone via the room properties that this is the new active player
SetActivePlayer(nextPlayerID);
}
// This writes the new active player ID into the room properties
// You can see this as kind of SENDER since the room properties will be updated for everyone
private void SetActivePlayer(int id)
{
var hash = new ExitGames.Client.Photon.Hashtable();
hash[ACTIVE_PLAYER_KEY] = id;
room.SetCustomProperties(hash);
}
// this applies all local changes according to the active player
private void ApplyActivePlayer(int id)
{
// get the according player
var activePlayer = Player.Get(id);
// Am I this player?
var iAmActive = PhotonNetwork.LocalPlayer.ActorNumber == id;
// Set the button active/inactive accordingly
button.gameObject.SetActive(iAmActive);
// Set the text accordingly
Player_Name.text = string.Format(iAmActive ? ACTIVE_ME_FORMAT : ACTIVE_OTHER_FORMAT, activePlayer.NickName):
}
}
I've set up a very simple Editor script in Unity 2020.2.1f1 that, upon pressing an Inspector button, should change the value of a specified parameter to a value set in the code.
public override void OnInspectorGUI()
{
DrawDefaultInspector();
StateObject s = (StateObject)target;
if (s.objID == 0)
{
if (GUILayout.Button("Generate Object ID"))
{
GenerateID(s);
}
}
}
public void GenerateID(StateObject s)
{
s.objID = DateTimeOffset.Now.ToUnixTimeSeconds();
}
This all works like it's supposed to. I press the button, the correct number appears in the field, and I'm happy. However, once I switch to Play mode, the value resets to the prefab default and remains that way even when I switch Play mode off.
Am I missing some ApplyChange function or something?
(EDIT: This works, but isn't as good as the accepted answer.)
Well, yes, I am in fact missing some sort of ApplyChange function.
I don't know how I missed it, but I was looking for this:
EditorUtility.SetDirty(target);
So, in my script, I would just edit the GenerateID function:
public void GenerateID(StateObject s)
{
s.objID = DateTimeOffset.Now.ToUnixTimeSeconds();
EditorUtility.SetDirty(s);
}
And I am posting it here in case anyone runs into the same issue, that way they hopefully won't have to spend as much time looking for a solution before being reminded that SetDirty is a thing.
In my eyes better than mixing in direct accesses from Editor scripts and then manually mark things dirty rather go through SerializedProperty and let the Inspector handle it all (also the marking dirty and saving changes, handle undo/redo etc)
SerializedProperty id;
private void OnEnable()
{
id = serializedObject.FindProperty("objID");
}
public override void OnInspectorGUI()
{
DrawDefaultInspector();
// Loads the actual values into the serialized properties
// See https://docs.unity3d.com/ScriptReference/SerializedObject.Update.html
serializedObject.Update();
if (id.intValue == 0)
{
if (GUILayout.Button("Generate Object ID"))
{
id.intValue = DateTimeOffset.Now.ToUnixTimeSeconds();
}
}
// Writes back modified properties into the actual class
// Handles all marking dirty, undo/redo, etc
// See https://docs.unity3d.com/ScriptReference/SerializedObject.ApplyModifiedProperties.html
serializedObject.ApplyModifiedProperties();
}
I have an object with a script that moves it along a path. On the same object is a script that, if activated, sends it back to its start point. The mover script is default active and the home is by default inactive. I want it so that if I press "2", mover deactivates and home activates, and if I press "1", the scripts go back to how they were. states 1 & 2 should be exclusive. I have created a script, on the same object, as follows:
public class activator : MonoBehaviour
{
bool mover = new bool();
bool home = new bool();
void Start ()
{
mover = true;
home = false;
}
void Update ()
{
if (Input.GetButtonDown("1"))
{
mover = true;
home = false;
}
if (Input.GetButtonDown("2"))
{
mover = false;
home = true;
}
if(mover == true)
{
GetComponent<router>().enabled = true;
GetComponent<routeRepairs>().enabled = false;
}
else if(home == true)
{
GetComponent<router>().enabled = false;
GetComponent<routeRepairs>().enabled = true;
}
}
}
note the actual scripts I'm trying to activate and deactivate from the object are router and routeRepairs. When I actually run the game in playmode nothing happens after the button presses.
There is a question that stackoverflow is telling me is similar but the solutions given aren't doing anything for me. So, any help with how to get this working would be greatly appreciated! Thanks in advance!
one more thing: I hope to add more movement scripts that should be activated and deactivated in the same way, so solutions that only apply to two states (ie moving or home) aren't ideal. probably not important but it just occurred to me that it was worth qualifying..?
Are the inputs actually recognized? Put a print inside the input if to see if it actually gets the input. If not, maybe your input is not configured correctly. Or you can try using KeyCode instead like:
if (Input.GetKeyDown(KeyCode.Alpha1))
Also, you don't need the extra booleans or the extra if statements. Just get the scripts in start and then directly enable/disable them
router router;
routerRepairs routerRepairs;
void Start ()
{
router = GetComponent<router>();
routerRepairs = GetComponent<routerRepairs>();
}
void Update ()
{
if (Input.GetKeyDown(KeyCde.Alpha1))
{
router.enabled = true;
routerRepairs.enabled = false;
}
if (Input.GetKeyDown(KeyCde.Alpha2))
{
router.enabled = false;
routerRepairs.enabled = true;
}
}
As you most probably know, Unity3D have terrible buil-in input system what is unable to change configuration runtime so i decised to write own input system based on SharpDX DirectInput. I know well directInput is not officialy recomendet but i like it for its ability to work with device of all kinds (Like Trust dual stick gamepad GTX 28 of mine. Originaly purchased for PSX emulation).
I using class below to representate button object
public class InputButton
{
public JoystickOffset button;
public Key key;
public int pressValue;
public int relaseValue;
public bool isJoystick;
public InputButton(JoystickOffset button, int pressValue, int relaseValue)
{
this.button = button;
this.pressValue = pressValue;
this.relaseValue = relaseValue;
isJoystick = true;
}
public InputButton(Key key, int pressValue, int relaseValue)
{
this.key = key;
this.pressValue = pressValue;
this.relaseValue = relaseValue;
isJoystick = false;
}
}
Then i replace Unity's (pretty terrible method by the way) Input.GetKeyDown with my own (If you name class same as one of unity's classes you replace it. I know someone must not like use of static here but i see it very benefical)
public static bool GetKeyDown(InputButton button)
{
bool pressed = false;
keyboard.Poll();
keyboardData = keyboard.GetBufferedData();
if (button.isJoystick == false)
{
foreach (var state in keyboardData)
{
if (state.Key == button.key && state.Value == button.pressValue)
{
pressed = true;
}
}
}
return pressed;
}
But before everything i call Input.Initialize() from another class (during Awake()). it looks like this :
public static void Initialize()
{
directInput = new DirectInput();
var joystickGuid = Guid.Empty;
foreach (var deviceInstance in directInput.GetDevices(SharpDX.DirectInput.DeviceType.Joystick, DeviceEnumerationFlags.AttachedOnly))
{
joystickGuid = deviceInstance.InstanceGuid;
}
if (joystickGuid == Guid.Empty)
{
foreach (var deviceInstance in directInput.GetDevices(SharpDX.DirectInput.DeviceType.Gamepad, DeviceEnumerationFlags.AttachedOnly))
{
joystickGuid = deviceInstance.InstanceGuid;
}
}
if (joystickGuid != Guid.Empty)
{
joystick = new Joystick(directInput, joystickGuid);
joystick.Properties.BufferSize = 128;
joystick.Acquire();
}
keyboard = new Keyboard(directInput);
keyboard.Properties.BufferSize = 128;
keyboard.Acquire();
}
Now to the problem. When i click to anything outside game window in the editor, keys does not respond anymore. I checked everything and both directInput and keyboard are still in variables. Most likely some problem with "Focus" of window because this problem looks like directInput instance or keyboard gets disconnected as soon as game window lost focus (focus is lost when window is not active window, active window is not "active" but so called "focused").
Do someone know why this happenig and how to repair it ?
EDIT : Looks like this problem is somehow connected to window(s). I have settings and i'm able to switch fullscreen runtime. As long as i'm in fullscreen it works fine but when i switch to window it stop working.
Thanks.
-Garrom
Now i see myself as very stupid person... Anyway i was right abou window focus. When game window lost focus it (somehow) break directInput. I solved this useing unity's callback OnApplicationFocus and re-Initialize (call Initialize(). See original question) every time game window gets focused.