Set MecAnim trigger once until state returns - c#

I'm trying to play a single animation once on a character in Unity using MecAnim. I'm really not familiar with any of this, so I might have got the approach completely wrong.
The base layer contains a lot of walking stuff, but the animation I'm trying to trigger is on a seperate Right Arm layer with an empty Default state. There is a Wave trigger applied to the Default -> Wave transition, and a timed exit on the Wave -> Default one.
I then have a script which (while debugging) fires when you press 'O' and causes the character to wave, once.
if (Input.GetKey(KeyCode.O))
{
AnimatorStateInfo currentState = this.animator.GetCurrentAnimatorStateInfo(1);
if (currentState.IsName("Right Arm.Default"))
{
Debug.Log("Waving triggered");
this.animator.SetTrigger("Wave");
}
}
The animation plays as expected, but the console shows that the IsName check is always passing as true, which makes me think I'm doing something wrong.
The in transition takes a fraction of a second to complete, then after that if the SetTrigger method is invoked again, the animation will play twice.
I'm looking for a simple way of ensure the trigger is only ever set when the state of this layer has fully returned to default.

Related

UnitySharpNEAT How to deactivate a unit

I'm hoping that someone here is familiar with UnitySharpNEAT as I'm running into a problem I can't seem to find the solution to. I can describe it, but providing code won't really be helpful as it extends over multiple scripts. It really requires that someone already know how to use this.
I'm running a simulation where a creature must find food, or die of starvation. For the purposes of "dying", I can see two different options of how to deactivate a unit, but neither one is giving me the results I am desiring.
The first option is if the hunger reaches zero, I can do this:
IsActive = false;
The problem with using this method is that if all the units are inactivated before the end of the duration of the trial, the trial just continues running until the time is elapsed, and I don't know how to make it start a new generation when all the units are inactive.
The other option is to call
DeactivateUnit()
from the base class UnitController. This Deactivates the unit, but for some reason, continues to try to perform operations on it, specifically the activate method, and results in a NullReferenceException, because it's trying to access a blackbox that has been set to null, which it shouldn't even do because that block of code is only supposed to be called if IsActive is true, but it's set to false by the DeactivateUnit() method.
All I'm looking for, is a way to deactivate a unit that has failed, by starvation or touching a wall, and if all units are deactivated, to immediately begin a new generation.

Parameter" does not exist warning

The Context:
I'm currently creating a melee combo system for my 2D RPG. The first time a player attacks will trigger the first attack animation and if the player chooses to attack a second time, it ill trigger the second attack animation. I got the system to work by calling an attack function that passes a string parameter depending on which animation I need to be played.
So the ComboOrder function will be called every frame to order the animations and once the player presses the "E" key, the Attack function will be called with either "Attack-1" or "Attack-2".
The Problem: The code and animations work fine however, after many changes to other parts of the game I noticed, I get a warning every time I press the "E" key. What I changed was completely unrelated ti this so I don't see a connection from that to the warning.
Parameter" does not exist
Solutions I have tried: I've searched the web for answers, however, none of them fit my issue. It seems that Unity thinks I'm passing the string " which would indicate a syntax error but I've double-checked my code and I can't find anything of sorts. I've also heard that it has been a bug in Unity but they never told how to fix it. Is there anything I can do if that were the case?
Here's the code:
void ComboOrder() {
if (comboIndex == 1)
{
if (Input.GetKeyDown(KeyCode.E)) // Attack Input
{
Attack("Attack-1");
comboIndex++;
}
} else if (comboIndex == 2) {
if (Input.GetKeyDown(KeyCode.E)) // Attack Input
{
Attack("Attack-2");
comboIndex--;
}
}
}
public void Attack(string attack)
{
animator.SetTrigger(attack);
}
And here are the Animator settings for the player:
So after not being able to work on the game for about two weeks, I came back to take a closer look and realized it was what you said, there was an animation event calling the function without passing a parameter and since it was not coded, I never caught it. Thank you to everybody who helped.

How often is while(true) called in C# Unity?

