'Object Reference Not Set... Arm Chain Generator Not Working

So this one is a bit convoluted.

It started off with trying to learn kinematics for procedural animation. Then I went on a tangent about generating thicker lines. Now I'm trying to produce a program that generates a chain of inter-connected lines made out of DrawSpheres with variable length/angle/resolution.

I had the original single line functioning perfectly. But I can not get the program to generate more. Each line is generated at the end target of the previous line, but there seems to be no starting object to reference. What do I change?

The individual line code:

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

public class Arm
{
    public GameObject joint;

    [Range(0, 10), HideInInspector]
    public float length;

    [Range(-360, 360), HideInInspector]
    public float angle;

    [HideInInspector]
    public Transform origin;

    [Range(0, 2560), HideInInspector]
    public int density;

    [Range(0, 256), HideInInspector]
    public float thickness;

    public Vector3 Target()
    {
        Vector3 target = new Vector3(0, 0, 0);

        target.x = origin.position.x + Mathf.Cos(this.angle) * this.length;
        target.y = origin.position.y + Mathf.Sin(this.angle) * this.length;

        return target;
    }

    public Arm(float length, float angle, Vector3 origin, int resolution, float thickness, Vector3 target)
    {
        this.length = length;
        this.angle = angle;
        this.origin.position = origin;
        this.density = resolution;
        this.thickness = thickness;

    }

    public void GenerateLine()
    {
        Vector3[] lineSegments = new Vector3[density];
        float segmentLength = length / lineSegments.Length;

        lineSegments[0] = (origin.position);

        for(int i = 1; i < lineSegments.Length; i++)
        {
            lineSegments[i].x = lineSegments[i - 1].x + Mathf.Cos(this.angle/57.3f) * segmentLength;
            lineSegments[i].y = lineSegments[i - 1].y + Mathf.Sin(this.angle/57.3f) * segmentLength;

            Gizmos.color = Color.black;
            Gizmos.DrawSphere(lineSegments[i], thickness / 1000);
        }

    }
}

The Chain manager code

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

public class ArmChain : MonoBehaviour
{
    [Range(0, 5)]
    public int chainLength;

    [Range(0, 10)]
    public float length;

    [Range(-360, 360)]
    public float angle;

    public Transform origin;

    [Range(0, 2560)]
    public int resolution;

    [Range(0, 256)]
    public float thickness;

    public Vector3 Target()
    {
        Vector3 target = new Vector3(0, 0, 0);

        target.x = this.transform.position.x + Mathf.Cos(this.angle) * this.length;
        target.y = this.transform.position.y + Mathf.Sin(this.angle) * this.length;

        return target;
    }

    public Transform jointOrigin;

    [SerializeField, HideInInspector]
    public Arm[] arms;

    private void OnDrawGizmos()
    {
        Initialize();
        GenerateChain();
    }


    void Initialize()
    {
        Arm[] arms = new Arm[chainLength];

        for (int i = 1; i < chainLength; i++)
        {
            arms[i] = new Arm(arms[i - 1].length, arms[i].angle, arms[i - 1].Target(), arms[i - 1].density, arms[i - 1].thickness, arms[i].Target());
        }
    }

    public void GenerateChain()
    {
        foreach (Arm arm in arms)
        {
            arm.GenerateLine();
        }
    }


}



Solution 1:[1]

you do

arms[i] = new Arm(arms[i - 1].length, arms[i].angle, arms[i - 1].Target(), arms[i - 1].density, arms[i - 1].thickness, arms[i].Target());
  • well what is arms[0] ..? You never create it so the very first arms[i - 1] already returns null.

  • and further note the last access to arms[i].Target()

    => if arms[i] has never been set yet (because you are just going to do this) then there won't be anything at arms[i].


Besides that you do

Arm[] arms = new Arm[chainLength];

which hides the class field arms

=> when you call GenerateChain the field arms was never initialized.

You rather would want

void Initialize()
{
    arms = new Arm[chainLength];

    ...
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1