Readd missing import files

This commit is contained in:
Lucien
2026-05-07 10:14:44 +02:00
parent ecb44e63d8
commit cd608d5796
810 changed files with 263144 additions and 1 deletions
@@ -0,0 +1,33 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CreateStacksFromCode : MonoBehaviour {
public GameObject[] prefabs;
// Use this for initialization
void Start () {
for (int i = 0; i < 5; i++)
{
StackUtility.CreateStack(
"Stack" + i, //name
new Vector3(-7 + 3.5f*i, 0, 0), //position
0, //rotation
5, //count
prefabs,
2, //start scale
1, //end scale
0, //scale variation
0, //random position offset
0, //start rotation variance
0, //object rotation variance
10, //object rotation offset
0, //pYOffset
false //Create compound collider
);
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 59465161eb1772d40b0b9b54eb423479
timeCreated: 1519379605
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,183 @@
using System.Collections.Generic;
using UnityEngine;
/**
* Creates stacks of items with different scale and rotation settings.
*
* @author J.C. Wichman - InnerDriveStudios.com
*/
[ExecuteInEditMode]
public class StackCreator : MonoBehaviour {
[Header("Placement settings")]
[Tooltip ("If the parent name is not empty, a new object with the given name will be created as parent for the created objects.")]
public string newParentName = "Stack";
[Tooltip("If checked, a ray will be cast down to automatically locate a surface below the stackcreator to place the objects on.")]
public bool keepGrounded = true;
[Tooltip("The layer mask for valid ground objects. Note that ground objects need to have a collider in order to be hit with a ray.")]
public LayerMask groundMask;
[Header("Prefab settings")]
[Tooltip("All prefabs in this list will randomly be picked to built a stack from.")]
public GameObject[] stackPrefabs;
[Header("Stacksize settings")]
[Tooltip("The minimum amount of objects in the stack.")]
[Range(1,100)]
public int minStackSize = 5;
[Range(1,100)]
[Tooltip("The maximum amount of objects in the stack.")]
public int maxStackSize = 10;
[Header("Scale settings")]
[Range(0.5f, 2)]
[Tooltip("The scale for the object on the bottom of the stack. Interpolated towards the top scale to get a base scale for the current object in the stack.")]
public float bottomObjectScale = 1;
[Range(0.5f, 2)]
[Tooltip("The scale for the object on the top of the stack. Interpolated from the bottom scale to get a base scale for the current object in the stack.")]
public float topObjectScale = 1;
[Range(0, 0.5f)]
[Tooltip("The variation in scale for all the objects in the stack." +
"The actual scale will be between (1-variation) * the base scale and (1+variation) * the base scale.")]
public float scaleVariation = 0.5f;
[Header("Position settings")]
[Range(0, 0.5f)]
[Tooltip("A randomly added position offset added to the xz direction to make stacks look less organized.")]
public float randomPositionOffset = 0;
[Header("Rotation settings")]
[Range(0, 180)]
[Tooltip("A random rotation between -VALUE and +VALUE for the first object in the stack.")]
public float startRotationVariance = 0;
[Range(0, 180)]
[Tooltip("A random rotation between -VALUE and +VALUE for each next object in the stack.")]
public float objectRotationVariance = 0;
[Range(-180, 180)]
[Tooltip ("A fixed offset rotation that is added for each next object in the stack.")]
public float objectRotationOffset = 0;
[Header("Collider settings")]
[Tooltip("Specifies whether to add a compound capsule collider to the stack parent (if applicable)")]
public bool compoundCapsuleCollider = false;
[Header("Other")]
[Tooltip("Change this to adjust the auto calculated y offset between the objects. Automatically adjusted by the scale. Default 0.")]
[Range(-0.1f, 0.1f)]
public float yOffset;
[Tooltip("Drag the object that contains this component through the scene and press this key to place a stack.")]
public KeyCode placementKey = KeyCode.S;
[Tooltip("Drag the object that contains this component through the scene and press this key to replace the last stack.")]
public KeyCode replacementKey = KeyCode.R;
void OnValidate()
{
minStackSize = Mathf.Min(minStackSize, maxStackSize);
maxStackSize = Mathf.Max(minStackSize, maxStackSize);
}
private void OnDrawGizmos()
{
//set our starting values based on our own transform
Vector3 stackPosition = transform.position;
float stackRotation = transform.rotation.eulerAngles.y;
//get an indication of the size of the bottom object in the stack
float width = 1f;
float height = 1f;
if (stackPrefabs != null && stackPrefabs.Length > 0)
{
Bounds? bounds = StackUtility.FindBounds(stackPrefabs[0]);
if (bounds != null)
{
Bounds actualBounds = (Bounds)bounds;
width = actualBounds.size.x;
height = actualBounds.size.z;
}
}
//now see if we can find the ground below us
Vector3 surfacePosition = stackPosition;
bool groundFound = StackUtility.FindStackPositionBelow(ref surfacePosition, groundMask);
if (keepGrounded)
{
//if we want to keep the stack grounded, draw an indicator of where that is going to happen
if (groundFound)
{
drawStackIndicator(stackPosition, stackRotation, Color.gray * 0.5f, width, height);
drawStackIndicator(surfacePosition, stackRotation, Color.green, width, height);
Gizmos.color = Color.blue;
Gizmos.DrawLine(stackPosition, surfacePosition);
}
else //or a red square if we could not locate the ground
{
drawStackIndicator(stackPosition, stackRotation, Color.red, width, height);
}
} else
{
//if we do not want to keep the stack grounded, we still draw a sort of shadow indicator
//because it makes placement easier
drawStackIndicator(stackPosition, stackRotation, Color.green, width, height);
if (groundFound)
{
drawStackIndicator(surfacePosition, stackRotation, Color.gray, width, height);
}
}
}
/**
* Draws a square with a cross using the given color.
*/
private void drawStackIndicator (Vector3 pPosition, float pYRotation, Color pColor, float pWidth = 1f, float pHeight = 0.75f)
{
GizmoUtility.DrawSquare(pPosition, Quaternion.Euler(90, pYRotation, 0), pColor, pWidth, pHeight,4);
GizmoUtility.DrawCross(pPosition, Quaternion.Euler(90, pYRotation, 0), pColor, pWidth/2, pHeight/2, 4);
}
private List<GameObject> _history;
//helper method to create stack according to settings above
public void CreateStack()
{
//check our creation settings
Vector3 stackPosition = transform.position;
Vector3 surfacePosition = stackPosition;
bool groundFound = StackUtility.FindStackPositionBelow(ref surfacePosition, groundMask);
if (keepGrounded && !groundFound)
{
Debug.Log("Cannot place stack using current settings. No ground found.");
return;
}
_history = StackUtility.CreateStack(
newParentName,
keepGrounded && groundFound ? surfacePosition : stackPosition,
transform.rotation.eulerAngles.y,
Random.Range (minStackSize, maxStackSize+1),
stackPrefabs,
bottomObjectScale,
topObjectScale,
scaleVariation,
randomPositionOffset,
startRotationVariance,
objectRotationVariance,
objectRotationOffset,
yOffset,
compoundCapsuleCollider
);
}
public void DeleteLastStack()
{
if (_history == null) return;
for (int i = _history.Count - 1; i >= 0; i--)
{
GameObject.DestroyImmediate(_history[i]);
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 67a1244fda9ffe7488d5c1cb9981f091
timeCreated: 1515700206
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,214 @@
using System.Collections.Generic;
using UnityEngine;
/**
* StackUtility class to create stacks of items through code.
*
* @author J.C. Wichman - www.innerdrivestudios.com
*/
public class StackUtility {
/**
* Helper method to find a valid stack position below a given stackposition.
* For example you can pick a point above a floor and this method will return
* a position on the floor.
*
* @param pStackPosition the position to start looking from (downwards)
* @param pLayerMask the layermask of the objects to include in the downward raycast
*/
public static bool FindStackPositionBelow (ref Vector3 pStackPosition, LayerMask pLayerMask )
{
//use given stackposition as start to cast a ray down to find the first target we hit
//if we can't find a ray, just return false
RaycastHit info;
Ray ray = new Ray(pStackPosition, Vector3.down);
if (Physics.Raycast(ray, out info, float.PositiveInfinity, pLayerMask))
{
pStackPosition = info.point;
return true;
}
else
{
return false;
}
}
/**
* Create a stack of objects, automatically randomizing them, scaling them, rotating them etc.
*
* @param pParentName if pParentName != null, all objects will be created as children of a parent with the given name
* @param pStackPosition the world space position of the bottom of the stack
* @param pStackRotation the world space y rotation of the stack (0,360)
* @param pStackSize the amount of objects in the stack (1-...?)
*
* @param pPrefabs the prefabs to choose from randomly when creating objects in the stack
*
* @param pStartScale the uniform scale for the object on the bottom of the stack (interpolated to top)
* @param pEndScale the uniform scale for the object on the top of the stack (interpolated from bottom)
* @param pScaleVariation the percentage of scale variation for each book (A range of 0..0.5f works best)
*
* @param pRandomPositionOffset a random offset added to each next book, calculated from the center
*
* @param pStartRotationVariance the variance in rotation for the first object in the stack (0 .. 180)
* (calculated as a number between (-pObjectRotationVariance, pObjectRotationVariance)
* @param pObjectRotationVariance the variance in rotation for each subsequent object (0 .. 180)
* (calculated as a number between (-pObjectRotationVariance, pObjectRotationVariance)
* @param pObjectRotationOffset the added rotation to each object (-180 .. 180)
* @param pYOffset an additional yOffset padding between the objects automatically multiplied with the scale
*
* @param pCompoundCapsuleCollider should we create a compound capsule collider for the stack as a whole
*
* @return a list of all created root objects (which is 1 if pParentName.Length > 0)
*/
public static List<GameObject> CreateStack(
string pParentName,
Vector3 pStackPosition,
float pStackRotation,
int pStackSize,
GameObject[] pPrefabs,
float pStartScale,
float pEndScale,
float pScaleVariation,
float pRandomPositionOffset,
float pStartRotationVariance,
float pObjectRotationVariance,
float pObjectRotationOffset,
float pYOffset,
bool pCompoundCapsuleCollider
)
{
//during creation keep a list of created objects so we can return that to the caller
List<GameObject> rootStackObjects = new List<GameObject>();
//set some start variables that we can overwrite later
//start by assuming the objects will be attached directly to the world
Transform parent = null;
Vector3 startPosition = pStackPosition;
float startRotation = pStackRotation + Random.Range(-pStartRotationVariance, pStartRotationVariance);
//if required created an addition stack parent and attach it to the main parent (if given)
bool createIntermediateNode = pParentName != null && pParentName.Length > 0;
if (createIntermediateNode)
{
//overwrite the null parent with this new intermediate node
parent = new GameObject(pParentName).transform;
rootStackObjects.Add(parent.gameObject);
parent.position = pStackPosition;
parent.rotation = Quaternion.AngleAxis(startRotation, Vector3.up);
//but since all objects will now be nested under this new node, reset the object start position & rotation to 0
startPosition = Vector3.zero;
startRotation = 0;
}
//now build the stack of objects
//this loop is fairly long, but all variables are so related that
//splitting it up into smaller parts does not improve the readability or performance.
//stacktop is used to place a new book and for collider calculation
float stackTop = 0;
//maxExtents is used to calculate a radius for a compound collider
float maxExtents = 0;
for (int i = 0; i < pStackSize; i++)
{
//create a random object, the object should be created from a prefab at (0,0,0), without rotation, keeping the original scale
GameObject newObject = GameObject.Instantiate(pPrefabs[Random.Range(0, pPrefabs.Length)], Vector3.zero, Quaternion.identity);
//calculate scale based on start/end/index
float baseScale = (pStackSize > 1) ?
Mathf.Lerp(pStartScale, pEndScale, ((float)i) / (pStackSize - 1)) :
pStartScale;
baseScale += Random.Range(-baseScale * pScaleVariation, baseScale * pScaleVariation);
newObject.transform.localScale = newObject.transform.localScale * baseScale;
//get the bounds for this object so we can use those values for positioning etc
Bounds? bounds = FindBounds(newObject);
if (bounds == null)
{
Debug.LogWarning("Created object has no meshrenderers, check your prefabs!");
continue;
}
Bounds actualBounds = (Bounds)bounds;
//now that we have the bounds, set the position with an optionally added random offset
Vector2 randomOffset = Random.insideUnitCircle * pRandomPositionOffset;
newObject.transform.localPosition =
//the bottom of the stack
startPosition +
new Vector3(
0,
//the distance from the bottom of the stack, to the top of the last object
stackTop +
//plus the offset from the center of the bounds to the bottom (or top) of the object
actualBounds.extents.y - actualBounds.center.y
,
0
) +
new Vector3(randomOffset.x, 0, randomOffset.y);
//set our top to be the new starting point
stackTop += (2 * actualBounds.extents.y) + (pYOffset * baseScale);
//calculate the max extents in case we want to add a compound collider
maxExtents = Mathf.Max(Mathf.Max(actualBounds.extents.x, actualBounds.extents.z), maxExtents);
//update parenting and history, if we have a parent, attach us, if not
//add us to the history list so that the caller can remove us if required
if (parent != null) newObject.transform.SetParent(parent, false);
else rootStackObjects.Add(newObject);
//update object rotation
newObject.transform.localRotation = Quaternion.AngleAxis(startRotation, Vector3.up);
startRotation += Random.Range(-pObjectRotationVariance, pObjectRotationVariance) + pObjectRotationOffset;
}
//we can also add a compound collider assuming there is an intermediate stack mode
if (pCompoundCapsuleCollider)
{
if (createIntermediateNode)
{
CapsuleCollider collider = parent.gameObject.AddComponent<CapsuleCollider>();
collider.center = new Vector3(0, stackTop/2, 0);
collider.height = stackTop;
collider.radius = maxExtents;
} else
{
Debug.Log("Cannot add a compound collider, since there is no intermediate node.");
}
}
return rootStackObjects;
}
public static Bounds? FindBounds (GameObject pGameObject)
{
if (pGameObject == null) return null;
MeshRenderer[] meshRenderers = pGameObject.GetComponentsInChildren<MeshRenderer>();
if (meshRenderers.Length > 0)
{
Bounds bounds = meshRenderers[0].bounds;
for (int i = 1; i < meshRenderers.Length; i++)
{
bounds.Encapsulate(meshRenderers[i].bounds);
}
return bounds;
} else
{
return null;
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c54fe1ab3952e964d8fc3b7ce93d8b39
timeCreated: 1515840197
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: