0
\$\begingroup\$

I'm currently working in Unity building a game inspired by the niche DS game, Dragon Quest Rocket Slime. It's a Zelda-like forced-perspective top-down game where the primary combat mode is you physically running around on a tank to throw ammo into cannons to fire them down 'lanes', almost like a real-time card battler in the veins of the modern Clash Royale.

Screenshots of Dragon Quest Rocket Slime

The problem is, I don't know how the game should handle the 'firing lanes' due to the fact that player characters and crewmates can ALSO be fired out of cannons. When they reach the other end, they'll land in the enemy ship to cause mayhem, steal ammo or sabotage their ammo dispensers.

I'm fairly rusty at programming, but my initial thoughts were creating a separate UI-element to represent the 'firing lanes' (which, in the initial DS game, was visualized through the top screen) that would use tiny sprites to simulate when ammo has reached the other side or not (and could be shot down if two opposing ammo collided), applying the relevant damage or effects upon reaching the end successfully.

The issue with that is twofold - I'm currently not sure HOW to build this system due to how many moving parts it has - defining an ammo class would be somewhat straightforward, but getting the cannon to take the ammo, spawn the ammo in the flight path with the stats the ammo has and simulate all of it, I don't quite know where to even begin as I'm still in the process of building the core movement systems and the all-important 'actual ability to pick up things and throw them into the cannons'.

The second issue is with the player characters and crewmates doubling as ammunition. I imagine I could probably make the cannons interact with the player characters differently, but the issue is how I can also apply some ammo properties to them as well in this theoretical 'the cannons turn ammo into sprites' situation. Some player characters could even have special effects when fired out of a cannon, making the difference a bit more complicated. Could I just... apply the ammo class to player characters too that activate when they're put into a cannon?

What's more is, in the original DS game, if a player character was shot down - they don't disappear like ammo, they simply fall to the ground and take some damage. Unlike the ammo, they can't be despawned so easily, and, IDEALLY, they'd also land on the ground proportional to how far they've travelled in a firing lane.

\$\endgroup\$
1

1 Answer 1

0
\$\begingroup\$

Whenever you want to be able to do similar things with different objects, you should create a reusable component.

As an analogy, think about how you typically add physics to a GameObject. Whether that object is a crate or a beach ball or a grenade, you'll probably start by adding a Rigidbody component and some type of Collider component. The Rigidbody and Collider components don't care what they're attached to.

So, in regards to your question - you should make a reusable component that has all of the functions you need for any kind of ammo. Then you can attach this component to any object that can serve as ammo, whether it's a cannonball or a character or something else.

I don't know your exact needs, so here's an example that probably doesn't do exactly what you want:

public class CannonAmmoEvent : UnityEvent<CannonAmmo> {}
public class CannonAmmoImpactEvent : UnityEvent<CannonAmmo, Collider> {}
public class CannonAmmo : MonoBehaviour {
    [SerializeField] private ParticleSystem firedEffect;
    [SerializeField] private ParticleSystem impactEffect;
    [Min(0)]
    [SerializeField] private int damage = 10;

    [SerializeField] private CannonAmmoEvent onLoaded = new CannonAmmoEvent()
    public CannonAmmoEvent OnLoaded => onLoaded;
    [SerializeField] private CannonAmmoEvent onFired = new CannonAmmoEvent()
    public CannonAmmoEvent OnFired => onFired;
    [SerializeField] private CannonAmmoImpactEvent onImpact = new CannonAmmoImpactEvent()
    public CannonAmmoImpactEvent OnImpact => onImpact;
    
    public void Load() {
        onLoaded.Invoke(this);
    }

    public void Fire() {
        if (firedEffect != null) {
            Instantiate(firedEffect, transform.position, Quaternion.identity);
        }
        onFired.Invoke(this);
    }

    void OnCollisionEnter(Collision col) {
        if (impactEffect != null) {
            Instantiate(impactEffect, transform.position, Quaternion.identity);
        }
        var health = col.collider.GetComponent<Health>();
        if (health != null) health.ApplyDamage(damage);
        onImpact.Invoke(this, col.collider);
    }
}

Notice that I included UnityEvents that are invoked when the ammo is fired and when it impacts something. You can use these events to call code in other scripts that adds additional functionality. For example:

public class Character : MonoBehaviour {
    [SerializeField] private Animator animator;
    //lots of other stuff goes here
    //[...]
    
    //called by onLoaded event on my CannonAmmo component
    public void OnLoaded(CannonAmmo ca) {
        animator.SetTrigger("CurlIntoBall")
    }
    //called by onImpact event on my CannonAmmo component
    public void OnImpact(CannonAmmo ca, Collider collider) {
        var ship = collider.GetComponentInParent<Ship>();
        if (ship != null) {
             LandOnShip(ship);
        }
    }
    private void LandOnShip(Ship ship) {
        animator.SetTrigger("Uncurl");
        //put other appropriate logic here
    }
}

In some cases, you find it convenient to use inheritance - create other classes that extend CannonAmmo with additional/different functionality.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .