Unity3d Animation just doesn't show up sometimes - unity3d

I have simple pop-up text animator with four attached animations (heal text animation, crit heal animation, damage animation and crit damage snimation).
The animator changes animations on a trigger received from a simple script.
public static void PopUpTextInstantiator(int text, Transform location, bool crit)
{
Initialize();
Debug.Log("Instancing POPUP with VALUE" +text +" and CRIT is "+ crit);
PopUpText instanceclone = Instantiate(popupText);
Vector2 screenPosition = new Vector2(location.position.x + Random.Range(-.5f, .5f), location.position.y + Random.Range(0.1f, 0.5f));
instanceclone.transform.SetParent(canvas.transform, false);
if (text < 0 && crit == true)
{
instanceclone.GetComponentInChildren<Animator>().SetTrigger("CritDamage");
Destroy(instanceclone, 1.2f);
}
else if (text < 0 && crit == false)
{
instanceclone.GetComponentInChildren<Animator>().SetTrigger("Damage");
Destroy(instanceclone, 1.2f);
}
else if (text > 0 && crit == false)
{
instanceclone.GetComponentInChildren<Animator>().SetTrigger("Heal");
Debug.Log("IM WORKING POPUP INSTANTIATOR NON CRIT");
Destroy(instanceclone, 1.2f);
}
else if (text > 0 && crit == true)
{
instanceclone.GetComponentInChildren<Animator>().SetTrigger("CritHeal");
Destroy(instanceclone, 1.2f);
}
//Debug.Log("Instancing POPUP at COORD VALUE" + location.transform.position);
//instanceclone.transform.position = screenPosition;
instanceclone.transform.position = screenPosition;
instanceclone.SetText(text);
}
There is problem SOMETIMES (not always but quite often) where the animation (especially "hea animation") just doesn't shown up. I see instanced parent but no animation. Same problem in the build. Crit Heal animation is always shown correctly, damage some times doesn't show, and simple Heal doesn't show very often. I just don't understand why and where the error is - the script is essentially the same. The animation by itself is working perfectly.

Related

Unity 3d Gun Recoil Animation IK Problems

im having trouble with the hand IK of a -recoil shoot animation- that is on an override layer in the animator. I have it set up so that when I aim(left trigger), it allows me to shoot with another button(right trigger). I have it so the weight (hand IK) increases to 1 (in the rig layer) when I aim and decreases to 0 when I let go of the aim button.
The problem is that if I shoot the gun (uses recoil gun animation) and let go of the aim button immediately afterwards, the animation will continue to play but the IK will go to 0 and the hands will look all messed up.
I've tried setting the IK hand weight to 1 when he fires the gun, so he'll still hold onto it, but it doesn't work since shoot is only true if aim is being held down.
So overall I fire the gun, he does a recoil animation, and when you let go of aim too early, the animation looks all messed up like he's waving to you from behind his back. Like it aborts the animation or something.
private void HandleMovementInput()
{
horizontalMovementInput = movementInput.x;
verticalMovementInput = movementInput.y;
animatorManager.HandleAnimatorValues(horizontalMovementInput, verticalMovementInput, runInput);
if (verticalMovementInput != 0 || horizontalMovementInput !=0) //running
{
if (aimingInput)
{
if (animatorManager.isAimingGunn == false)
{
shootInput = false;
}
}
}
if (animatorManager.isAimingGunn)
{
animatorManager.leftHandIK.weight = 1; // IK weight
animatorManager.rightHandIK.weight = 1;
horizontalMovementInput = 0f; // joystick
verticalMovementInput = 0f;
}
else if(animatorManager.isAimingGunn == false)
{
if(verticalMovementInput != 0 || horizontalMovementInput !=0) //running
{
animatorManager.leftHandIK.weight = 0;
}
animatorManager.leftHandIK.weight = 0; // IK weight
animatorManager.rightHandIK.weight = 0;
}
}
private void HandleShoot()
{
if (aimingInput) // must aim otherwise shootInput(right trigger on controller) wont work
{
if (shootInput)
{
shootInput = false;
playerManager.UseCurrentWeapon();
}
}
}
I was able to fix it. I used this code to tell the character to keep aiming if still in the current animation.This allows for the animation to finish before you set the Hand IK to 0.
if(animator.GetCurrentAnimatorStateInfo(1).IsName("Pistol_Shoot"))
{
aimingInput = true;
}
Also Due to it getting overly complicated I changed the aim cancel button to the top left trigger on the controller ( while aim is on the bottom left trigger).

How to use boolean functions to display different "menus" of processing game

