Unity2d game shooting and animation sync issue - animation

I'm a new in Unity and making my first 2D game. I seen several topics on this forum in this issue, but I didn't found the solution.
So I have a lovely shooting animation and the bullet generation. My problem, I have to generate the bullet somewhere at the middle of the animation, but the character shoots the bullet and the animation at the same time, which killing the UX :)
I attached an image, about the issue, this is the moment, when the bullet should be initialized, but as you can see it's already on it's way.
Please find my code:
The GameManager update method calls the attackEnemy function:
public void Awake(){
animator = GetComponent ();
animator.SetTrigger ("enemyIdle");
}
//if the enemy pass this point, they stop shooting, and just go off the scren
private float shootingStopLimit = -6f;
public override void attackPlayer(){
//animator.SetTrigger ("enemyIdle");
if (!isAttacking && gameObject.transform.position.y > shootingStopLimit) {
isAttacking = true;
animator.SetTrigger("enemyShoot");
StartCoroutine(doWait());
gameObject.GetComponentInChildren ().fireBullet ();
StartCoroutine (Reload ());
}
}
private IEnumerator doWait(){
yield return new WaitForSeconds(5);
}
private IEnumerator Reload(){
animator.SetTrigger ("enemyIdle");
int reloadTime = Random.Range (4,7);
yield return new WaitForSeconds(reloadTime);
isAttacking = false;
}......
My questions:
- How can I sync the animation and the bullet generation ?
Why not the doWait() works ? :)
Is it okay to call the attackPlayer method from the GameManager update ?
The enemies are flynig from the right side of the screen to the left, when they reach the most right side of the screen, they became visible to the user. I don't know why, but they to a shooting animation (no bullet generation happen )first, only after it they do the idle. Any idea why ?
Thanks,
K

I would suggest checking out animation events. Using animation events, you can call a method to instantiate your bullet.
To use Mecanim Animation Events 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.
The other boxes are for any variables that you want to pass to that function to trigger whatever you have in mind.
Triggering/blending between different animations can be done in many different ways. The event area is more for other things that you want to trigger that are not related to animation (e.g. audio, particle fx, etc).

Related

My animation is lagging, why?

