So I’m ripping my hair off atm (what’s left of it)
Basically I have 3 aim animations that I blend together to create smooth straight/up/down aiming. And I have a ‘gunTip’ transform at the tip of the character’s gun. The ‘forward’ of the tip is coming out of the gun’s barrel. This is where I shoot from.
When I fire, I cast a ray from the tip with the tip’s forward being the direction. The animations are handled from script (not root motion). For some reason, if I call the shoot method from OnAnimatorMove
, the raycast doesn’t seem to want to follow the tip’s forward when I aim up/down!
I made a 1 showing the problem, my code, and the two different aid-band fixes I made.
- The first fix is calling TryShoot
from the PlayerController’s Update,
and not OnAnimatorMove, it worked
pretty well, but of course without
an animation. - The second fix, just to prove that the animation has nothing to do with the problem, I created a
tipFwd
Vector3 inWeapon
, and assigned it to the gun’s tip in Update, and used that variable when I do raycast.
The first fix actually produces more accurate results than the second. Notice in my OnDrawGizmos I draw a red sphere (which I get its position from the shooting hit point) and a yellow sphere which I draw from the hit point I get from raycasting in OnDrawGizmos. What drives me crazy is that I’m using the “SAME” raycast both when I shoot and OnDrawGizmos, yet the red sphere doesn’t appear where it should, while the yellow one is placed appropriately…
Here’s my PlayerController’s Update and OnAnimatorMove:
private void Update()
{
if (animator)
{
animator.speed = animationSpeed;
animator.SetFloat("Speed", Input.GetAxis("Vertical"));
animator.SetBool("IsAiming", Input.GetMouseButton(1));
animator.SetBool("IsRunning", Input.GetKey(KeyCode.LeftShift));
}
transform.Rotate(0f, Input.GetAxis("Horizontal") * Time.deltaTime * rotationSpeed * 100f, 0f);
}
private void OnAnimatorMove()
{
var baseLayer = animator.GetCurrentAnimatorStateInfo(0);
var secondLayer = animator.GetCurrentAnimatorStateInfo(1);
Func<int, bool> baseIsInState = hash => baseLayer.nameHash == hash;
Func<int, bool> secondLayerIsInState = hash => secondLayer.nameHash == hash;
bool isAiming = Input.GetMouseButton(1) && secondLayerIsInState(aimState);
if (isAiming)
{
if (!resetAim)
{
resetAim = true;
animator.SetFloat("AimY", 0f);
}
animator.SetFloat("AimY", Mathf.Clamp(animator.GetFloat("AimY") + Input.GetAxis("Mouse Y"), -1f, 1f));
animator.SetBool("IsShooting", Input.GetMouseButton(0) && weapon.TryShoot());
}
else
{
resetAim = false;
}
// Movement...
}
And here’s my Weapon’s Shoot/TryShoot:
public bool TryShoot()
{
if (shooting conditions are not met)
{
return false;
}
Shoot();
return true;
}
private void Shoot()
{
// Sound, muzzle and ammo decreasing...
RaycastHit hit;
if (Physics.Raycast(gunTip.position, gunTip.forward, out hit, Distance, shootingMask))
{
dbgLastShot = hit.point; // this is how I determine the red sphere's position
// irrelevant code...
}
}
The problem doesn’t make any sense to me… But I have a good amount of certainty that it’s a gotcha related to Animator/Mecanim and/or OnAnimatorMove… If you have any idea I’d really appreciate it!
Thanks a lot!