Attack speed messing up animation - c#

if (Input.GetMouseButtonDown(0))
{
if (currentanim >= 3)
{
currentanim = 1;
}
if (swordanimactive == false)
{
if (swordblockanimactive == 1)
{
currentanim = currentanim + 1;
//the problem seems to be here
Swordcontroller.speed = attackspeed;
Swordcontroller.SetInteger("attackindex", currentanim);
Swordcontroller.SetTrigger("attack");
}
}
}
The problem is when I set the attack speed over 1 (regular speed), after a few clicks it just stops working. I have no idea what causes this and I don't know how to fix it since I just implemnted this new animation system. Also, the current animation is just because there are 3 sword animations. However, if I set it to only one animation it works perfectly fine. When I use 3 different animations it doesn't work.

First of all, I do not really know how you set up the animator, but I recommend this structure.
Multi Animation Animator
Has Exit Time

Maybe you can create some dataType like
public class MeleeAttackInstance
{
public string animationName;
public float animationSpeed;
public float modifiedSpeed;
public void ApplySpeedModifier(int queCount)
{
animationSpeed*(queCount +1);
}
}
And make a queue of this attacks. When craracter should attack, you place item in queue and get the top one applying modified speed.

Related

How to reverse an If Statement when conditions are no longer met

In my Unity project, I have an if statement set-up where if the conditions are true, my character's box collider will shrink to a specific value when crouching (along with movement speed change, turning speed, etc). And when my character is not crouching anymore, the box collider (along with the other parameters I mentioned) will return to its original size in the else statement.
However, I don't want to keep track of every parameter I change/need to reverse across all my scripts. In the future, my character's base parameters may change, which'll cause me to have to go back and change every else statement I ever make involving changing my character to its default parameters. I can create variables to store my base parameters so I wouldn't have to worry about copy-pasting values if I change them in Unity. But it'll eventually snowball into spaghetti-code territory if I do this method for every parameter I create/change in my scripts.
Is there a simpler way to code in C# where if an If statement is no longer true, it'll reverse all changes it made?
Psuedo code:
float height = 10.42f;
float movementSpeed = 95.89f;
if (condition1==true && condition2==true){
height = 3.5f;
movementSpeed = 40.125f;
}
*code to reverse all changes the If Statement made when it stops being true*
Is there a simpler way to code in C# where if an If statement is no longer true, it'll reverse all changes it made?
No. If you want to revert to an earlier state you need to save that state in advance, e.g. in variables as you propose in the question.
It's look like buff system , it can be todo and undo player status , And it's expandability , So you can design a buffsystem to do it like this:
public interface IBuff
{
void Do(Player player);
void UnDo(Player player);
}
public BuffAddHeight : IBuff
{
public Do(Player player)
{
player.Height += 100;
}
public UnDo(Player player)
{
player.Height -= 100;
}
}
public BuffSeed : IBuff
{
public Do(Player player)
{
player.speed += 100;
}
public UnDo(Player player)
{
player.speed -= 100;
}
}
public class Player
{
// by the way , you can design a buff container to manager your buff.
public void AddBuff(IBuff buff) { buff.Do(this); }
public void RemoveBuff(IBuff buff) { buff.UnDo(this); }
}

Interrupting a Jump Animation in windows form

