How to change Sprite Image when it reaches 90 degrees? - c#

I say that I am a beginner.
I have a question during the project.
I'm currently implementing a card-matching game.
When I start the game, The image is loaded from the external path (D: / ..).
My question is in the code below.
public void createCardList()
{
int count_x = 0;
int count_y = 0;
GameObject parent_area = GameObject.Find("GameMain");
List<int> num = createRandomIndex(createArrayIndex());
for (int i = 0; i < card_list.Count; ++i)
{
if ((i % CARD_ROWS) == 0 && i > 0)
{
count_y += 1;
count_x = 0;
}
GameObject card_prefab_load = Resources.Load("Prefabs/card") as GameObject;
GameObject card_prefab_instantiate = Instantiate(card_prefab_load, card_prefab_load.transform.position, Quaternion.identity);
float card_position_x = (CARD_WIDTH + CARD_SPACE) * (i % CARD_ROWS) - 290f;
//Debug.Log("card_position_x" + card_position_x);
float card_position_y = count_y * (CARD_HEIGHT + CARD_SPACE) - 280f;
//Debug.Log("card_position_y" + card_position_y);
card_prefab_instantiate.transform.SetParent(parent_area.transform);
card_prefab_instantiate.transform.name = "card_" + num[i];
card_prefab_instantiate.transform.localScale = new Vector3(1f, 1f, 1f);
card_prefab_instantiate.transform.localPosition = new Vector3(card_position_x, card_position_y, 1f);
StartCoroutine(firstRotateOriginalImage());
}
}
// Rotate image
private IEnumerator firstRotateOriginalImage()
{
yield return new WaitForSeconds(2f);
GameObject findCardList = GameObject.Find("GameMain");
for (int i = 0; i < findCardList.transform.childCount; ++i)
{
// I don't know what code to put in this part.
}
}
What I want to implement is below.
When the card rotation value reaches 90 degrees,How to change an externally imported image to a Sprite Image of a child GameObject?
How to rotate the child objects 360 degrees after the first task is completed?
For example, the picture below.
Arrows indicate the order in which cards are flipped.
also, Of the 12 GameObjects, Six GameObjects try to implement a common image.
I don't know much. I need your help.

There are many ways to do that...
transform.Rotate(...)
transform.RotateAround(...)
transform.localEulerAngles = transform.localEulerAngles.X|Y|Z +
amount
transform.localRotation = transform.localRotation*relativeRotation
/*= a Quaternion*/
Something else entirely...

I'm a doubtful regarding how well I understand your question...
But it seems like you want to simply flip the cards over don't you?
The approach I'd take is to have each card as the combination of the face (rotated 180 degrees in Y) and the back, both being children of an empty GameObject.
That way you could simply rotate the Card object using transform.Rotate(0, 180, 0)
To use it in a coroutine you could do
//Speed of animation (here 0.55 seconds)
float degreesPerSecond = 200f;
//The amount you want to rotate
float maxDegrees = 180f;
//Animate
for (float f = maxDegrees; f < 0;)
{
//How much to rotate
float rot = degreesPerSecond * Time.deltaTime;
//Rotate children
foreach(var child in transform)
child.Rotate(0, rot, 0);
//Record rotation
f -= rot;
//Wait next frame
yield return null;
}
//Round to desired rotation
foreach(var child in transform)
child.position = new Vector3(child.position.x, maxDegrees, child.position.z);

Related

How to Spawn Objects in Unity3D with a Minimum Distance between

