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();
}
}
}
CodePudding user response:
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 firstarms[i - 1]
already returnsnull
.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 atarms[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];
...
}
CodePudding user response:
With help from derHugo, and a C# youtube tutorial series by Caleb Curry I have found the solution. The issue came from lack of understanding of classes and the difference between static and non-static methods.
Here's the code, it's a fun little bit of code that makes a simple forward kinematic arm.
using UnityEngine;
public class Arm
{
public float length { get; set; }
public float angle { get; set; }
public Vector3 origin { get; set; }
public int resolution { get; set; }
public float thickness { get; set; }
public Vector3 target { get; set; }
static public Vector3 Target(Vector3 origin, float angle, float length)
{
Vector3 target;
target.x = origin.x Mathf.Cos(angle) * length;
target.y = origin.y Mathf.Sin(angle) * length;
target.z = 0;
return target;
}
static public void GenerateLine(int resolution, float length, Vector3 origin, float angle, float thickness)
{
Vector3[] lineSegments = new Vector3[resolution];
float segmentLength = length / lineSegments.Length;
lineSegments[0] = origin;
for(int i = 1; i < lineSegments.Length; i )
{
lineSegments[i].x = lineSegments[i - 1].x Mathf.Cos(angle) * segmentLength;
lineSegments[i].y = lineSegments[i - 1].y Mathf.Sin(angle) * segmentLength;
Gizmos.color = Color.black;
Gizmos.DrawSphere(lineSegments[i], thickness);
}
}
}
using UnityEngine;
public class ArmChain : MonoBehaviour
{
[Range(0, 100)]
public int chainLength;
[Range(0, 10)]
public float length;
[Range(-.02f * 3.141592f, .02f * 3.141592f)]
public float angle;
[Range(0, 2560)]
public int resolution;
public Transform jointOrigin;
[Range(0, 2560)]
public float thickness;
[SerializeField, HideInInspector]
public Arm[] arms;
private void OnDrawGizmos()
{
Initialize();
GenerateChain();
}
void Initialize()
{
arms = new Arm[chainLength];
arms[0] = new Arm();
arms[0].length = length;
arms[0].angle = angle;
arms[0].origin = jointOrigin.position;
arms[0].resolution = resolution;
arms[0].thickness = thickness;
arms[0].target = Arm.Target(jointOrigin.position, angle, length);
for (int i = 1; i < chainLength; i )
{
arms[i] = new Arm();
arms[i].length = length;
arms[i].angle = arms[i - 1].angle angle;
arms[i].origin = arms[i - 1].target;
arms[i].resolution = resolution;
arms[i].thickness = thickness;
arms[i].target = Arm.Target(arms[i].origin, arms[i].angle, length);
}
}
public void GenerateChain()
{
for(int i = 0; i < chainLength; i )
{
Arm.GenerateLine(arms[i].resolution, arms[i].length, arms[i].origin, arms[i].angle, arms[i].thickness);
}
}
}