Instantiate as Child not working

Hi guys, im trying to instantiate a sword in my player hand, it works fine but is not a child of my playerhand parent, can anyone help plz? this is the code

using UnityEngine;
using System.Collections;

public class PlayerWeaponController : MonoBehaviour
{
    public GameObject playerHand;
    public GameObject EquippedWeapon{ get; set;}

    IWeapon equippedWeapon;
    CharacterStats characterStats;

    void Start()
    {
        characterStats = GetComponent<CharacterStats> ();
    }

    public void EquipWeapon(Item itemToEquip)
    {
        if (EquippedWeapon != null)
        {
            characterStats.RemoveStatBonus (EquippedWeapon.GetComponent<IWeapon>().Stats);
            Destroy (playerHand.transform.GetChild (0).gameObject);
        }

        EquippedWeapon = (GameObject)Instantiate (Resources.Load<GameObject>("Weapons/" + itemToEquip.ObjectSlug),
            playerHand.transform.position, playerHand.transform.rotation);
        equippedWeapon = EquippedWeapon.GetComponent<IWeapon> ();
        equippedWeapon.Stats = itemToEquip.Stats;
        EquippedWeapon.transform.SetParent (playerHand.transform);
        characterStats.AddStatBonus (itemToEquip.Stats);
        Debug.Log(equippedWeapon.Stats[0].GetCalculatedStatValue());
    }

    public void PerformWeaponAttack()
    {
        equippedWeapon.PerformAttack ();
    }
}

You may find it easier to have all the weapons pre-parented in the editor, starting deactivated, and then activate or deactivate them as necessary. That way you dont have to worry about position, rotation, or creating and destroying on the fly.

What do you observe happening? Does the weapon get parented to anything?

Try adding a false second parameter to the SetParent() call.

EquippedWeapon.transform.SetParent (playerHand.transform, false);

That forces the child to use its local position/orientation only, and ignore where it happened to be in the world immediately before parenting. Personally, I find that you almost always want to pass false to SetParent(), at least when creating new objects. But when taking something that already exists and making it a child of an object, it might be appropriate to pass SetParent() a true second parameter (which is the default when you specify no second parameter).

2 Likes

The weapon just instantiate at the end of hierarquie but not as child of anything

Are you getting any errors? Try using Debug.Log to print out the object names to make sure the parenting is happening correctly. Is there any other code handling parenting or potentially destroying the parent or setting it to null?

Also, could you simplify this:

Destroy (playerHand.transform.GetChild (0).gameObject);

to this?

Destroy (EquippedWeapon);

Doesnt fix the problem, it still instantiate in place but not as child

Dont work too… i m getting an error yes, but its about the weapon stats that i couldnt find the problem yet too… but nothing to be with the instantiation i guess. and this only weapon when i change my cube model from a real model… then i try back to cube model but never work properly again.

Does the error happen in this file?

If it happens on any of the lines before the parenting, that could be the reason the parenting isn’t happening.

Try this:

public void EquipWeapon(Item itemToEquip) {
    if(EquippedWeapon != null) {
        characterStats.RemoveStatBonus(EquippedWeapon.GetComponent<IWeapon>().Stats);
        Destroy(playerHand.transform.GetChild(0).gameObject);
    }

    EquippedWeapon = (GameObject)Instantiate(Resources.Load<GameObject>("Weapons/" + itemToEquip.ObjectSlug),
        playerHand.transform.position, playerHand.transform.rotation);
    EquippedWeapon.transform.SetParent(playerHand.transform);

    equippedWeapon = EquippedWeapon.GetComponent<IWeapon>();
    equippedWeapon.Stats = itemToEquip.Stats;
    characterStats.AddStatBonus(itemToEquip.Stats);
    Debug.Log(equippedWeapon.Stats[0].GetCalculatedStatValue());
}

Yes in line 12… damm every single time i try restart my prototype test i get all kinds of problems :frowning: 1st the click to move interfere with all kinds of stuff, then animations and even this simple this… im to newbie yet but this get me frustrated some time…

Don’t get frustrated, you will always run into roadblocks. It’s just the way it is when learning something new. Think of this as an opportunity to improve your debugging skills, as well as learn a thing or two to avoid this in the future.

So this line is the culprit:

equippedWeapon.Stats = itemToEquip.Stats;

That means that something here is null. Let’s find out what is null.