I am Programming a random "Stone" Spawner and have a big problem at the moment. I have some ideas how to fix it, but want to know a performance friendly way to do it.
So my way to Spawn the Objects on the Sphere Surface is this one:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnObjects : MonoBehaviour
{
public Vector3 centerOfSphere = new Vector3(0, 5000, 0);
public float radiusOfSphere = 5000.0f;
public List<GameObject> stones;
public int stonesToSpawn = 1;
void Start()
{
Vector3 center = transform.position + centerOfSphere; //Setting the center position of the Sphere
//This for loop is spawning the Stones on a random position on Sphere Surface
for (int i = 0; i < stonesToSpawn; i++)
{
Vector3 pos = RandomCircle(center, radiusOfSphere);
Quaternion rot = Quaternion.FromToRotation(Vector3.forward, center - pos);
Instantiate(stones[Random.Range(0, stones.Count)], pos, rot);
}
}
//Method returns a Random Position on a Sphere
Vector3 RandomCircle(Vector3 center, float radius)
{
float alpha = UnityEngine.Random.value * 360;
float beta = UnityEngine.Random.value * 360;
Vector3 pos;
pos.x = radius * Mathf.Cos(beta) * Mathf.Cos(alpha);
pos.y = radius * Mathf.Cos(beta) * Mathf.Sin(alpha);
pos.z = radius * Mathf.Sin(beta);
return pos;
}
}
So thank you for your following explanations! :)
As said to make your live one step easier simply use Random.onUnitSphere so your entire method RandomCircle (change that name btw!) can be shrinked to
private Vector3 RandomOnSphere(Vector3 center, float radius)
{
return center + Random.onUnitSphere * radius;
}
And then in order to have a minimum distance between them there are probably multiple ways but I guess the simplest - brute force - way would be:
store already used positions
when you get a new random position check the distance to already existing ones
keep get new random positions until you have found one, that is not too close to an already existing one
This depends of course a lot on your use case and the amount of objects and the minimum distance etc - in other words I leave it up to you to assure that the requested amount and minimum distance is doable at all with the given sphere radius.
You could always leave an "emergency exit" and give up after e.g. 100 attempts.
Something like e.g.
// Linq offers some handy query shorthands that allow to shorten
// long foreach loops into single calls
using System.Linq;
...
private const int MAX_ATTEMPTS = 100;
public float minimumDistance = 1f;
void Start()
{
var center = transform.position + centerOfSphere;
// It is cheaper to use with square magnitudes
var minDistanceSqr = minimumDistance * minimumDistance;
// For storing the already used positions
// Already initialize with the correct capacity, this saves resources
var usedPositions = new List<Vector3>(stonesToSpawn);
for (int i = 0; i < stonesToSpawn; i++)
{
// Keep track of the attempts (for the emergency break)
var attempts = 0;
Vector3 pos = Vector3.zero;
do
{
// Get a new random position
pos = RandomOnSphere(center, radiusOfSphere);
// increase the attempts
attempts++;
// We couldn't find a "free" position within the 100 attempts :(
if(attempts >= MAX_ATTEMPTS)
{
throw new Exception ("Unable to find a free spot! :'(");
}
}
// As the name suggests this checks if any "p" in "usedPositions" is too close to the given "pos"
while(usedPositions.Any(p => (p - pos).sqrMagnitude <= minDistanceSqr)));
var rot = Quaternion.FromToRotation(Vector3.forward, center - pos);
Instantiate(stones[Random.Range(0, stones.Count)], pos, rot);
// Finally add this position to the used ones so the next iteration
// also checks against this position
usedPositions.Add(pos);
}
}
Where
usedPositions.Any(p => (p - pos).sqrMagnitude <= minDistanceSqr))
basically equals doing something like
private bool AnyPointTooClose(Vector3 pos, List<Vector3> usedPositions, float minDistanceSqr)
{
foreach(var p in usedPositions)
{
if((p - pos).sqrMagnitude <= minDistanceSqr)
{
return true;
}
}
return false;
}
if that's better to understand for you

2D Projectile Trajectory Prediction(unity 2D)

