I want to make a warp pipe from the Mario games in Unity. The key feature of this object will be that I can set the length (height) of its "neck" to any length I require, as long as it is greater than 0.5m (the fixed depth of the interior of its "cap"). That is, I want this object to be "extrudable" and the neck material to be tilable under this operation.
I have already modeled the pipe in Blender and baked textures for the material (but I won't be upset if I have to redo the material, it just needs to be a green anistropic type, very basic). It consists of 2 pieces, the neck and the cap. The cap is a child of the neck. Only the neck grows/shrinks.
I have never done this before and am not sure how to begin. How can I create this feature? I would like the pipe to grow/shrink in the editor when I change the public variable "height".
EDIT: I just put the neck and cap back together as one object and used a bone to control the neck length. I exported the FBX and am seeing how the material looks on it at different lengths now
EDIT 2: So I tried to make a script that alters the transforms of the prefab's children in the inspector but it is not working. It doesn't work in the inspector and it doesn't work while running the game if I execute the function in the start method. The prefab contains two objects, PipeNeck and PipeCap. The script is attached to the parent inside the prefab. Here is the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ExtrudePipe : MonoBehaviour
{
public float pipeHeight = 0.5f;
private GameObject neck = GameObject.Find("PipeNeck").gameObject;
private GameObject cap = GameObject.Find("PipeCap").gameObject;
void Start()
{
Extrusion();
}
void Extrusion()
{
neck.transform.localScale = new Vector3(1, 2 * pipeHeight, 1);
cap.transform.localPosition = new Vector3(0, pipeHeight - 0.5f, 0);
}
}
EDIT 3: So I realized there were 8 new errors hidden under a hundred known warnings for something else that I didn't clear on my last test. These errors say that I can't use transform.* in monobehavior, I had to put them in a function instead. So I put it in Awake() and now the pipe is stretched when the game is played, but I would still rather get instant feedback from the editor. Here is the updated code. Does anyone know what will get me instant feedback by typing the new height into the prefab's inspector field, "pipeHeight"?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ExtrudePipe : MonoBehaviour
{
public float pipeHeight = 0.5f;
void Awake()
{
Extrusion();
}
void Extrusion()
{
GameObject neck = GameObject.Find("PipeNeck").gameObject;
GameObject cap = GameObject.Find("PipeCap").gameObject;
neck.transform.localScale = new Vector3(1, 2 * pipeHeight, 1);
cap.transform.localPosition = new Vector3(0, pipeHeight - 0.5f, 0);
}
}
pipeHeight changed from "0.5" to "2":
EDIT 4: Last script was garbage, this one works when the game runs. Funny how simple things mess you up:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ExtrudePipe : MonoBehaviour
{
public float pipeHeight = 1.0f;
void Awake()
{
Extrusion();
}
void Extrusion()
{
if (pipeHeight == 1.0f)
{
return;
}
GameObject neck = GameObject.Find("PipeNeck").gameObject;
GameObject cap = GameObject.Find("PipeCap").gameObject;
float scaleFactor = (pipeHeight -0.5f)/ (0.5f * neck.transform.localScale.y);
neck.transform.localScale = new Vector3(1, scaleFactor, 1);
cap.transform.localPosition = new Vector3(0, pipeHeight - 1, 0);
}
}
EDIT 5: WORKING SOLUTION, IN EDITOR AND IN GAME:
Slap this on the default parent object within the prefab (or I guess on the prefab in the scene) and it will work instantly in the editor as well as in the game. Special thanks to DMGregory, who has been tremendous help here since I started months ago!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ExtrudePipe : MonoBehaviour
{
public float pipeHeight = 1.0f;
void OnValidate()
{
Extrusion();
}
void OnAwake()
{
Extrusion();
}
void Extrusion()
{
GameObject neck = GameObject.Find("PipeNeck").gameObject;
GameObject cap = GameObject.Find("PipeCap").gameObject;
neck.transform.localScale = Vector3.one;
cap.transform.position = Vector3.zero;
if (pipeHeight <= 1)
{
return;
}
float scaleFactor = (pipeHeight -0.5f)/ (0.5f * neck.transform.localScale.y);
neck.transform.localScale = new Vector3(1, scaleFactor, 1);
cap.transform.localPosition = new Vector3(0, pipeHeight - 1, 0);
}
}