public void EquipWeapon(Item itemToEquip) {
    if(EquippedWeapon != null) {
        characterStats.RemoveStatBonus(EquippedWeapon.GetComponent<IWeapon>().Stats);
        Destroy(playerHand.transform.GetChild(0).gameObject);
    }

    EquippedWeapon = (GameObject)Instantiate(Resources.Load<GameObject>("Weapons/" + itemToEquip.ObjectSlug),
        playerHand.transform.position, playerHand.transform.rotation);
    equippedWeapon = EquippedWeapon.GetComponent<IWeapon>();

    if(equippedWeapon == null) {
        Debug.Log("new weapon missing IWeapon component");
        return;
    } else if(equippedWeapon.Stats == null) {
        Debug.Log("new IWeapon component has no stats");
        return;
    }

    if(itemToEquip.Stats == null) {
        Debug.Log("tried to equip weapon with no stats");
        return;
    }

    equippedWeapon.Stats = itemToEquip.Stats;

    EquippedWeapon.transform.SetParent(playerHand.transform);
    characterStats.AddStatBonus(itemToEquip.Stats);
    Debug.Log(equippedWeapon.Stats[0].GetCalculatedStatValue());
}
1 Like

Yes that true, im i dont know debug very well… with ur help i get that new weapon missing iweapon component…

Alright, so check your prefab in the Resources folder. Make sure it has a component that implements IWeapon (assuming it’s an interface).

Now im feeling like a dumb -.- i bet i dont attach the iweapon script to it.

Exaclty i dont have sword script in the weapon but now i get that new iweapon component has no stats in debug… but i dont get the error now on line 18 of this script

using UnityEngine;
using System.Collections.Generic;

public class CharacterStats : MonoBehaviour
{
    public List<BaseStats> stats = new List<BaseStats>();

    void Start()
    {
        stats.Add (new BaseStats(4, "Strenght", "Your attack power."));
        stats.Add (new BaseStats(2, "Vitality", "Your vitality level."));
    }

    public void AddStatBonus(List<BaseStats> statBonuses)
    {
        foreach(BaseStats statBonus in statBonuses)
        {
            stats.Find (x => x.StatName == statBonus.StatName).AddStatBonus (new StatsBonus (statBonus.BaseValue));
        }
    }

    public void RemoveStatBonus(List<BaseStats> statBonuses)
    {
        foreach(BaseStats statBonus in statBonuses)
        {
            stats.Find (x=> x.StatName == statBonus.StatName).RemoveStatBonus(new StatsBonus(statBonus.BaseValue));
        }
    }
}

And i hv this 2 more scripts

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class BaseStats : MonoBehaviour
{
    public List<StatsBonus> BaseAdditives { get; set; }

    public int BaseValue { get; set; }
    public string StatName { get; set; }
    public string StatDescription { get; set; }
    public int FinalValue { get; set; }

    public BaseStats(int baseValue, string statName, string statDescription)
    {
        this.BaseAdditives = new List<StatsBonus> ();
        this.BaseValue = baseValue;
        this.StatName = statName;
        this.StatDescription = statDescription;
    }

    public void AddStatBonus(StatsBonus statBonus)
    {
        this.BaseAdditives.Add (statBonus);
    }

    public void RemoveStatBonus(StatsBonus statBonus)
    {
        this.BaseAdditives.Remove (BaseAdditives.Find(x => x.BonusValue == statBonus.BonusValue ));
    }

    public int GetCalculatedStatValue()
    {
        this.FinalValue = 0;
       
        this.BaseAdditives.ForEach (x => this.FinalValue += x.BonusValue);
        this.FinalValue += BaseValue;

        return FinalValue;
    }
}
using UnityEngine;
using System.Collections;

public class StatsBonus
{
    public int BonusValue {    get; set; }

    public StatsBonus(int bonusValue)
    {
        this.BonusValue = bonusValue;
        Debug.Log ("New stat bonus initiated.");
    }
}

And ty. Sry for taking your time

Try not to focus on the end result, just focus on fixing each error one at a time. It’s possible that fixing one error will fix others as well.

So you say that you’re seeing “new IWeapon component has no stats” in the log now. That’s okay, because that is printing out before you assign the stats so it must be null. That also means you’re getting past the previous Debug statement, so IWeapon is no longer null.

Try this and see if it still outputs that:

public void EquipWeapon(Item itemToEquip) {
    if(EquippedWeapon != null) {
        characterStats.RemoveStatBonus(EquippedWeapon.GetComponent<IWeapon>().Stats);
        Destroy(playerHand.transform.GetChild(0).gameObject);
    }

    EquippedWeapon = (GameObject)Instantiate(Resources.Load<GameObject>("Weapons/" + itemToEquip.ObjectSlug),
        playerHand.transform.position, playerHand.transform.rotation);
    equippedWeapon = EquippedWeapon.GetComponent<IWeapon>();

    equippedWeapon.Stats = itemToEquip.Stats;

    if(equippedWeapon.Stats == null) {
        Debug.Log("new IWeapon component has no stats");
        return;
    }

    EquippedWeapon.transform.SetParent(playerHand.transform);
    characterStats.AddStatBonus(itemToEquip.Stats);
    Debug.Log(equippedWeapon.Stats[0].GetCalculatedStatValue());
}

It doesn’t debug nothing so the new iweapon component has the stats, but the error persists and seems to be in the list of statBonus

this is the full error: and maybe im readung it wrong or not understanding whats going on but it points to 3 diferente scripts??

Yes, that is called the stack trace, and those 3 scripts are which bits of code were run before the error happened. They’re clues to help you track down the bug.

The actual object that is null is on line 18 of CharacterStats.cs. PlayerWeaponController on line 51 makes a call to CharacterStats, and InventoryController on line 23 calls to PlayerWeaponController.

Line 18 of CharacterStats.cs is this:

stats.Find (x => x.StatName == statBonus.StatName).AddStatBonus (new StatsBonus (statBonus.BaseValue));

So just like before, lets change the function to catch what is really null and where it’s coming from:

Try this:

public void AddStatBonus(List<BaseStats> statBonuses) {
    if(statBonuses == null) {
        Debug.Log("CharacterStats -> AddStatBonus: parameter list null");
        return;
    }

    if(this.stats == null) {
        Debug.Log("CharacterStats: class variable 'stats' is null");
        return;
    }
 
    foreach(BaseStats statBonus in statBonuses) {
        stats.Find(x => x.StatName == statBonus.StatName).AddStatBonus(new StatsBonus(statBonus.BaseValue));
    }
}

It’s possible that PlayerWeaponController is passing null into “AddStatBonus”. I haven’t seen your PlayerWeaponController, but it’s also possible that InventoryController is passing null to PlayerWeaponController.

So follow those breadcrumbs and track down what is null and why.

It doesn’t debug nothing, so none of them are null… :confused:

Alright, we’re eliminating sources of the error. Since those things aren’t null, that means that the other files probably are not the problem.

There are a some more things we can check for within the function.

Try this:

public void AddStatBonus(List<BaseStats> statBonuses) {
    if(statBonuses == null) {
        Debug.Log("CharacterStats -> AddStatBonus: parameter list null");
        return;
    }

    if(this.stats == null) {
        Debug.Log("CharacterStats: class variable 'stats' is null");
        return;
    }

    foreach(BaseStats statBonus in statBonuses) {
        if(statBonus == null) {
            Debug.Log("a stat within statBonuses list is null");
            return;
        }

        BaseStats baseStats = stats.Find(x => x.StatName == statBonus.StatName);

        if(baseStats == null) {
            Debug.Log("could not find matching statname to " + statBonus.StatName +" in 'stats'");
            return;
        }

        baseStats.AddStatBonus(new StatsBonus(statBonus.BaseValue));
    }
}

Hum, at least im learning something about debug :slight_smile: and changing this:

            stats.Find (x => x.StatName == statBonus.StatName).AddStatBonus (new StatsBonus (statBonus.BaseValue));

to this disapears with the error :slight_smile:

BaseStats baseStats = stats.Find(x => x.StatName == statBonus.StatName);

i just dont get where is the error in that line… :stuck_out_tongue:

and i get this debug: a stat within statBonuses list is null but i think its normal cuz we just add the stats after right? or thats the error? cuz now i get debugg the value of 6 (the stats i add in start function)

I don’t know exactly how your stat system works or what is supposed to be happening here, so it’s hard for me to tell you what is wrong with it.

If “statBonus” is null in the foreach loop, then you can’t access “statBonus.StatName” in the next line.

That also means that the problem may be from those other files, passing a list with null values to the AddStatBonus function.

If any of the entries in the class variable “stats” is null, then trying to do “stats.Find(x => x.StatName” won’t work because x is null.

Basically you have to make sure that you prevent null objects, or check if they’re null before trying to get something from them.

1 Like