using (unity 2019.3.7f1) 2d.
I have a player that moves around using a pullback mechanic and has a max power(like in Angry Birds).
I'm trying to draw a line(using a line renderer) that shows the exact path the player will go. I'm trying to make the line curve just like the player's path will. so far I've only managed to make a straight line in a pretty scuffed way.
The known variables are the Jump Power and the player's position, there is no friction. and I believe gravity is a constant(-9.81). Also, I would like to have a variable that allows me to control the line's length. And, if possible, the line will not go through objects and would act as if it has a collider.
// Edit
This is my current code. I changed The function so it would return the list's points because I wanted to be able to access it in Update() so it would only draw while I hold my mouse button.
My problem is that the trajectory line doesn't seem to curve, it goes in the right angle but it's straight. the line draws in the right direction and angle, but my initial issue of the line not curving remains unchanged. If you could please come back to me with an answer I would appreciate it.
enter code here
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TrajectoryShower : MonoBehaviour
{
LineRenderer lr;
public int Points;
public GameObject Player;
private float collisionCheckRadius = 0.1f;
public float TimeOfSimulation;
private void Awake()
{
lr = GetComponent<LineRenderer>();
lr.startColor = Color.white;
}
// Update is called once per frame
void Update()
{
if (Input.GetButton("Fire1"))
{
lr.positionCount = SimulateArc().Count;
for (int a = 0; a < lr.positionCount;a++)
{
lr.SetPosition(a, SimulateArc()[a]);
}
}
if (Input.GetButtonUp("Fire1"))
{
lr.positionCount = 0;
}
}
private List<Vector2> SimulateArc()
{
float simulateForDuration = TimeOfSimulation;
float simulationStep = 0.1f;//Will add a point every 0.1 secs.
int steps = (int)(simulateForDuration / simulationStep);
List<Vector2> lineRendererPoints = new List<Vector2>();
Vector2 calculatedPosition;
Vector2 directionVector = Player.GetComponent<DragAndShoot>().Direction;// The direction it should go
Vector2 launchPosition = transform.position;//Position where you launch from
float launchSpeed = 5f;//The initial power applied on the player
for (int i = 0; i < steps; ++i)
{
calculatedPosition = launchPosition + (directionVector * ( launchSpeed * i * simulationStep));
//Calculate gravity
calculatedPosition.y += Physics2D.gravity.y * (i * simulationStep);
lineRendererPoints.Add(calculatedPosition);
if (CheckForCollision(calculatedPosition))//if you hit something
{
break;//stop adding positions
}
}
return lineRendererPoints;
}
private bool CheckForCollision(Vector2 position)
{
Collider2D[] hits = Physics2D.OverlapCircleAll(position, collisionCheckRadius);
if (hits.Length > 0)
{
for (int x = 0;x < hits.Length;x++)
{
if (hits[x].tag != "Player" && hits[x].tag != "Floor")
{
return true;
}
}
}
return false;
}
}
Here's a simple way to visualize this.
To create your line you want a bunch of points.
The points represents the player's positions after being fired after X amount of time.
The position of each point is going to be : DirectionVector * (launch speed * time elapse) + (GravityDirection * time elapse^2)
You can decide in advance how far you pre calculate the points by simulating X duration and choosing the simulation step(calculate a point every X amount of time)
To detect collision each time you calculate a point you can do a small circle cast at that location. If it hits something you can stop add new points.
private float collisionCheckRadius = 0.1f;
private void SimulateArc()
{
float simulateForDuration = 5f;//simulate for 5 secs in the furture
float simulationStep = 0.1f;//Will add a point every 0.1 secs.
int steps = (int)(simulateForDuration/simulationStep);//50 in this example
List<Vector2> lineRendererPoints = new List<Vector2>();
Vector2 calculatedPosition;
Vector2 directionVector = new Vector2(0.5f,0.5f);//You plug you own direction here this is just an example
Vector2 launchPosition = Vector2.zero;//Position where you launch from
float launchSpeed = 10f;//Example speed per secs.
for(int i = 0; i < steps; ++i)
{
calculatedPosition = launchPosition + ( directionVector * (launchSpeed * i * simulationStep));
//Calculate gravity
calculatedPosition.y += Physics2D.gravity.y * ( i * simulationStep) * ( i * simulationStep);
lineRendererPoints.Add(calculatedPosition);
if(CheckForCollision(calculatedPosition))//if you hit something
{
break;//stop adding positions
}
}
//Assign all the positions to the line renderer.
}
private bool CheckForCollision(Vector2 position)
{
Collider2D[] hits = Physics2D.OverlapCircleAll(position, collisionCheckRadius);
if(hits.Length > 0)
{
//We hit something
//check if its a wall or seomthing
//if its a valid hit then return true
return true;
}
return false;
}
This is basically a sum of 2 vectors along the time.
You have your initial position (x0, y0), initial speed vector (x, y) and gravity vector (0, -9.81) being added along the time. You can build a function that gives you the position over time:
f(t) = (x0 + x*t, y0 + y*t - 9.81t²/2)
translating to Unity:
Vector2 positionInTime(float time, Vector2 initialPosition, Vector2 initialSpeed){
return initialPosition +
new Vector2(initialSpeed.x * t, initialSpeed.y * time - 4.905 * (time * time);
}
Now, choose a little delta time, say dt = 0.25.
Time | Position
0) 0.00 | f(0.00) = (x0, y0)
1) 0.25 | f(0.25) = (x1, y1)
2) 0.50 | f(0.50) = (x2, y2)
3) 0.75 | f(0.75) = (x3, y3)
4) 1.00 | f(1.00) = (x4, y4)
... | ...
Over time, you have a lot of points where the line will cross. Choose a time interval (say 3 seconds), evaluate all the points between 0 and 3 seconds (using f) and put your line renderer to cover one by one.
The line renderer have properties like width, width over time, color, etc. This is up to you.