So far, I have a jump animation. It uses an integer "jump" to loop through an array of images that create a jump animation, additionally, depending on what number "jump" is,the height "PositionY" will be increased or reduced and when jump hits 10, the animation ends..... this is jump animation code
public Bitmap Jump_Frame2Draw()
{
Jump_Frames = new Bitmap[] { Jump_1, Jump_2, Jump_3, Jump_4, Jump_5, Jump_6, Jump_7,Jump_7,
Jump_8, Jump_8 };
if (jump < Jump_Frames.Length)
{
if (jump <= 3)
{
PositionY -= 30;
}
else if (jump == 8 || jump == 10)
{
PositionY += 0;
}
else
{
PositionY += 24;
}
jumpFrame = Jump_Frames[jump];
jump++;
if (jump == 10)
{
jumpTimer.Stop();
isJumping = false;
jump = 0;
standTimer.Start();
Invalidate();
}
}
tracer = jumpFrame.GetPixel(1, 1);
jumpFrame.MakeTransparent(tracer);
isJumping = true;
return jumpFrame;
}
By using a timer and a paint event, I'm able to simply call this method every x seconds inorder to draw it when I press my designated jump key... Now my problem is lets say I'm in the middle of the jump animation, and I want to go back up .How do I do I go about that. Think of it as a double jump. Also, the jump and height(PositionY) are directly correlated. So if jump is 0,1,2 or 3, then height is 214 - (jump + 1) * 30). Else if jump is (5-9) height is 94 + (jump - 4) * 24). So the maximum height that any images will ever be drawn is 94.(its windows form so up is down and down is up... (0,0) is located at top left).
///////////
For a visual perspective, this is similar to my jump animation. This one is a little shorter in terms of time but it the best I could find.
Jump animation: https://media.giphy.com/media/wXervlFEqohO0/giphy.gif
now imagine this guy was ironman, he uses his jet boosters to jump up, but now while still in the air, he decided to just go straight up.
I think you'd save yourself alot of trouble if you move most of the animation-specific code to a dedicated JumpAnimation class. Pass all information required for the specific animation in the constructor:
class JumpAnimation
{
public JumpAnimation(int howHigh)
{
...
}
}
Responding to a click on the space bar, you know you have to create a JumpAnimation. But while your timer is ticking, you don't want to deal with the specifics of a jump or jetpack animation - you want an IAnimation interface that allows you to continue the animation whatever it was. And when you acitvate the jetpack, you just want to replace whatever animation is currently active with a JetPackAnimation:
In your form:
private IAnimation currentAnimation = null;
And the IAnimation interface:
public interface IAnimation
{
// get the bitmap at the time relevant to the animation start
Bitmap GetBitmapAt(int time);
}
You can reuse alot of the code you shared in your question when you implement IAnimation in your JumpAnimation.
Now instead of returning just the Bitmap, you can create a class that holds more information about the "current step in the animation:
public class AnimationStep
{
public Bitmap Bitmap { get; set; }
// the y-offset
public int OffsetY { get; set; }
// indicates whether this was the last step of the animation
public bool Completed { get; set; }
// a jump animation can be interrupted by a jetpack animation, but a DieAnimation cant:
public bool CanBeInterrupted { get; set; }
...
}
I hope you get the idea. I'm not claiming this is the only or best way to tackle your problem, but sometimes another person's view on the matter helps thinking outside the box.

Triggering an animation from a script related to the value of a slider

I have a script that gives me the normalized value of a slider which is set to animationTime
Along this slider I'd like some little pop ups to appear to indicate important dates to the user when they happen, but just having them 'appear' is super boring and doesn't catch the eye, so I'd like a little toast like pop-up animation to happen.
How do I trigger this animation upon reaching the correct point on the slider?
So far to just get them to appear I'm using this script.
float t = animationTime;
if (0.256f < t)
{
pilingFinished.gameObject.SetActive(true);
}
else
{
pilingFinished.gameObject.SetActive(false);
}
if (0.39f < t)
{
basementFinished.gameObject.SetActive(true);
}
else
{
basementFinished.gameObject.SetActive(false);
}
}
From my limited knowledge I'm sure this can be cleaned up as well, considering there are going to be multiple toast pop-ups on the timeline to indicate many different important dates to be looking at.
Many thanks
There's a fair amount of setup to this solution, but it's all relatively simple logic. I'm using two classes, owe that automatically positions the elements along the slider and handles the OnChange event of the slider, and the other which controls the animator of the element.
TimelineController.cs
[RequireComponent(typeof(Slider))]
public class TimelineController : MonoBehaviour
{
private RectTransform m_transform;
private Slider m_slider;
private TimelineElement[] m_elements;
private Vector3 m_tempPosition;
public void Start()
{
m_transform = GetComponent<RectTransform>();
m_slider = GetComponent<Slider>();
m_elements = GetComponentsInChildren<TimelineElement>();
m_slider.maxValue = m_elements.Length - 1;
m_tempPosition = m_elements[0].GetComponent<RectTransform>().localPosition;
for(int element = 0; element < m_elements.Length; element++)
{
m_tempPosition.x = (m_transform.rect.width - 20f) * ((float)element / (m_elements.Length - 1));
Debug.Log(m_transform.rect.width);
m_elements[element].GetComponent<RectTransform>().localPosition = m_tempPosition;
}
m_elements[0].SetVisible(true);
}
public void OnChange()
{
m_elements[(int)m_slider.value].SetVisible(true);
for (int element = 0; element < m_elements.Length; element++)
{
if (element != (int)m_slider.value)
m_elements[element].SetVisible(false);
}
}
}
To position all the elements, the number of TimelineElement components in the children is got, the slider's maxValue is set to the number of elements retrieved, and an initial Vector3 of the element is got.
(m_transform.rect.width - 20f) * ((float)element / (m_elements.Length - 1));
Each position is determined based on a percentage (current element divided by the length of the element array), and multiplying this by the width of the slider minus 20f (the width of the handle).
TimelineElement.cs
[RequireComponent(typeof(Animator))]
public class TimelineElement : MonoBehaviour
{
private Animator m_animator;
public void Start()
{
m_animator = GetComponent<Animator>();
}
public void SetVisible(bool p_visible)
{
m_animator.SetBool("Visible", p_visible);
}
}
As previously described, this simple sets a boolean in the animator to true or false, causing the relevant animation to play. All that's left is to setup your hierarchy similar to the example above with a bool Visible in the animator, and set your slider Whole Numbers to true.
Hope this helped.

