Activate and Deactivate Invoke function - c#

I attempted to give a delay to my function in Unity using C# language. By using Invoke, I achieved to add delay when the cursor is moved to a certain area. However, now I need to cancel the Invoke when the cursor is moved from that certain area. The idea is, when I accidentally move the cursor to the area, I can cancel whatever function being invoked there.
Here's my current code.
void SceneCall(){
Application.LoadLevel (MainMenu);
}
void SceneCallIn(){
Invoke ("SceneCall", 3f);
}
if (_newGameButton.Contains (Event.current.mousePosition)) {
SceneCallIn();
}
I tried to use CancelInvoke() as else, and it even doesn't want to invoke anymore when I move my cursor to _newGameButton afterwards. How do you cancel an Invoke then activate it once again? Thank you for your answer~
EDIT: Like #Programmer says in comments, what I exactly want to do is when my mouse is position at a certain point, timer will start counting. After 3 seconds
MainMenu scene will be loaded. While the timer is counting and the pointer is moved away from that certain position, I want the timer to stop and I don't want the MainMenu scene to be loaded anymore.

If you truly want to have "rollovers" and so on, here is a full tutorial:
https://stackoverflow.com/a/36046495/294884
Really you will have to become totally expert in all that, before you can do it.
I must tell you again though:
For 15 years now, you should never use rollovers for any reason in interface.

I faced the same problem yesterday, but I solved simply calling again the invoke method.
Here is my code:
public void OnGazeEnter()
{
InvokeRepeating("OnGazeStay", 0.0f, 1.0f / 30.0f);
}
public void OnGazeExit()
{
CancelInvoke("OnGazeStay");
}
In your case, if you want to register more than one method, you will have to save some sort of List<String> myMethods, so you will be able to delete every method that you've registered.

Related

Unity: No animation event is fired when quickly pressing a button

I am working on a 2D video game project but I have a somewhat strange error in the character's attack. I've been using Unity for a short time...
When I press the attack button, an animation is played and a boolean variable is set to true. When the attack animation ends, it has an event in place that calls a function to change the boolean variable back to false.
Main script added to player gameobject (MonoBehaviour):
void Update(){
if (Input.GetKey(script_buttons.button_attack))
{
gun_attacking = false;
player_animator.Play("gun_attack");
}
}
Event that is called when the weapon attack animation ends:
void foot_gun_attack()
{
attack_script.gun_attacking = false;
}
It works fine, but if I quickly press the attack button, there are times when the variable never goes to false, and the game goes crazy.
Is it unreliable to use events in the animations themselves? why does it fail and not change the boolean variable to false again?
I have partially fixed it by adding a State machine behavior script to the animation, and in said script, right in the OnStateExit function I change the variable to false. This works and the attack never misses no matter how fast you press the button, the problem? which forces me to have both at once, the animation event and the state machine behavior script. If I remove the event the vairable never goes false, if I remove the state machine behavior the variable does go false but fails every once in a while.
Script on state machine behavior:
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
attack_script.gun_attacking = false;
}
The only way it won't fail is to set the variable to false in both places, which I think is crazy and shouldn't be normal behavior. The animation event should suffice and work fine, but why isn't it working correctly? I wouldn't like to have to limit button presses or add Timeouts, or would that be the only way?
Maybe it's my mistake or Unity problem, does anyone know what's going on?
The reason may be that the animation never ends and goes to another state
The first way is that
When You can call the function you want when the animation starts, but in the coroutine, it waits for the animation time and then returns the bool to false.
or continue with your own method, but check and change this configuration in the transitions before and after that animation.
Especially try these 2 checkboxes

How to implement the Command Pattern in a Puzzle Game

Setup:
I'm making a classic top-down, tile based puzzle game about pushing blocks and I'm trying to implement the Command Pattern to have a Undo/Redo function. In my design, a "turn" is fired whenever the player moves one tile, and the world must update somehow (lasers can be blocked, Blocks are destroyed if on top of water, Big floor buttons are pressed down, etc.)
I've abstracted my player movement into a Concrete Command MoveCommand by simply changing its position based on a direction on execution. This MoveCommand is then instantiated inside a Move() method. Blocks also happen to have a Move() method that must be called whenever the player "pushes" them (i.e. walks into them and there's a free space behind).
Question 1. Should the Block movement be its own Command, or should it be somehow appended to and managed by the player's MoveCommand? Right now I figured I would have each be its own separate thing, and then whenever the player presses the Undo button, have the Undo method execute several times until everything that must happen in that turn resolves. However, I'm not sure whether this is how you're supposed to be implementing this pattern.
Question 2 As mentioned above, blocks must be destroyed when they touch water. Should this destruction be its own WalkIntoDeadlyTile Command, or should it be appended to the Block's MoveCommand? Both questions make me realize I might not be understanding how to use this pattern, but I'm not sure how to look it up or answer these specific problems.
It is a rare case, where the ICommand interface would not be completely missplaced. You can not keep polling CanExecute in most environments. You need a way to force re-evaluation on conditions. Or just use something with binding.
But games are what I call "notorious redrawers" anyway. They could poll CanExecute once per draw pass and once in the Input processing pass, without much issues. The check would also be relatively simple (isPlayerTurn). The only possible issue is getting teh games state into the Command Implementations.
Question 2 As mentioned above, blocks must be destroyed when they touch water. Should this destruction be its own WalkIntoDeadlyTile Command, or should it be appended to the Block's MoveCommand?
It should happen in the colission check. A basic square one would work, If the block box collides with the water box, call destroy on the block. This also prevents you from forgetting to add special movement to later blocks or if the blocks somehow teleport below water.