How often is while(true) called in C# Unity? Is it like Update(), where it's called every frame?
It will recurse infinity in a single frame unless there is a break or yield (coroutine). With a coroutine if you do something like
yield return null;
it will continue the next frame.
It will keep going within one frame drawing out the frame time to infinity. Unbroken, it will crash the editor or, if in a full build, the game.
The answer is once ... the frame where while(true) is entered, assuming it has no break/return or other mechanism to stop it, will be the last frame before Unity crashes to your desktop, probably with no warning or error message.
I've crashed Unity before with accidental recursion, like writing public int Number => Number; instead of public int Number => number; (property that returns itself to itself infinitely) and Unity just crashes, silently. And it can be hard to find something like that after you've copied and pasted some code around. Infinite loops/recursion are basically fatal to Unity on the main thread.
You probably picked up that while(true) idea from a scripting language for a much simpler game engine where it handles a lot of stuff behind the scenes for you. I've seen it before in "3D Game Studio" engine, many, many years ago, in their "Lite C" scripting language. You'd simply put while(1) and it would run an iteration of your script loop on each frame and shut it down for you when it ended, very conveniently. But you can't do that in C#. Even though Unity calls it "scripting", C# is still a compiled programming language and it does exactly what you tell it to do. And while(true) is telling it "Repeat this loop until true is no longer true" (which means forever), so the loop never ends (unless you use break, return or something else to explicitly stop it).

Avoid to use 'Update'?

I have a seperate script of time which I use to show time in my scene. It contains hour and minute and seconds variable.I want to do some specified work e.g., code execution on specified time and currently i am doing something like this. in Update. I am running a function which check continously check time variable in order to run an animation.
void Update()
{
checkTrainArriveTime();
}
void checkTrainArriveTime()
{
if (timeManager.GetComponent<Scale2>().hour == trainArriveTimeHour && timeManager.GetComponent<Scale2>().min == trainArriveTimeMin
&& isTrainArriveConditionExecute)
{
isTrainArriveConditionExecute = false;
PlayAnimationClip("Start");
}
else if (timeManager.GetComponent<Scale2>().min != trainArriveTimeMin)
{
isTrainArriveConditionExecute = true;
}
}
As Time will match this function will play the animation. Now I have 50 script attached to 50 different game Object. It is
working fine but It definitely not the right way to use Update Event. In my code, It is necessary to check time on every frame and
extra load on update. Is there any efficient way to do this Job?.
I can see your struggle. You are right, it is definitely not the best way forward.
The best option I can see here would be creating Animation Manager which is a singleton instance (there is only one instance allowed per application).
I would suggest moving your animation triggering logic to an Update method of AnimationManager.
Once you have done that. You will be able to access its instance calling AnimationManager.getInstance() method.
Next step is creating internal registry that would be nothing else than just a list of your registered game objects that you want to trigger animation for.
I don't know what exactly is your timeManager but I can imagine it is probably an instance of TimeManager controller that you drag and drop onto your public timeManager property. Consider turning it into singleton as well or at least moving assignment of timeManager.GetComponent<Scale2>() into Awake() method.
It is important to not to call GetComponent() method from inside of Update()', as it has an impact on performance.GetComponent` is quite expensive to call.
Hope it helps.

How do I fire up an event on any keyboard, mouse or gamepad state change?

Is there a way to immediately react to any change in the states of mouse, keyboard and gamepad(s) in a C# application?
I believe XNA is just like any other C# app, so it might not be any different, but just in case, I want to improve my XNA game input by immediately firing up corresponding events.
Default XNA doesn't have an event handler (at least I've never seen it being mentioned). Nuclex.Input doesn't detect some keys (like Alt, F10 or Pause, which is unacceptable).
Normally you store the state of the input on the previous frame, and then test whether then input has changed between frames. For example, your Update method might look like:
KeyboardState ks = Keyboard.GetState();
if(ks.IsKeyDown(Keys.Space) && lastKeyboardState.IsKeyUp(Keys.Space))
{
DoAThing();
}
lastKeyboardState = ks;
(Wrote that code entirely from memory, so it might not be quite right. But it should illustrate the concept.)
This will give you key events with no more than 1 / yourFPS delay. At 60FPS this is about 16ms. This is usually acceptable for gameplay purposes. If you especially want an event - you could simply fire one where I have put DoAThing, above.
For typing text you generally want the character events from Windows (which a library like Nuclex.Input can give you). This isn't so much so you get better latency, but so you can get keyboard events in an ordered and reliable way (for example: this way you never get two key coming down on a single frame resulting in an ambiguous order).
More importantly, it's so you can get the events after Windows has had a chance to apply input processing. For example, this gives you difference between typing an a and an A. Or someone entering a character with alt+numpad, or applying a diacritic. The downside is that you miss out on various non-text keys like, as you mention, Alt, F10, Pause, etc.
Finally, a quick read over Nuclex.Input reveals that it at least should provide the keys that you want - specifically IKeyboard.KeyPress and .KeyRelease. If it's not working, it could be a bug in Nuclex. Or something on your system is interfering with window messages.
One possible work-around might be to accept the latency on these missing keys by polling for them as well. The code to use polling as a seamless fall-back is probably fairly simple.

Categories

Resources