After the comment above (I know these 2 comments have nothing to do with my animation problem, so bear with me), I suffered a very similar problem, where I was unable to accumulate a value. Instead of taking the static approach, though, I took the Interface approach with this one (I don’t understand interfaces much, so please, review this part for me and let me know if this works out or not).
My problem was, I wanted to get an ‘offset’ value that I attached to my ‘Animal.cs’ Script (it’s a custom code that I created for my animals, so they can hold valuable information that I can accumulate, like type, offset of projectile firing, etc), and I wanted to decouple the code a little bit, without having to rely on static variables
So, here’s what I did:
- I created a brand new Interface (I called the file for my unique interfaces as ‘External Interfaces’), called ‘IAnimal’, (for now) solely to get the offset values:
using UnityEngine;
public interface IAnimal
{
Vector3 GetProjectileOffset {get;}
}
- In ‘Animal.cs’, which holds the offset value that I want to get (and goes on all animals in my game scene), I implemented this interface, so I can have a hold of the offsets of all the animals:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace RPG.Animals {
public enum AnimalType
{
Horse,
Raven,
}
public class Animal : MonoBehaviour, IAnimal
{
[SerializeField] private AnimalType animalType;
public AnimalType Type => animalType;
[SerializeField] public Transform AnimalPlayerRangerCameraTransform;
[Tooltip("Is there any offset that's supposed to occur when firing a projectile from the back of this animal? Used in 'WeaponConfig.LaunchProjectile()' (freelook edition) to make sure the projectile doesn't accidentally hit the animal")]
[SerializeField] public Vector3 OnThisAnimalProjectileOffset;
public Vector3 GetProjectileOffset => OnThisAnimalProjectileOffset; // Implementing the 'IAnimal.cs' Interface rules
}
}
- I went to ‘LaunchProjectile’ in ‘WeaponConfig.cs’ (which I got from @Brian_Trotter 's RPG and Third Person merge course), and added an OPTIONAL parameter in the end of the parameters, of type ‘IAnimal’ (the interface), and officially set it to null
Inside the function, I check for it first before getting the code to act accordingly, as follows (this is no longer a 4-line function, it expanded because of my specific needs):
// for cases of firing a projectile when we don't have a target (freelook state). Also used when you're driving an animal:
public void LaunchProjectile(Transform rightHandTransform, Transform leftHandTransform, GameObject instigator, float damage, IAnimal animal = null)
{
Transform correctTransform = GetTransform(rightHandTransform, leftHandTransform);
Projectile projectileInstance;
if (AnimalMountManager.isOnAnimalMount && IsRangerAimingStaticClass.IsRangerAiming && animal != null)
{
// Compensation because on animals, the animations can get messy and the instantiation point can get terrible
// projectileInstance = Instantiate(projectile, correctTransform.position + new Vector3(0.5f, 0.5f, 0.5f) /* <-- convert to an 'AnimalOffset' Vector3 in 'Animal.cs', and refer to it from there */, Quaternion.identity);
Vector3 offset = animal.GetProjectileOffset;
projectileInstance = Instantiate(projectile, correctTransform.position + offset, Quaternion.identity);
Camera mainCamera = Camera.main;
Ray ray = mainCamera.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2, 0));
if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity))
{
projectileInstance.transform.LookAt(hit.point);
projectileInstance.transform.forward = ray.direction;
}
else
{
projectileInstance.transform.forward = ray.direction;
}
}
else
{
projectileInstance = Instantiate(projectile, correctTransform.position, Quaternion.identity);
projectileInstance.transform.forward = instigator.transform.forward;
}
projectileInstance.SetupNoTarget(instigator, damage);
Debug.Log($"Projectile Launched");
}
- In ‘Fighter.cs’, where I actually call the ‘LaunchProjectile.cs’ function, from ‘Shoot()’ (which is called from the animation event line), I added a line to get the type of animal, as follows:
IAnimal currentAnimal = AnimalMountManager.isOnAnimalMount ? GetComponent<PlayerOnAnimalStateMachine>().GetAnimal() /* only the player holds 'PlayerOnAnimalStateMachine.cs', so alls good */ : null;
(Note: I already had an animal getter in my ‘PlayerOnAnimalStateMachine.cs’ variant of my state machine, which only works when the player is mounting an animal, and replacing the original state machine in that case)
and then I plugged that value into my ‘Shoot → LaunchProjectile’ call:
if (targetObject != null)
{
// use the 'LaunchProjectile' function with 5 arguments (as we do have a target)
currentWeaponConfig.LaunchProjectile(rightHandTransform, leftHandTransform, targetObject.GetComponent<Health>(), gameObject, damage);
}
else
{
// use the 'LaunchProjectile' function with 4 arguments (as we don't have a target), the last one (added 14/6/2024) is to offset the arrows based on the animal being driven
currentWeaponConfig.LaunchProjectile(rightHandTransform, leftHandTransform, gameObject, damage, currentAnimal);
}
Quite the learning journey with this one…
I’ll repeat the last 2 steps to get the Aim Reticle on my screen to act properly as well
(I still have the animation problem from the title of this topic )