I'm facing a really weird issue with the pause menu.
Whenever I pause and then unpause and pause again, the buttons lose their focus.
The first time I pause:
Second time I pause:
Only the first time is working as expected, all pauses after that are like the second image(no button highlighted). I couldn't figure out the reason.
Here is my code:
void Update()
{
var gamepad = Gamepad.current;
var keyboard = Keyboard.current;
if (gamepad == null && keyboard == null)
return; // No gamepad connected.
if ((gamepad != null && gamepad.startButton.wasPressedThisFrame) || (keyboard !=null && keyboard.pKey.wasPressedThisFrame))
{
if (GameIsPaused)
{
Resume();
}
else
{
Pause();
}
}
}
public void Resume()
{
player.gameObject.GetComponent<MyPlayerMovement>().enabled = true;
pauseMenuUI.SetActive(false);
Time.timeScale = 1f;
GameIsPaused = false;
// GameObject.Find("ThePlayer").GetComponent<MyPlayerMovement>().enabled = false;
// GameObject.Find("ThePlayer").GetComponent<InteractIcons>().enabled = false;
}
private void Pause()
{
player.gameObject.GetComponent<MyPlayerMovement>().enabled = false;
pauseMenuUI.SetActive(true);
resumeBtn.Select();
Time.timeScale = 0f;
GameIsPaused = true;
// GameObject.Find("ThePlayer").GetComponent<MyPlayerMovement>().enabled = true;
// GameObject.Find("ThePlayer").GetComponent<InteractIcons>().enabled = true;
}
I tried assigning the button in the inspector to a variable and then added this variable like so resumeBtn.Select(); in Pause() but it changed nothing.
Note that when the buttons are not highlighted, they get highlighted only after I press the arrows up or down or move the gamepad's analogue stick up or down. but at first, they are not highlighted. How can I fix this?
In your event system you specified first selected to you resume button, however that seems to be not enough.
I'm not really sure how it works (this paragraph may be absolute bs), but after empirical research I think that event system sets its current selected item to the first selected reference during its awake or start. On disable, it seems to clear its current selected, but doesn't set it again on its enable.
One way to tackle this problem is to manually set current selected item when bringing up pause menu: eventSystem.SetSelectedGameObject(resumeButtonGameObject); where eventSystem is obviousely of EventSystem type.
Related
I have this scenario:
The first user that joins a lobby will have an active button on his screen. After some actions, if the player hit the button, it will disable, and then the next player in the room will have this button active, and so on.
Based on a property 'Turn' I want to change this button state like this.
In this function PassTurn I first set for the LocalPlayer the Turn property to false and then I determine the next player using some logic, and set for that player the Turn property to true.
private PassTurn()
{
PunHashtable _myCustomProperties_forCurrentPlayer = new PunHashtable();
_myCustomProperties_forCurrentPlayer["Turn"] = false;
PhotonNetwork.LocalPlayer.SetCustomProperties(_myCustomProperties_forCurrentPlayer);
foreach (Player player in PhotonNetwork.PlayerList)
{
// ... some logic to determine the next player to set the 'Turn' property to true
if (someCondition for player) {
PunHashtable _myCustomProperties_forNextPlayer = new PunHashtable();
_myCustomProperties_forNextPlayer["Turn"] = true;
player.SetCustomProperties(_myCustomProperties_forNextPlayer);
}
}
}
In OnPlayerPropertiesUpdate function, if Turn property ever change, activate or deactivate the button based on Turn property value (if true - show the button, if false don't display the button).
public override void OnPlayerPropertiesUpdate(Player targetPlayer, ExitGames.Client.Photon.Hashtable changedProps)
{
base.OnPlayerPropertiesUpdate(targetPlayer, changedProps);
if (targetPlayer != null) {
if (changedProps.ContainsKey("Turn"))
{
{
foreach (Player player in PhotonNetwork.PlayerList)
{
// this print will display (1, false) and (2, false) which is not correct, because the second player doesn't have de property changed
print(player.ActorNumber + player.CustomProperties["Turn"];
if ((bool)player.CustomProperties["Turn"] == true)
{
print("HEY HEY HEY 1");
endTurnBtn.SetActive(true);
}
if ((bool)player.CustomProperties["Turn"] == false)
{
print("HEY HEY HEY 2");
endTurnBtn.SetActive(false);
}
}
}
}
}
}
This is not working properly since it will always enter on HEY HEY HEY 2., the button for the current play will disappear, but it will never appear on the next player.
Which is the right approach for this situation? How can I change ui components on other players screen? Thank you for your time!
LaterEdit based on accepted comment:
public override void OnPlayerPropertiesUpdate(Player targetPlayer, ExitGames.Client.Photon.Hashtable changedProps)
{
base.OnPlayerPropertiesUpdate(targetPlayer, changedProps);
if (targetPlayer != null) {
if (changedProps.ContainsKey("Turn"))
{
{
if ((bool)PhotonNetwork.LocalPlayer.CustomProperties["Turn"] == true)
{
print("HEY HEY HEY 1");
endTurnBtn.SetActive(true);
}
if ((bool)PhotonNetwork.LocalPlayer.CustomProperties["Turn"] == false)
{
print("HEY HEY HEY 2");
endTurnBtn.SetActive(false);
}
}
}
}
}
you iterate over every player and check the variable, so as soon as the last player in your list has the turn property false every player will disable the button, while when the last players turn property is true every player will activate the button.
Either way it makes no sense to iterate over every player in the room, since you only want to change the locally shown button. Therefore you should only check the local player/players and change the button accordingly.
Imagine some standard Unity UI ScrollView. You grab it with your mouse and start dragging it so it is scrolling with your mouse. How do I programmatically make it stop scrolling while mouse button is still down? Is there any way to make ScrollRect think that user is released mouse button?
Quite old question, but I found exactly this same problem and no clean solution. My problem was to have scrollRect with items which I can scroll left/right but when user select one item and drag it up then scrollRect should cancel scrolling and allow user to drag item up. I achieved this by temporary setting ScrollRect.enable to false, and after few ms set it back to true.
Here is part of mu code which do this. Maybe somebody find this useful.
void Update()
{
if (state == DragState.Started) {
dragStart = Input.mousePosition;
state = DragState.Continued;
}
if (state == DragState.Continued) {
Vector3 pos = Input.mousePosition;
if (pos.y - dragStart.y > 80) {
scrollRect.enabled = false;
state = DragState.None;
Invoke("ReenableScroll", 0.01f);
}
}
}
private void ReenableScroll() {
scrollRect.enabled = true;
}
Its not easy to make the EventSystem think something has happend while it hasn't. I believe its much easier to implement your own ScrollRect logic and parse the mouse input yourself
You can call ScrollRect's OnEndDrag() method with artificial PointerEventData.
var forceEndDragData = new PointerEventData(EventSystem.current)
{
button = PointerEventData.InputButton.Left
};
_scrollRect.OnEndDrag(forceEndDragData);
I'm making a 2D Platformer and I have a block that I want to disappear when you jump and then reappear when you jump again. However, the block is just staying shown and I don't why. Here is my script;
var animator : Animator;
animator.SetBool("changeState", false);
var AudioOut : AudioSource;
var showNext = true;
function Update (){
if (Input.GetButtonDown("Jump") & showNext == true){
Close();
}
if (Input.GetButtonDown("Jump") & showNext == false){
Open();
}
}
function Close(){
GetComponent.<AudioSource>().Play();
animator.SetBool("changeState", true);
showNext = false;
}
function Open(){
AudioOut.GetComponent.<AudioSource>().Play();
animator.SetBool("changeState", false);
showNext = true;
}
Thanks
A couple of things:
This line:
animator.SetBool("changeState", false);
written on the top of your script and doesn't lies inside any function. Probably wrap it inside Start function. Verify that you are passing correct value to changeState state. For true value it should behave as Close. Verify from Animation tab and Animator tab.
this might help
there is another way you can achieve this
show the platform if the collosionEnter is triggered and on collision exit disappear the plaform
Context
I am making a mobile game in which the player is required to touch objects in a specified order. The correct order is determined in a List called clickOrder. To determine the current object the player is supposed to click, currClickIndex is used.
Problem
When touching a correct object, the debug text will display "Correct" for a split second, and will then immediately change to "Wrong." What I am unsure about is why both the if and else blocks are executed when only touching a single object.
Code
void Update()
{
if (Input.touchCount == 1)
{
if (this.enabled)
{
Vector2 worldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(worldPoint, Vector2.zero);
if (hit != null && hit.collider != null)
{
// check if the touched object is the correct one
if (hit.collider.gameObject == clickOrder[MyData.currClickIndex])
{
debug.text = "Correct";
MyData.currClickIndex++;
}
else
{
debug.text = "Wrong";
}
}
}
}
}
As soon as the correct object is being touched, you do this:
MyData.currClickIndex++;
which moves you forward in the ordered sequence, and from then on, the previously correct object is not correct anymore. But you're still touching it.
If you want to avoid this, you need to move forward in the sequence after you've touched the correct object.
if (there are touches and the correct object is being touched)
{
set a flag;
}
else if (a flag has been set)
{
MyData.currClickIndex++;
reset the flag;
}
I am trying to make a game in where you can stab an enemy, the enemy struggles for about a second and drops dead. (ragdoll);
i think its best to just show my script and you know what I mean:
In an on trigger enter script:
if(other.tag == "enemy"){
other.transform.parent.gameObject.name = ("enemy" + currentEnemy);
print(other.name);
gameObject.Find("enemy" + currentEnemy).GetComponent("RagdollOrNot").MakeKinematicFalse();
BloodParticle.emit = true;
Stabbed = true;
Character.GetComponent("MouseLook").enabled = false;
Character.GetComponent("CharacterMotor").enabled = false;
}
and in the update function:
if(Stabbed == true){
StopBleeding ++;
}
if(StopBleeding > 50){
Stabbed = false;
StopBleeding = 0;
currentEnemy ++;
Character.GetComponent("MouseLook").enabled = true;
Character.GetComponent("CharacterMotor").enabled = true;
BloodParticle.emit = false;
}
Now when my knife enters the collision of the enemy the enemy imediatly drops to the floor.
I tried putting the:
gameObject.Find("enemy" + currentEnemy).GetComponent("RagdollOrNot").MakeKinematicFalse();
in the update function in if(StopBleeding > 50).
if I do that I get an error of Null reverance exception becaus the script cand find the enemy. While it can I its in the trigger enter.
Basicly my question is: Is there any way to fix this error to give it a 50 frame delay (all the rest in StopBleeding works)?
Or is there any way I can put a simple delay in before the Ragdoll gets activated?
Thanks in advance
You can use StartCoroutine("DelayDeath"); where DelayDeath is the name of a method. See below.
if(other.tag == "enemy"){
other.transform.parent.gameObject.name = ("enemy" + currentEnemy);
print(other.name);
StartCoroutine("DelayDeath");
BloodParticle.emit = true;
Stabbed = true;
Character.GetComponent("MouseLook").enabled = false;
Character.GetComponent("CharacterMotor").enabled = false;
}
private IEnumerator DelayDeath()
{
//this will return...and one second later re-enter and finish the method
yield return new WaitForSeconds(1.0f);
gameObject.Find("enemy" + currentEnemy).GetComponent("RagdollOrNot").MakeKinematicFalse();
}
Since you're asking specifically about Unity JS and not C#, you'll use the yield keyword.
print("foo");
yield WaitForSeconds (5.0); // waits for 5 seconds before executing the rest of the code
print("bar");
On stabbing you could look up the enemy object but save it away in a variable instead of issuing the enemies dead. After the bleeding finishes you don't have to look up the enemy and can trigger the death on the saved one.
Another hint: Don't count frames as frames might be of different length. Add up time from Time.deltaTime until you reach let's say 2 seconds and then trigger the death.
Hope that helps.