Instantiate as many gameObjects as possible from one position and end at another

How do I instantiate as many gameObjects as possible that start at one position and end at another position. For example, instantiate gameObject at x=0 and end at x=5 axis. Between these two values, there should be as many gameObjects as possible, preferably 10-12 small scaled ones.
public GameObject prefab;
void Awake()
{
GameObject ref = (GameObject)Instantiate(prefab, Vector3.zero, Quaternion.identity);
}
when you say as many GameObjects as possible I guess you mean without overlapping?
This solution works assuming the prefab uses Colliders.
I would instantiate the first object allways and simply get it's bounding box so we know how big it is
var first = Instantiate(prefab, Vector3.zero + Vector3.right * MinX, Quaternion.identity);
var bounds = new Bounds(Vector3.zero, Vector3.zero);
foreach (var col in first.GetComponentsInChildren<Collider>(true))
{
bounds.Encapsulate(col.bounds);
}
// now you can get the size in X direction
var width = bounds.size.x;
I suspect the pivot point of your prefab would probably be in the center so first move it to the right by half of its width
first.transform.position += Vector3.right * width / 2f;
Now you can check how many objects will fit in your given range. Lets say e.g. the width was 1 then in a range from 0 to 5 there would fit in total 4 objects. There will be some redundancies in the calculation (adding 1 then decreasing 1 etc ) but I'll leave it sfor better understanding
var minPosition = MinX;
var maxPosition = MaxX;
var actualMinPosition = minPosition + width / 2;
var actualMaxPosition = maxPosition - width / 2;
// +1 here since before we reduced actualMinPosition and actualMaxPosition by
// exactly 1 * width
var possibleAmount = (int)Mathf.Floor((actualMaxPosition - actualMinPosition) / width) + 1;
So now instantiate the missing objects
// since I guess you also want them evenly spread between the start and end position
var distanceBetween = (actualMaxPosition - actualMinPosition) / (possibleAmount - 1);
// since we already instantiated the first one
// we spawn only possibleAmount - 1 more
for (var i = 0; i < possibleAmount - 1; i++)
{
// +1 here since we started the loop with i=0 but the first
// object here is actually the second to be spawned in total
// so we want it to be moved already
var x = actualMinPosition + distanceBetween * (i + 1);
var obj = Instantiate(prefab, Vector3.zero + Vector3.right * x, Quaternion.identity);
}
So all together
public void Spawn()
{
var first = Instantiate(prefab, Vector3.zero, Quaternion.identity);
var bounds = new Bounds(Vector3.zero, Vector3.zero);
foreach (var col in first.GetComponentsInChildren<Collider>(true))
{
bounds.Encapsulate(col.bounds);
}
// now you can get the size in X direction
var width = bounds.size.x;
first.transform.position += Vector3.right * width / 2f;
var minPosition = MinX;
var maxPosition = MaxX;
var actualMinPosition = minPosition + width / 2;
var actualMaxPosition = maxPosition - width / 2;
// +1 here since before we reduced actualMinPosition and actualMaxPosition by
// exactly 1 * width
var possibleAmount = (int)Mathf.Floor((actualMaxPosition - actualMinPosition) / width) + 1;
// since I guess you also want them evenly spread between the start and end position
var distanceBetween = (actualMaxPosition - actualMinPosition) / (possibleAmount - 1);
// since we already instantiated the first one
// we spawn only possibleAmount - 1 more
for (var i = 0; i < possibleAmount - 1; i++)
{
// +1 here since we started the loop with i=0 but the first
// object here is actually the second to be spawned in total
// so we want it to be moved already
var x = actualMinPosition + distanceBetween * (i + 1);
var obj = Instantiate(prefab, Vector3.zero + Vector3.right * x, Quaternion.identity);
}
}
I simply destroyed and respawned everything in Update for this demo
You could loop the amount of enemys that you want to be spawned(12 for example) and increase the position at every loop iteration.
public GameObject prefab;
public Vector3 pos;
void Awake()
{
for (int i = 0; i < 12; i++)
{
Instantiate(prefab, pos, Quaternion.identity);
pos.x += 0.5f;
}
}
This should create 10 GameObject between 0 and 5.
void Awake() {
for(float x = 0; x < 5; x+=0.5f){
Vector3 loc = new Vector3(x, 0, 0);
GameObject gameObject = (GameObject)Instantiate(prefab, loc, Quaternion.identity);
}
}
Thank you for all your answers, I did something like this:
(a) Create two gameObjects in the scene separated by some distance
(b) In the script, give reference to these two gameObjects
(c) Give number of segments (spheres) that should be generated between these two points
public Transform PointA; public Transform PointB; public float NumberOfSegments = 3; public float AlongThePath = .25f;
// Update is called once per frame
void Start()
{
Create();
}
void Create()
{
StartCoroutine(StartSpheringOut());
}
IEnumerator StartSpheringOut()
{
NumberOfSegments += 1;// since we are skipping 1st placement since its the same as starting point we increase the number by 1
AlongThePath = 1 / (NumberOfSegments);//% along the path
for (int i = 1; i < NumberOfSegments; i++)
{
yield return new WaitForSeconds(0.05f);
Vector3 CreatPosition = PointA.position + (PointB.position - PointA.position) * (AlongThePath * i);
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = CreatPosition;
sphere.transform.localScale = new Vector3(0.25f, 0.25f, 0.25f);
}

How can i make a character to turn 180 degrees on the place while walking?

using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityStandardAssets.Characters.ThirdPerson;
public class Multiple_objects : MonoBehaviour {
public GameObject prefab;
public GameObject[] gos;
public int NumberOfObjects;
private ThirdPersonCharacter[] thirdPersonCharacter;
private Animator[] _animator;
private int count = 0;
private List<float> floats = new List<float>();
public float smooth = 1f;
private Vector3 targetAngles;
void Awake()
{
Vector3 v3 = prefab.transform.position;
_animator = new Animator[NumberOfObjects];
gos = new GameObject[NumberOfObjects];
for(int i = 0; i < gos.Length; i++)
{
count = count + 2;
GameObject clone = (GameObject)Instantiate(prefab, Vector3.zero, Quaternion.identity);
gos [i] = clone;
gos [i].transform.position = new Vector3 (v3.x - count, v3.y, v3.z);
_animator [i] = gos[i].GetComponent<Animator> ();
float randomspeed = 0f;
// Keep repeating this until we find an unique randomspeed.
while(randomspeed == 0f || floats.Contains(randomspeed))
{
randomspeed = UnityEngine.Random.Range(1.0f, 15.0f);
}
floats.Add (randomspeed);
//float vertInput = 1.0f;
_animator [i].SetFloat ("Speed", randomspeed);
if (randomspeed != 0.0f)
_animator[i].speed = randomspeed;
else
_animator [i].speed = 1.0f;
}
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(Input.GetKeyDown(KeyCode.S)) // some condition to rotate 180
targetAngles = gos[5].transform.eulerAngles + 180f * Vector3.up; // what the new angles should be
transform.eulerAngles = Vector3.Lerp(gos[5].transform.eulerAngles, targetAngles, smooth * Time.deltaTime); // lerp to new angles
}
}
In the Hierarchy i have two ThirdPersoncontroller: ThirdPersonController and ThirdPersonController(1)
I put the script on the ThirdPersonController and the prefab is the ThirdPersonController(1) then it's cloning more 15 ThirdPersonControllers.
Then each of the cloned 15 players walk in another speed.
Now in the Update function when i press on the S key the ThirdPersonController is turning 180 degrees and then all the cloned 15 players also turn 180 degrees and keep walking to this direction.
What i want to do is when one of the cloned players getting to Z position turn 180 degrees only this player and turn on place 180 degrees for a second ot two walk on place turn then continue walking to the turned direction.
So in the Update function i'm using now the S key as condition but it's turning the ThirdPersonController and all the clones turn according to him and walk to the turned direction.
I tried to use gos[0].transform also gos[5].transform but it's not turning only the fifth clone but turn all of them 180 degrees.
And the condition i tried to make if(gos[0].transform.position.z == 108.9377f) or if(gos[0].transform.position.z == 100) but it's never get to the next line i used a break point.
Rather than checking when you reach that exact value, I'd check for distance between you and the waypoint using Vector3.Distance
Now for the reason all the characters are walking the same action is because of this line :
transform.eulerAngles = Vector3.Lerp(gos[5].transform.eulerAngles, targetAngles, smooth * Time.deltaTime);
You'd want to do something like this in your update
for(int i = 0; i < gos.Length; i++)
{
//if(Input.GetKeyDown(KeyCode.S)) // some condition to rotate 180
// targetAngles = gos[i].transform.eulerAngles + 180f * Vector3.up;
// If the Distance between gos[i] and Vector3(0,0,100) is smaller than 3f
if(Vector3.Distance(gos[i].transform.position, new Vector3(0,0,100)) < 3f)
{
targetAngles = gos[i].transform.eulerAngles + 180f * Vector3.up;
}
gos[i].transform.eulerAngles = Vector3.Lerp(gos[i].transform.eulerAngles, targetAngles, smooth * Time.deltaTime);
}

Spawning items at sides of a spline

I have just done the Curves and Splines Tutorials from the catlikecoding.com website (http://catlikecoding.com/unity/tutorials/curves-and-splines/) and after finishing it I came up with an idea. I would like to spawn the items from the SplineDecorator at the same distance from the spline at both sides of the spline. I have tried duplicating the for loop and instantiating the newItem twice but at different position but it doenst work as I want to. Here's the Spline Decorator script that takes a spline and then Instantiate some items along the its path
using UnityEngine;
public class SplineDecorator : MonoBehaviour
{
public BezierSpline spline;
public int frequency;
public float distanceBetweenItems;
public bool lookForward;
public Transform[] items;
private void Awake()
{
if (frequency <= 0 || items == null || items.Length == 0)
{
return;
}
float stepSize = 1f / (frequency * items.Length);
for (int p = 0, f = 0; f < frequency; f++)
{
for (int i = 0; i < items.Length; i++, p++)
{
Transform item = Instantiate(items[i]) as Transform;
Vector3 position = spline.GetPoint(p * stepSize);
item.transform.localPosition = new Vector3(position.x + distanceBetweenItems, position.y, position.z);
if (lookForward)
{
item.transform.LookAt(position + spline.GetDirection(p * stepSize));
}
item.transform.parent = transform;
}
}
}
}
You don't define exactly what "at both sides" means to you, so I'm not sure if this is what you're looking for, but maybe this will get you on the right track.
I replaced the inner loop with the following and got a sort of "race track" feel with distanceBetweenItems = 2:
Transform item = Instantiate(items[i]) as Transform;
Transform item2 = Instantiate(items[i]) as Transform;
Vector3 position = spline.GetPoint(p * stepSize);
Vector3 direction = spline.GetDirection(p * stepSize);
Vector3 cross = Vector3.Cross(direction, Vector3.up);
Vector3 delta = cross.normalized * (distanceBetweenItems/2);
item.transform.localPosition = new Vector3(position.x + delta.x, position.y + delta.y, position.z + delta.z);
item2.transform.localPosition = new Vector3(position.x - delta.x, position.y - delta.y, position.z - delta.z);
if (lookForward)
{
item.transform.LookAt( position + spline.GetDirection(p * stepSize));
item2.transform.LookAt(position + spline.GetDirection(p * stepSize));
}
item.transform.parent = transform;
item2.transform.parent = transform;
What I've done here is use Vector3.Cross() (Unity Documentation) to find the line perpendicular to both the spline and Vector3.up. Then I calculate how far along that line to go by normalizing it and multiplying it by half of distanceBetweenItems. (So that, combined, they're distanceBetweenItems apart.)
If you instead wanted something like tracing the wingtips of a plane flying that spline, you'll need to replace the Vector.up above. The simplest way is to replace it with the 'binormal vector', though there are issues with that. This pdf I just found talks a little about it, and might get you on the right path.
(Goofing around, I was able to get a reasonable approximation by replacing the Vector3 cross = ... line with Vector3 cross = Vector3.Cross(direction, direction - spline.GetDirection(p * stepSize + 0.01f));, though it's screwy on sharp bends, non-mirrored vertices, and at the start/end loop.)

Categories