- Home /
Procedural wires/cables/tubes
I am currently building a little puzzle platformer an currently I try to create a method to tell the player what button/lever control which mechanism, without outright telling them. I think the best way would be wires that connect the appropriate tiles. I created some wire models, but placing them is a bit tedious and I would have to create additional models for new situations, like wires going up or behind the platforms.
I thought about writing a script that creates wires between two objects, not necessarily as elaborate as the models I have now, but more user-friendly.
I think the separate steps would be:
Create a master curve between two objects (probably cosh(x))
Create one/multiple slave curves that follow the master spline, with added twists and turns
Create vertices along the slave splines and connect them with polygons
While I think I can manage the first (although probably without being able to display the curve to test if it works), I have no idea how to start on the other two.
Image to show how it look right now:
Got the cosh(x) thing working finally. Even with feedback in the viewport, thanks to Gizmos. Off to the next part....
using UnityEngine;
using System.Collections;
[ExecuteInEdit$$anonymous$$ode]
public class Spliner : $$anonymous$$onoBehaviour {
public GameObject next;
public float gravity;
public int steps;
private Vector3 nextPosition;
private Vector3[] pointArr;
void Update() {
if(steps < 0) steps= 0;
pointArr = new Vector3[steps];
if(next) nextPosition = next.transform.position;
for(int i = 0; i < steps; i++) {
pointArr[i] = $$anonymous$$idpoint(i);
}
}
Vector3 $$anonymous$$idpoint(int i) {
Vector3 direction = nextPosition - transform.position;
return transform.position + direction/steps * i + new Vector3(0, gravity * ((CosH((1.0f * i / steps) - 0.5f) - CosH(0.5f))), 0);
}
float CosH(float t) {
return ($$anonymous$$athf.Exp(t) + $$anonymous$$athf.Exp(-t))/2;
}
void OnDrawGizmos() {
foreach(Vector3 temp in pointArr) {
Gizmos.DrawSphere(temp, 0.1f);
}
}
}
(I know I should not do this in Update. I just have it like this to have instant feedback in Edit $$anonymous$$ode. This will all go in Start eventually)
Ok...next part done, more or less...I can create multiple subsplines that curl around the master spline...I might add additional randomness, but it already looks quite nice.
using UnityEngine;
using System.Collections;
[ExecuteInEdit$$anonymous$$ode]
public class Spliner : $$anonymous$$onoBehaviour {
public GameObject next;
public float gravity;
public int sides;
public int steps;
public int subSplines;
public float frequency;
public float amplitude;
private Vector3 curPosition;
private Vector3 nextPosition;
private Vector3[] mainPointArr = new Vector3[0];
private Vector3[,] subPointArr = new Vector3[0,0];
void Update() {
if(next) {
nextPosition = next.transform.position - 2.8f * next.transform.forward; //the offset here and in the next line are optional, they are important for my current project only
curPosition = transform.position - 2.8f * transform.forward;
if(sides < 3) sides = 3;
if(steps < 1) steps= 1;
mainPointArr = new Vector3[steps + 1];
for(int i = 0; i <= steps; i++) {
mainPointArr[i] = DrawCosH(i);
}
if(subSplines < 1) subSplines = 1;
subPointArr = new Vector3[subSplines, steps];
for(int i = 0; i < subSplines; i++) {
DrawSubSpline(i);
}
}
}
//create master spline
Vector3 DrawCosH(int i) {
Vector3 direction = nextPosition - curPosition;
return curPosition + direction/steps * i + new Vector3(0, gravity * (CosH((1.0f * i / steps) - 0.5f) - CosH(0.5f)), 0) - Vector3.up; //this last Vector3.up is optional, like the offset at the top
}
//calculate cosh
float CosH(float t) {
return ($$anonymous$$athf.Exp(t) + $$anonymous$$athf.Exp(-t))/2;
}
//create sub splines
void DrawSubSpline(int i) {
float locAmp = amplitude * Random.Range(0.5f, 1.2f) / 10;
float locFreq = frequency * Random.Range(0.8f, 1.2f);
float offset = Random.Range(0.0f, 1.0f);
int cw = (Random.Range(0.0f, 1.0f) > 0.5 ? -1 : 1);
for(int j = 0; j < steps; j++) {
Vector3 direction = mainPointArr[j + 1] - mainPointArr[j];
Quaternion rot = Quaternion.LookRotation(direction);
subPointArr[i, j] = mainPointArr[j] + rot * (Vector3.up * $$anonymous$$athf.Sin(1.0f * j * locFreq / steps + offset) + Vector3.right * cw * $$anonymous$$athf.Cos(1.0f * j * locFreq / steps + offset)) * locAmp;
}
}
//draw Gizmos for visualization in the Editor
void OnDrawGizmos() {
if(next) {
Gizmos.color = Color.yellow;
//foreach(Vector3 temp in mainPointArr) {
// Gizmos.DrawSphere(temp, 0.1f);
//}
if(subSplines > 0) {
Gizmos.color = Color.red;
foreach(Vector3 temp in subPointArr) {
Gizmos.DrawSphere(temp, 0.05f);
}
}
}
}
}
Here is an image that shows how it currently looks (with an extensive amount of steps and Gizmo Spheres on each point)
Sorry for the long comments. Probably I should write this somewhere else.
Answer by Piflik · Jan 06, 2013 at 03:15 AM
Ater failing to create meshes on runtime, I decided to use the LineRenderer instead. I am quite happy with it, although it seems to handle materials differently than the MeshRenderer, but it is just so much easier to use. Anyways, here is the working code. Not sure if I want to work a bit more on it, or call it good enough...
using UnityEngine;
using System.Collections;
public class Spliner : MonoBehaviour {
public GameObject next;
public float gravity;
public float radius;
public int steps;
public int subSplines;
public float frequency;
public float amplitude;
public Material material;
private Vector3 curPosition;
private Vector3 nextPosition;
private Vector3[] mainPointArr = new Vector3[0];
private Vector3[,] subPointArr = new Vector3[0,0];
private GameObject[] children;
void Start() {
if(next) {
nextPosition = next.transform.position;
curPosition = transform.position;
if(steps < 2) steps = 2;
mainPointArr = new Vector3[steps + 1];
for(int i = 0; i <= steps; i++) {
mainPointArr[i] = DrawCosH(i);
}
if(subSplines < 1) subSplines = 1;
subPointArr = new Vector3[subSplines, steps];
for(int i = 0; i < subSplines; i++) {
DrawSubSpline(i);
}
children = new GameObject[subSplines];
for(int i = 0; i < subSplines; i++) {
children[i] = new GameObject("Child0" + i);
children[i].transform.parent = transform;
LineRenderer temp = children[i].AddComponent<LineRenderer>();
temp.SetVertexCount(steps);
temp.SetWidth(radius, radius);
temp.material = material;
for(int j = 0; j < steps; j++) {
temp.SetPosition(j, subPointArr[i, j]);
}
}
}
}
public Vector3 DrawCosH(int i) {
Vector3 direction = nextPosition - curPosition;
int locStep = steps - 1;
return curPosition + direction/locStep * i + new Vector3(0, gravity * (CosH((1.0f * i / locStep) - 0.5f) - CosH(0.5f)), 0);
}
float CosH(float t) {
return (Mathf.Exp(t) + Mathf.Exp(-t))/2;
}
void DrawSubSpline(int i) {
float locAmp = amplitude * Random.Range(0.5f, 1.2f) / 10;
float locFreq = frequency * Random.Range(0.8f, 1.2f);
float offset = Random.Range(0.0f, 1.0f);
int cw = (Random.Range(0.0f, 1.0f) > 0.5 ? -1 : 1);
for(int j = 0; j < steps; j++) {
Vector3 direction = mainPointArr[j + 1] - mainPointArr[j];
Quaternion rot = Quaternion.LookRotation(direction);
subPointArr[i, j] = mainPointArr[j] + rot * (Vector3.up * Mathf.Sin(1.0f * j * locFreq / steps + offset) + Vector3.right * cw * Mathf.Cos(1.0f * j * locFreq / steps + offset)) * locAmp;
}
}
}
I'll keep this question open, in case someone views that as an invitation to borrow me his brain...
Answer by gogo199432 · Aug 01, 2013 at 02:45 PM
Hi man, this looks like a really good script there, one which i desperatly need, however i have no clue how to use it :D I'm kinda new to programming, and I use Java, so...
Since this script has no interaction with other scripts, you should still be able to use it without converting to js. The only thing to make sure, is to name the script Spliner.cs, because it needs to be the same name as the class.
Yeah i got it till that, but how should i use it. I mean I attached it to an empty and set the next GameObject to another empty. However when i start the game, there is nothing. I added a pitch black material btw.
You have to set the different parameters of the script to useful values, most notably Radius (< 0) and Steps (at least 2). Just noticed that I actually test, if "Steps" is smaller than 1, but that has to be '< 2'...fixed it now
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Implementation of directional buildings? 1 Answer
How to render procedurally generated mesh to be rendered as 2 sided? 1 Answer
Flip over an object (smooth transition) 3 Answers