Unity UI - Interacting with worldspace UI when cursor is locked

I'm trying to interact with world space UI using a first person controller when Cursor.lockState is set to CursorLockMode.Locked.
world space UI and a character
But when cursor is locked, cursor position is set to (-1, -1),
which is told from the Inspector.
cursor position of (-1, -1)
I performed a graphic raycast with EventSystem.RaycastAll, Sreen.width/2 and PointerEventData. EventSystem.current.RaycastAll collects all UI objects in the middle of screen, but no events is sent to them.
I also tried ExecuteEvents.Execute<IEventSystemHandler> to manully send event to UI targets. This works for button when I send 'submit' event to it. Obviously this is not an elegant solution. I have no idea how to send message to slider either.
// manully send a 'submit' event to UI elements
List<RaycastResult> results = new List<RaycastResult>();
void Update() {
if (Input.GetButtonUp("Fire1")) {
PointerEventData data = new PointerEventData(EventSystem.current);
data.position = new Vector2(Screen.width / 2, Screen.height / 2);
EventSystem.current.RaycastAll(data, results);
foreach (var result in results) {
ExecuteEvents.ExecuteHierarchy<ISubmitHandler>(
result.gameObject, data,
ExecuteEvents.submitHandler
);
}
}
}
This crazy attempt works when played full-screen on Windows. 2333
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SetCursorPos ( int x , int y );
void SetCursorPositionToCenter()
{
  SetCursorPos(Screen.width/2, Screen.height/2);
}
Relavant Resources
I had a lot of problems working with Graphics Raycaster and Global UI elements as well. I tried a lot of things as well but the event system didn't seem to work. But I was simulating a mouse with a touchpad and maybe I didn't completely simulate how a mouse works with UI elements.
I ended up abandoning graphics raycaster and instead add a box collider to all UI elements. That way a regular physics raycaster would be able to detect it and run some code. For the slider, it is just increasing the slider's value as your x or y of your pointer increase.
Hope this helps a little.
What you're doing with the submit handler is similar to the many different ways this can be done. I've not dealt with sliders specifically, because it's not very easy to control sliders in this method (player controller or, in the case of VR, the user's head, does not do straight lines very well). So for slider input we usually go with +/- buttons. Another idea could be that when the user is pointing at a UI element that you release the cursorLock when they click. When click is released you can resume cursor lock.
UI elements are also often in need of states like hover/onEnter, onExit, sometimes pointer up, and usually pointer down. So we've often used Selectable class for this. I think all the interactable UI elements inherit from this so it's a good spot to access the UI element from. This will usually trigger the proper events but it can be a little tricky. Examine some of the many readily available gaze input systems as they're doing the same thing. I don't think I've ever seen one handle sliders though (they're usually meant for VR and gaze-to-slider control would be bad UX).
Cheers and good luck!
If you're trying to access UI elements without affecting gameplay you can simply set Time.TimeScale = 0; which basically pauses time but UI elements will still be active. Then just unlock your cursor and use it freely.

Animator Controller: Animation Completion Callback

I've seen some posts on the legacy system using Animations, but I'm using an Animator Controller and I want to know when an animation has completed playing.
Is there a way to assign a callback to when an animation has completed playing?
I could create a co-routine and check every frame but I feel thats the wrong way to do it.
Do you know how to check when an Animation Controller Animation has finished playing?
Since you are using Mecanim this will give you what you want:
if(this.animator.GetCurrentAnimatorStateInfo(0).IsName("AnimationName"))
{
// Do something.
}
Make sure you use the correct AnimationName and you will be alright.
The API reference GetCurrentAnimatorStateInfo.
Gets the current State information on a specified AnimatorController
layer.
It takes one parameter which is The Layer's Index.
Event Solution
You can trigger an Event by calling a function. You need to write the name of the function you want to call at the selected frame in the Function area of the Edit Animation Event window.
Short tutorial on how to do it.

Playing two separate animations one after another upon completion

I'm trying to play two animations one after another in unity (each animation is two separate paths for the main camera) and from my research I think I need to use the following:
// Update is called once per frame
void Update () {
animation.PlayQueued("CameraMovement", QueueMode.PlayNow);
animation.PlayQueued("SpaceSceneMovement", QueueMode.CompleteOthers);
}
However, with this code attached to my camera, my game still only plays the first path. I created the paths so that there should be half a second delay between the different paths. I have both animations in the animation component of my camera (see attached pics) and I'm stumped as to why this isn't working.
Am I missing something?
As stated by user2025312, you are calling the code each frame. Which means that each frame you're telling it to play the first animation immediately, and you queue the second one. That won't work.
Depending on what you want to do you have several options. Say you want to continuously play the two animations in a loop. What you could do is:
void Update () {
if (!animation.isPlaying)
{
animation.PlayQueued("CameraMovement", QueueMode.PlayNow);
animation.PlayQueued("SpaceSceneMovement", QueueMode.CompleteOthers);
}
}
As should be easy to follow, that checks whether or not there is an animation playing, and if not, it will queue the two, playing the first one immediately. That will work fine within Update().
If however you're looking to play the animation sequence just once (or upon a trigger) place the two lines within Start() or a method of your choice.
void Start () {
animation.PlayQueued("CameraMovement", QueueMode.PlayNow);
animation.PlayQueued("SpaceSceneMovement", QueueMode.CompleteOthers);
}
That should work just fine. If not, verify that your animations work individually.

Categories