Spawning several characters each with different item inventories

bbjones

Member
Game scenario is several different AI soldier types, each with different item loadouts.

On top of that the human player can play any of those character types, as well as any player (AI or human) can pick up any dropped weapon from any other player's kit. Think of a soldier picking up a dead enemy's gun.

What would be the general approach to doing this?

Would I?
  • Create a new Character via Character Manager for every possible character I will spawn? Each has a different model and may be different sizes.
  • Do I need to add and position every possible item model with every possible character via the Character Manager in the editor - and go through the item alignment process etc for every item?
  • After doing that for every character, create prefabs of the final version and spawn those prefabs into my scene when needed? Which also means I can remove all of that stuff from the scene hierarchy in the editor at design time.
With so much potentially redundant setup of items and characters, I'm mainly looking for the most efficient way to do this, that allows the easier way to update original prefabs to push out changes to everything I've created already.
 
With many characters your best bet is to take a look at the UMA integration to see how to generate the characters dynamically. This will allow you to easily create a new prefab for each character and speed up your workflow. Items can then be added at runtime which would also help.
 
Thanks for introducing me to UMA, while I don't need all features (expression, clothing changes etc) since I'm using fairly generic and simple low poly character models, I'll probably still use it for character sizing/random changes and performance gains.

While that should aid in character prefabs and spawning, I'm still looking to confirm effective ways to deal with item loadouts and item upgrades.

I can make an item prefab easy enough (following item pickup guides), but I need to have multiple characters in scene with a copy of that item as well as spawn in characters at runtime with their own copy of each item, and be able to pick up dropped items during gameplay. If I make a single item prefab I don't see a way to give that to characters as a default loadout (and ideally part of a loadout kit made up of several items for that characters class)?

I'm starting to think most of what I want/need to do is going to be done in code at spawn/runtime to add items to player's kits and position then correctly? Something like how item pickup works, but all done in code at spawn time to setup the correct item loadouts all based on individual item prefabs?

Does this approach make sense?
  • Create all items as pickup prefabs (set all shootable properties, ammo, clip size etc)
  • When spawning a character in scene, simulate the object ItemPickup methods to attach the desired items for that particular character, iterate on each item to adjust the item's FPS/TPS transform so it will be positioned correctly for that characters size/hand spacing etc.
  • I'll then need a cross reference of FPS/TPS transforms for every item adjusted for every character, and set that at runtime when spawning. Same sized models will all have the same item positioning, so I only need different values for different sized character models.
  • For dropped weapons, they end up with the standard object ItemPickup, but when picked up again by another character I'll still need to adjust the TPS/FPS transform values for whichever character picked up the item.
Other things I want to do which I think the above approach enables:
  • update an item prefab to change clip size - for example, the player upgrades all machine guns to have a clip increase from 50 rounds to 100 rounds, all new spawned instances will have the increased value while currently spawned instances retain whatever value they spawned with
  • Fairly easily create loudout sets for different characters in script, which could then be exposed to the player as a configurable item loudout kit along with individual item property changes (max ammo, clip size, grips, scopes, etc)
  • A dropped item should retain it's current properties (remaining ammo etc) so when picked up again it doesn't get reset to original values
 
I've got this working "good enough" for now using code from the scripts used for UMA/UCC Integration. Note that I'm not using UMA.

This is a fairly basic example that should work with all demo assets, or your own custom assets.
It assumes there will only be one UCC character in the scene at a time.
Next I need to figure out spawning multiple AI agents and a player character at the same time, but for now this solved my problem of wanting to spawn a character from code, and being able to choose from various item loadouts all using prefabs, instead of setting up character inventory through the Opsive character/item manager.

Setup:
  • Setup scene as usual - Opsive manager, camera, UI
  • Create UCC character prefabs as usual
    • Drag character into scene
    • Build character using Opsive Character manager
    • Save Opsive built character as a new prefab in project assets folder, remove character from scene. Repeat this for each different character.
  • Create Opsive Items and Pickup Objects as you normally would, but don't place anything in the scene.
  • You should now have Opsive character, item, and pickup prefabs to spawn at runtime, with nothing in the scene yet.
  • Create an empty game object and add the script below
  • Drag in the Opsive camera and setup the elements for Default Kits
Example of the inspector:
1572983257741.png

In my case I added a button to the UI with the click event wired up to the SpawnCharacter.SpawnACharacter() method to initiate the spawn test.

Here's the code, change the enums to match how many unique characters and item pickups you have, name them whatever you want.

C#:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Opsive.UltimateCharacterController.Inventory;
using Opsive.UltimateCharacterController.Objects.CharacterAssist;

[System.Serializable]
public class SpawnCharacter : MonoBehaviour
{
    [Tooltip("At run-time, select the type of character you want to spawn. Then call the SpawnACharacter() method, easy way is to wire that up to a UI Button click event.")]
    [Header("Testing")]
    public ECharacterType characterTypeToSpawn;
    [Tooltip("Drag in the Opsive camera you created in your scene with the Opsive Setup Manager.  Be sure to uncheck Init Character On Awake.")]
    public GameObject opsiveCamera;

    [Tooltip("One entry for every combination of character type and default loadout")]
    [Header("Default Kits")]
    public CharacterDefaultKits[] characterDefaultKits;

    private GameObject spawnedCharacter;

    // The code for adding ItemPickups is taken from the UMA Integration asset scripts found here https://opsive.com/downloads/?pid=923
    // Note that I'm not using anything to do with UMA, and does not require the UMA asset to function.
    // Spawns the character with the typical Unity.GameObject.Instantiate() method.
    public void SpawnACharacter()
    {
        // destroy currently spawned character if exists
        if (spawnedCharacter != null)
        {
            Destroy(spawnedCharacter);
        }

        Opsive.UltimateCharacterController.Camera.CameraController uccCam = opsiveCamera.GetComponent<Opsive.UltimateCharacterController.Camera.CameraController>();

        // loop through character kits to find the type that matches variable characterTypeToSpawn
        for (int c = 0; c < characterDefaultKits.Length; ++c)
        {
            if (characterDefaultKits[c].ECharacterType == characterTypeToSpawn)
            {
                // spawn the UCC character prefab
                spawnedCharacter = GameObject.Instantiate(characterDefaultKits[c].CharacterPrefab);
                // attach new character to Opsive camera
                uccCam.Character = spawnedCharacter;

                // get UCC inventory from new character
                var inventory = spawnedCharacter.GetComponent<InventoryBase>();
                if (inventory == null)
                {
                    return;
                }

                // add all ItemPickups for the new character type
                for (int i = 0; i < characterDefaultKits[c].ItemPickups.Length; ++i)
                {
                    if (characterDefaultKits[c].ItemPickups[i] == null)
                    {
                        continue;
                    }

                    characterDefaultKits[c].ItemPickups[i].DoItemPickup(spawnedCharacter, inventory, -1, true, true);
                }
            }
        }
    }
}

// this class represents all the default items for a single character type
[System.Serializable]
public class CharacterDefaultKits
{
    public ECharacterType ECharacterType;
    public GameObject CharacterPrefab;
    public ItemPickup[] ItemPickups;
}

// this class represents the different types of characters
[System.Serializable]
public enum ECharacterType
{
    CharacterType1,
    CharacterType2,
    CharacterType3
}
 
Last edited:
Thanks for sharing your code - I'll move this to the scripts section so it doesn't quickly get lost in the questions section. I think that I would handle this situation the same way :)
 
Top