I am writing code for a version of "Flappy Bird". I am trying to produce a start menu, end menu, and difficulty menu. So far I have been successful with the start and end, but am struggling with the difficulty menu to show. I believe my code is also very messy and would like to tidy it up, but not sure where to start.
I tried adding boolean "diff" and including that as false in my arguments in the mousePressed method.
void mousePressed() {
//START MENU
if (menu==true&&end==false) {
if (mouseX > 175 && mouseX < 625 && mouseY > 500 && mouseY < 600) {
menu = false;
end = true;
}
if (mouseX > 175 && mouseX < 625 && mouseY > 650 && mouseY < 750) {
diff();
}
}
//GAMEPLAY
if (menu==false&&end==true) {
b.bounce();
}
//END MENU
if (menu==false&&end==false) {
if (mouseX > 200 && mouseX < 600 && mouseY > 500 && mouseY < 600) {
restart();
b.bounce();
}
if (mouseX > 200 && mouseX < 600 && mouseY > 650 && mouseY < 750) {
startMenu();
}
}
}
I expected the output to show the difficulty menu, but it only showed the difficulty menu for one frame, then snapped back to the start menu.
I'm assuming your diff() function draws the difficulty menu. I'm also assuming you have a draw() function that draws things depending on your game's current state (menu, game, end menu, etc...).
The problem is that you're drawing your difficulty menu once, when the mouse is pressed on the difficulty button, and then it's being immediately overdrawn by draw().
In programs that draw continuously (like with draw()), whenever you want to show something for more than one frame, you need to draw it each frame (i.e. in draw()).
The solution is to add a "difficulty menu" state. Your draw() function would then work something like this:
void draw() {
if (menu && !diff && !end) {
drawMenu();
} else if (!menu && diff && !end) {
diff();
} else if (!menu && !diff && end) {
//Why do you draw the game when end is TRUE?
drawGame();
} else if (!menu && !diff && !end) {
//Why do you draw the end menu when end is FALSE?
drawEndMenu();
}
}
You would, of course, need to modify the mousePressed() function as well.
You also said that you feel your code is messy. This is a type of code smell; Whenever somethings feels "wrong" when you're programming, it often means there's a better way to do it. It's good that you noticed this.
Firstly, your function names are a bit non-descriptive: Instead of diff(), I recommend something like drawDiffMenu(). Rule of thumb: Function names should almost always be verbs.
Secondly, you shouldn't be handling gamestate with a bunch of booleans; Since you can only have one state at a time, you should only have one variable. (If you ever need a state-inside-a-state, make another variable.) Best way to do that is with enums!
Example:
enum GameState {
MENU, GAME, DIFF_MENU, END
}
GameState gameState = GameState.MENU;
//...
void draw() {
// Google "java switch statement"
if (gameState == GameState.MENU) {
drawMenu();
} else if (gameState == GamesState.DIFF_MENU) {
drawDiffMenu();
} else if...
// Etc...
}
A nitpick: Calling b.bounce() after restart() is a bit odd, since in theory that bounce should be a part of your game starting.
Happy coding!

Unity - CheckSphere not working? spawn freezes only on device?

I am trying to spawn a set number of cubes within an ever changing area (a plane, ARKit) and NOT have them overlap. Pretty simple I'd think, and I have this working in Unity editor like so:
My problem is deploy to device (iPhone) and everything is different. Several things aren't working, and I don't know why - it's a relatively simple script. First I thought CheckSphere wasn't working, something with scale being different - but this is how I try to get an empty space:
public Vector3 CheckForEmptySpace (Bounds bounds)
{
float sphereRadius = tierDist;
Vector3 startingPos = new Vector3 (UnityEngine.Random.Range(bounds.min.x, bounds.max.x), bounds.min.y, UnityEngine.Random.Range(bounds.min.z, bounds.max.z));
// Loop, until empty adjacent space is found
var spawnPos = startingPos;
while ( true )
{
if (!(Physics.CheckSphere(spawnPos, sphereRadius, 1 << 0)) ) // Check if area is empty
return spawnPos; // Return location
else
{
// Not empty, so gradually move position down. If we hit the boundary edge, move and start again from the opposite edge.
var shiftAmount = 0.5f;
spawnPos.z -= shiftAmount;
if ( spawnPos.z < bounds.min.z )
{
spawnPos.z = bounds.max.z;
spawnPos.x += shiftAmount;
if ( spawnPos.x > bounds.max.x )
spawnPos.x = bounds.min.x;
}
// If we reach back to a close radius of the starting point, then we didn't find any empty spots
var proximity = (spawnPos - startingPos).sqrMagnitude;
var range = shiftAmount-0.1; // Slight 0.1 buffer so it ignores our initial proximity to the start point
if ( proximity < range*range ) // Square the range
{
Debug.Log( "An empty location could not be found" );
return new Vector3 (200, 200, 200);
}
}
}
}
This again, works perfect in editor. This is the code Im running on my device (without check sphere)
public void spawnAllTiers(int maxNum)
{
if(GameController.trackingReady && !hasTriedSpawn)
{
hasTriedSpawn = true;
int numTimesTried = 0;
BoxCollider bounds = GetGrid ();
if (bounds != null) {
while (tiersSpawned.Length < maxNum && numTimesTried < 70) { //still has space
Tier t = getNextTier ();
Vector3 newPos = new Vector3 (UnityEngine.Random.Range(GetGrid ().bounds.min.x, GetGrid ().bounds.max.x), GetGrid ().bounds.min.y, UnityEngine.Random.Range(GetGrid ().bounds.min.z, GetGrid ().bounds.max.z));
//Vector3 newPos = CheckForEmptySpace (bounds.bounds);
if(GetGrid ().bounds.Contains(newPos)) //meaning not 200 so it is there
{
spawnTier (newPos, t);
}
numTimesTried++;
platformsSpawned = GameObject.FindObjectsOfType<Platform> ();
tiersSpawned = GameObject.FindObjectsOfType<Tier> ();
}
if(tiersSpawned.Length < maxNum)
{
print ("DIDNT REACH - maxed at "+tiersSpawned.Length);
}
}
}
//maybe check for num times trying, or if size of all spawned tiers is greater than area approx
}
//SPAWN NEXT TIER
public void spawnTier(Vector3 position, Tier t) //if run out of plats THEN we spawn up like tree house
{
print ("SUCCESS - spawn "+position+"SPHERE: "+Physics.CheckSphere(position, tierDist, 1 << 0));
// Vector3 pos = currentTier.transform.position; //LATER UNCOMMENT - would be the current tier spawning from
//TO TEST comment to this line ---------------------------------------------------------------------------
#if UNITY_EDITOR
Instantiate (t, position, Quaternion.identity);
anchorManager.AddAnchor(t.gameObject);
#else
//------------------------------------------------------------------------------------------
Instantiate (t, position, Quaternion.identity);
anchorManager.AddAnchor(t.gameObject);
#endif
}
This doesnt crash the device but spawns ALL in the same place. I cant understand why. If I do this, CHECKING for overlap:
public void spawnAllTiers(int maxNum)
{
if(GameController.trackingReady && !hasTriedSpawn)
{
hasTriedSpawn = true;
int numTimesTried = 0;
BoxCollider bounds = GetGrid ();
if (bounds != null) {
while (tiersSpawned.Length < maxNum && numTimesTried < 70) { //still has space
Tier t = getNextTier ();
//Vector3 newPos = new Vector3 (UnityEngine.Random.Range(GetGrid ().bounds.min.x, GetGrid ().bounds.max.x), GetGrid ().bounds.min.y, UnityEngine.Random.Range(GetGrid ().bounds.min.z, GetGrid ().bounds.max.z));
Vector3 newPos = CheckForEmptySpace (GetGrid ().bounds);
if(GetGrid ().bounds.Contains(newPos) && t) //meaning not 200 so it is there
{
spawnTier (newPos, t);
}
numTimesTried++;
platformsSpawned = GameObject.FindObjectsOfType<Platform> ();
tiersSpawned = GameObject.FindObjectsOfType<Tier> ();
}
if(tiersSpawned.Length < maxNum)
{
print ("DIDNT REACH - maxed at "+tiersSpawned.Length);
}
}
}
//maybe check for num times trying, or if size of all spawned tiers is greater than area approx
}
Works great in editor again, but completely freezes the device. Logs are not helpful, as I just get this every time, even though they aren't spawning in those positions:
SUCCESS - spawn (0.2, -0.9, -0.9)SPHERE: False
SUCCESS - spawn (-0.4, -0.9, 0.2)SPHERE: False
SUCCESS - spawn (0.8, -0.9, 0.2)SPHERE: False
SUCCESS - spawn (-0.4, -0.9, -0.8)SPHERE: False
SUCCESS - spawn (0.9, -0.9, -0.8)SPHERE: False
What the hell is happening - why would it freeze only on device like this?
Summary:
it sounds like you needed a short gap between each spawn.
(BTW a useful trick is, learn how to wait until the next frame - check out many articles on it.)
All-time classic answer for this
https://stackoverflow.com/a/35228592/294884
get in to "chunking" for random algorthims
observe the handy line of code at "How to get sets of unique random numbers."
Enjoy
Unrelated issue -
Could it be you need to basically wait a small moment between spawning each cube?
For a time in unity it's very simply Invoke - your code pattern would look something like this:
Currently ...
for 1 to 100 .. spawn a cube
To have a pause between each ...
In Start ...
Call Invoke("_spawn", 1f)
and then
func _spawn() {
if count > 70 .. break
spawn a cube
Invoke("_spawn", 1f)
}
Similar example code - https://stackoverflow.com/a/36736807/294884
Even simpler - https://stackoverflow.com/a/35807346/294884
Enjoy