How to start more than one animation with unity animator?

I have an animatormanager able to create run time animation from 1 animation (start frame, end frame and delay then the speed is calculated, will do morphing and more later). My unity version is 5.3.1f1
Everything work fine, some stuff are not done but are optional. The animator can queue requested animation to prevent interupting the current one.
The thing is, I can only start 1 time an animation with an object. The code to launch the next animation is exactly the same but there is just nothing to do.
Event if its 2 time the same animation with the same animation data
All formula are good and tested.
I did intensive debugging with breakpoint to make sure everything is fine at any point
Is there something to prevent me from starting an animation 2 time on an object one after an other?. I have no error or warning at all. The first animation work fine no matter the settings I put in my AnimData struct, but the second time, nothing happen.
Here is the essential:
public int? startAnim(int index)
{
if(index < animIndex.Count)
{
startAnim(animIndex[index]);
}
return null;
}
//private because the struct is internal, this make sure the animator keep control of the list.
private int? startAnim(AnimData animD)
{
if(locked)
{
#if UNITY_EDITOR
Debug.Log("anim locked");
#endif
return null;
}
//current anim (queue anim) not finished
if(endTime > Time.time)
{
if(canQueue)
{
addToQueue(animD);
return animDataQ.Count;
}
else
{
return null;
}
}
else
{
endTime = Time.time + animD.TotalTime;
StartCoroutine(animManager(animD));
return 0;
}
return null;
}
#endregion anim starters
private IEnumerator animManager(AnimData animData)
{
animator.speed = Mathf.Abs(animData.calculateSpeed(animLength, AnimType.main, currentKey).Value);
//animator.Play(0,0, animData.StartKey/animLength);
if(animData.AnimSpeed > 0)
{
animator.Play(0,0, animData.StartKey/animLength/2);
}
else
{
//animator.Play(0,0, (animLength * 2) - (animData.StartKey/animLength));
animator.Play(0,0, (((animLength*2) - animData.StartKey)/(animLength * 2)));
}
//animator.Play(0,0, (animData.AnimSpeed > 0) ? animData.StartKey/animLength : ((animLength * 2) - (animData.StartKey/animLength)));
yield return new WaitForSeconds(animData.Delay);
animator.Stop();
yield return null;
endAnim();
}
private void addToQueue(AnimData animD)
{
animDataQ.Enqueue(animD);
endTime += animD.TotalTime;
queueTime += animD.TotalTime;
}
private void endAnim()
{
if(canQueue && animDataQ.Count > 0)
{
StartCoroutine(animManager(animDataQ.Dequeue()));
}
}
Thanks for your time.
i found a work around.
I dont want to mark it as an accepted solution since its not "clean" in my opinion
there is certainly some kind of problem with the animator for some specific case like mine.
my solution was to use animator.speed = 0 instead of animator.stop();
everything worked instantly with that small change
i will ask my question to the unity forum because there is something strange for sure

Unity3D: Adding charged force in relation to position

I am trying to make a game which "kind of" simulates the shooting of the "worms" game. The player can choose the position (circular) of an object and then, the force that is applied to the object should move in the direction its pointing towards. I tried using the AddForce(transform.right) code, but it would just go to the right. (2D BoxCollider and RigidBody2D)
Then comes the hard part, making the player choose the force by charging the power. When the player holds down the "f" key, I want the power to go up to a certain point. Once it reaches that point, I want it to go down again and then up again, so the player can choose the power he wants. I have no idea how to go about this.
It's been awhile since I've did Unity coding, so there may be some minor errors with my syntax but it should give you an idea of how to accomplish this. Your best bet for the loop is to use a coroutine to not block the main thread.
in Update() check for 'on key down' for F and start this coroutine:
IEnumerator Cycle()
{
float max = 10.0f;
float min = 1.0f;
float interval = 0.5f;
do
{
for(int i=min;i<max;i++)
{
PowerValue = i;
yield return new waitforseconds(interval);
if(!input.getkey(f))
break;
}
for(int i=max;i>min;i--)
{
PowerValue = i;
yield return new waitforseconds(interval);
if(!input.getkey(f))
break;
}
} while(input.getkey(f));
}
And back in update() use that powerValue with getKeyUp(f)
And here is PowerValue setup as a parameter that prevents code from setting the max and min outside of a 1 to 10 range (configurable)
private float powerValue = 1.0f;
public float PowerValue
{
get { return powerValue; }
set {
if(value>10f)
powerValue=10f;
else if (value<1f)
powerValue=1f;
else
powerValue=value;
}
}

Categories

Resources