I have an animation in unity, and basically it shows Donald Trump running:
I also have this one frame animation of Trump jumping:
Basically, when he jumps, the jump animation plays, and when he lands, the walk animation plays again.
This all works, and this code runs it:
function Update() {
trump.velocity = Vector2(speed, trump.velocity.y);
if (jump > 0) {
jumpBool = true;
}
else {
jumpBool = false;
}
animator.SetBool("Jump", jumpBool);
That's in the physics script. Then from the animator:
This all works, and the animations change when they are supposed to. The issue is, it lags before it finishes. I think that when Trump jumps, the walk animation finishes before it switches to the jump animation. My question is, how do I automatically switch animations immediately, so it won't look so laggy?
You can immediately call the Jump animation to be played at the point you make the JumpBool = true. Doing so you don't need to wait for the walk animation finish, it will simply stop the Walk and and move to Jump.
function Update() {
trump.velocity = Vector2(speed, trump.velocity.y);
if (jump > 0) {
animator.Play("Trump Jump");
//jumpBool = true;
}
else {
//jumpBool = false;
}
//animator.SetBool("Jump", jumpBool);
You don't even need to Set the bool, after the Jump animation has finished it will move back to the Walk animation.

Controlling animations in an animator via parameters, in sequences

So I am animating an avatar, and this avatar has its own animator with states and such.
When interacting with props, the props itself has an animator with states in it. In both case, I transition to some animations through parameters in the animator (bool type).
For example, for a door, the character will have "isOpeningDoor", while the door will have "isOpen".
Now the question: when I change the value on an animator on GO1, and then change the bool on GO2; do the first animation finish and then the second start? Because in my case, it does not happen; they start almost at the same time.
void OnTriggerEnter (collider door)
{
if (door.gameObject.tag=="door")
{
GOAnimator1.SetBool("isOpeningDoor", true);
GOAnimator2.SetBool("isOpen", true);
}
}
I believe that I am doing it wrong, since I change the parameter on the animator, but I do not check for the animation to end; is this even possible or am I doing something not kosher?
I really think it might be doable!
As you have it in your code now, the animations on GO1 and GO2 start at almost the same time because that's how it's written. The OnTriggerEnter() function will complete the execution in the frame it is called, and return the control to Unity.
What I think that might help you are coroutines and sendMessage between gameobjects:
http://docs.unity3d.com/Manual/Coroutines.html
http://docs.unity3d.com/ScriptReference/GameObject.SendMessage.html
The idea is to:
Create a coroutine in GO2 that waits an amount of time until it sets the GOAnimator2 variable to activate the door animation.
Create a function in GO2 that calls the aforementioned coroutine
From the OnTriggerEnter() send a message to GO2 to execute the newly created function
It reads complicated, but it's fairly simple. The execution would be like this:
1.Code for the coroutine:
function GO2coroutine(){
float timeToWait = 0.5f; //Tweak this
for ( float t = 0f; t < timeToWait; t+=time.deltaTime)
yield;
GetComponent<Animator>().SetBool("isOpen",true);
}
Code for the function calling it:
function callCoroutine() {
StartCoroutine("Fade");
}
And the code modification for your OnTriggerEnter():
void OnTriggerEnter (collider door)
{
if (door.gameObject.tag=="door")
{
GOAnimator1.SetBool("isOpeningDoor", true);
GO2.SendMessage("callCoroutine");
}
}
I didn't have a chance to test the code, so please don't copy paste it, there might be slight changes to do.
There is another way, but I don't like it much. That is making the animation longer with an idle status to wait for the first game object animation to end... but it will be a hassle in case you shorten the animation because you have to, or have any other models or events.
Anyway, I think the way to go is with the coroutine! Good Luck!

Simple 2-step animation using Unity's Animation Tool

I am new to Unity/coding and trying to create a simple 2-step animation in which I can adjust the delay times for each step. I have a lift in my game that uses two animations: "Up" and "Down".
I'm using an enumerator to play the animations, and this is what I have so far:
IEnumerator Go()
{
while(true)
{
GetComponent<Animation>().Play ("Up");
yield return new WaitForSeconds(delayTime);
break;
GetComponent<Animation>().Play ("Down");
yield return new WaitForSeconds(delayTime);
break;
}
}
I understand I could just animate the whole thing as one motion, but I want to be able to adjust the delay times on the fly. My goal is to animate these two in succession. Up, then down. At the moment my lift goes up and stays there. What am I doing wrong?
Thanks for the help!
Remove the break-clauses:
IEnumerator Go()
{
while(true)
{
GetComponent<Animation>().Play ("Up");
yield return new WaitForSeconds(delayTime);
GetComponent<Animation>().Play ("Down");
yield return new WaitForSeconds(delayTime);
}
}
Now it should loop the two animations. In the original code the break statements are causing the execution jump out of the loop and, therefore, the Play for the "Down" is never called and execution of the function is terminated.
If you want the lift go up and down only once you need to remove the while loop.

StateTime in LibGDX Animation

How do I use implemented Animation in LibGDX? I know, that the documentation can be found here, but when I want to get a frame out of the Animation, I need to use stateTime, which isn't explained anywhere in the documentation. So the question is, what is stateTime in terms of LibGDX's Animation?
There is some more doc on the getKeyFrame method documentation:
Returns a TextureRegion based on the so called state time. This is the amount of seconds an object has spent in the state this Animation instance represents, e.g. running, jumping and so on.
(This documentation doesn't really make any sense to me either.)
But, the Animation.java source is readable. It looks like it boils down to
getKeyFrameIndex
which divides the stateTime by frameDuration (which is a parameter of the constructor -- how long each frame lasts) to compute an array index. getKeyFrameIndex does different things for looping or non-looping sequences, but basically it takes the array index to look up the right key frame in the sequence to display.
So the "stateTime" is the input to pick a key frame from your Animation. The documentation is assuming you have one Animation instance for "running" and another for "jumping" (these are the "states" its referring to). To find the right key frame within an Animation, you tell it how long you've been in this "state". So, if you've been in the "running" Animation instance for 1.2 seconds, it does some math to figure out which key frame to show (say you've initialized the instance with 30 frames that show for 0.0333 seconds and loop -- it picks the 6th frame).
The wiki https://github.com/libgdx/libgdx/wiki/2D-Animation has some more details and an example, but doesn't address this directly, either.
animationFrames = walkSheetArray[moveDirection];
animation = new Animation(1f / 5f, animationFrames);
myAnimatedActor = new AnimatedActor(animation);
stage.addActor(myAnimatedActor);
public class AnimatedActor extends Image {
private float stateTime = 0;
Animation animation;
public AnimatedActor(Animation animation) {
super(animation.getKeyFrame(0));
this.animation = animation;
}
#Override
public void act(float delta) {
((TextureRegionDrawable) getDrawable()).setRegion(animation.getKeyFrame(stateTime += delta, true));
super.act(delta);
}
}

Flixel Game Over Screen

I am new to game development but familiar with programming languages. I have started using Flixel and have a working Breakout game with score and lives.
I am just stuck on how I can create a new screen/game over screen if a player runs out of lives. I would like the process to be like following:
Check IF lives are equal to 0
Pause the game and display a new screen (probably transparent) that says 'Game Over'
When a user clicks or hits ENTER restart the level
Here is the function I currently have to update the lives:
private function loseLive(_ball:FlxObject, _bottomWall:FlxObject):void
{
// check for game over
if (lives_count == 0)
{
}
else
{
FlxG:lives_count -= 1;
lives.text = 'Lives: ' + lives_count.toString()
}
}
Here is my main game.as:
package
{
import org.flixel.*;
public class Game extends FlxGame
{
private const resolution:FlxPoint = new FlxPoint(640, 480);
private const zoom:uint = 2;
private const fps:uint = 60;
public function Game()
{
super(resolution.x / zoom, resolution.y / zoom, PlayState, zoom);
FlxG.flashFramerate = fps;
}
}
}
There are multiple ways to go about doing this...
You could use different FlxStates, like I described in the answer to your other post: Creating user UI using Flixel, although you'll have to get smart with passing the score or whatever around, or use a Registry-type setup
If you want it to actually work like you described above, with a transparent-overlay screen, you can try something like this (keep in mind, the exact details may differ for your project, I'm just trying to give you an idea):
First, make sure you have good logic for starting a level, lets say it's a function called StartLevel.
You'll want to define a flag - just a Boolean - that tracks whether or not the game is still going on or not: private var _isGameOver:Boolean; At the very end of StartLevel(), set this to false.
In your create() function for your PlayState, build a new FlxGroup which has all the things you want on your Game Over screen - some text, an image, and something that says "Press ENTER to Restart" (or whatever). Then set it to visible = false. The code for that might look something like:
grpGameOver = new FlxGroup();
grpGameOver.add(new FlxSprite(10,10).makeGraphic(FlxG.Width-20,FlxG.Height-20,0x66000000)); // just a semi-transparent black box to cover your game screen.
grpGameOver.add(new FlxText(...)); // whatever you want to add to the group...
grpGameOver.visible = false;
add(grpGameOver); // add the group to your State.
Depending on how your game is setup, you may also want to set the objects in your group's scrollFactor to 0 - if your game screen scrolls at all:
grpGameOver.setAll("scrollFactor", new FlxPoint(0,0));
In your update() function, you'll need to split it into 2 parts: one for when the game is over, and one for if the game is still going on:
if (_isGameOver)
{
if (FlxG.keys.justReleased("ENTER"))
{
grpGameOver.visible = false;
StartLevel();
}
}
else
{
... the rest of your game logic that you already have ...
}
super.update();
Keep in mind, if you have things that respond to user input anywhere else - like a player object or something, you might need to change their update() functions to check for that flag as well.
Then, the last thing you need to do is in your loseLive() logic:
if (lives_count == 0)
{
_isGameOver = true;
grpGameOver.visible = true;
}
else
...
That should do it!
I would highly recommend spending some time with different tutorials and sample projects to kind of get a better feel for Flixel in general. Photon Storm has some great material to play with (even though he's jumped over to HTML5 games)
I also want to note that if you get comfortable with the way Flixel handles updates, you can get really smart with your state's update() function and have it only call update on the grpGameOver objects, instead of having to change all your other objects updates individually. Pretty advanced stuff, but can be worth it to learn it.

Resources