Dodging-code uncertainty (Unity, no Unity physics)

So, I want to implement dodging which is something like a dash in a direction. It works pretty simple - if you move in a direction and press the button the character dodges there. The velocity should not matter for this, so that the dodging speed is always the same, no matter if you are running or standing and then pressing a direction + dodging. I've got something that seems to work but there are still problems left. It seems like that diagonal dodging is a bit too far in comparison to horizontal/vertical dodging and I tried to fix this. But I'm still not sure if it worked or not. In practice the character dodges and stuff but something still seems off, like it works pretty good with a controller but sometimes it's still wacky when using keyboard after standing still and then using dodge. The thing is - I'm not sure if the code I have is the best I could have or if there are still problems.
A good example of how it should work would be the dodging in Rune Factory 4.
Edit: If the problem lies in the Input Settings I could show them.
if (IsDodging == false)
{
Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
if (input.sqrMagnitude > 1) input.Normalize();
if (Input.GetButtonDown("Jump"))
{
// Jumping stuff I blended out
}
else if (Input.GetButtonDown("Block/Dodge") && input.x != 0 || Input.GetButtonDown("Block/Dodge") && input.z != 0) // To activate dodging
{
if (Time.time > Time_Start + DodgeCooldown) // Checks the cooldown
{
Time_Start = Time.time;
IsDodging = true;
dodge_direction = input;
if (dodge_direction.x > 0) { dodge_direction.x = 1; } // To fixate the distance traveled when dodging while ignoring how fast you are
if (dodge_direction.z > 0) { dodge_direction.z = 1; }
if (dodge_direction.x > 0 && dodge_direction.z > 0) { dodge_direction.Normalize(); } // To prevent diagonal dodging distance from becoming too big
}
}
else
{
// Walk.
transform.position += input * run_speed * Time.deltaTime;
}
}
else
{
transform.position += dodge_direction * dodge_distance;
distance_traveled += Vector3.Distance(transform.position, dodge_direction * dodge_distance) * Time.deltaTime;
if (distance_traveled > dodge_distance)
{
IsDodging = false;
dodge_direction = Vector3.zero;
distance_traveled = 0;
}
}

OnCollisionEnter is not working:

Please Guys help, I am new to Unity and programming:
I have a two Bouncing Ball, tag as BouncingBall1 and BouncingBall2, I want when a bullet hit both to destroy and if the time have not exceeded displaySecond and you have destroy the balls you win, but my problem is the OnCollisionEnter is not working. The part of wining is not working the rest are, my code fragment is below.
function OnCollisionEnter(col.collision) {
if ((displaySecond < 30) && (
col.gameObject.tag ==
BouncingBall1 == null &&
col.gameObject.tag ==
BouncingBall1 == null)) {
print("You have won");
}
}
col.gameObject.tag == BouncingBall1 == null
I think the problem is with the way you check if an object is destroyed. This isn't the way to do it. Also, you're checking if two identical lines of code are identical. So this will always return true if the display second is lower than 30.
Try changing it to
if ( (displaySecond < 30) &&
(col.gameObject.tag == "BouncingBall1") ) {
Debug.Log("You have won!")
}
It sounds like you want keep track of whether each ball has been destroyed and display "You have won" when both have been destroyed. This code is a little crude but should achieve this:
var ball1Destroyed = false;
var ball2Destroyed = false;
...
function OnCollisionEnter(col : Collision) {
if (col.gameObject.tag == "BouncingBall1") {
ball1Destroyed = true;
}
if (col.gameObject.tag == "BouncingBall2") {
ball2Destroyed = true;
}
if (displaySecond < 30 && ball1Destroyed && ball2Destroyed) {
Debug.Log("You have won");
}
}
This code assumes that the only collisions will be between bullets and balls (not between one ball and another), this can be done with collision layers.