public GameObject AddTrackPiece(Vector3 totalAngle, Vector3 modifiedPosition, Vector3 eulerAngles, Vector3 startAngle, Vector3 offset, float percentageOfTrack, int secondCurveStart) { GameObject newTrackPiece; if (unusedTrackPieces.Count > 0) { newTrackPiece = unusedTrackPieces[0]; unusedTrackPieces.RemoveAt(0); newTrackPiece.SetActive(true); } else { newTrackPiece = Instantiate(trackPrefab, transform); TrackPiece trackPieceClass = newTrackPiece.GetComponent <TrackPiece>(); trackPieceClass.Start(); trackPieceClass.rollerCoaster = this; } //reset position and angle before adjusting the track newTrackPiece.transform.position = Vector3.zero; newTrackPiece.transform.localEulerAngles = Vector3.zero; TrackPiece newTrackPieceClass = newTrackPiece.GetComponent <TrackPiece>(); newTrackPieceClass.totalAngle = totalAngle; trackPieces.Add(newTrackPiece); //adjust the track newTrackPieceClass.AdjustTrack(totalAngle, startAngle, percentageOfTrack, secondCurveStart); //set track rotation (after adjustment to make sure the adjustment process goes well) newTrackPiece.transform.eulerAngles = eulerAngles; //subtract offset newTrackPiece.transform.position = modifiedPosition - offset; return(newTrackPiece); }
//will create a path of tracks from a start position until the next position by creating turns between them //startTrack: track that this path is starting on //incline: if this path is creating an incline, false if it is creating a turning path public void CreatePath(GameObject startTrack, bool incline) { //if any tracks should be created bool cancel = false; //check if the straight button is being held down bool straight = Input.GetButton("RightMenuClick"); //check if the chail lift button is being held down bool chainLift = Input.GetButton("LeftMenuClick") || true; if (chainLift) { startTrack.GetComponent <TrackPiece>().chainLift = true; startTrack.GetComponent <TrackPiece>().chainSpeed = defaultLiftSpeed; } //the position of the first track piece that will be a part of this new edition (previous track pieces are not edited) Vector3 startPosition = startTrack.transform.position; Vector3 targetPosition = rightController.transform.position; Vector3 targetAngle = new Vector3(0, 1, 0) * rightController.transform.eulerAngles.y; //used to get x axis angle in incline tracks Vector3 xTargetAngle = rightController.transform.eulerAngles; Vector3 fullTargetAngle = rightController.transform.eulerAngles; Vector3 startTrackAngleRelative = Vector3.zero; Vector3 currentAngle = getCurrentAngle(startTrack, true); //full angle without any edits Vector3 fullStartAngle = getCurrentAngle(startTrack, true); if (incline) { targetAngle = new Vector3(1, 0, 0) * rightController.transform.eulerAngles.x; xTargetAngle = MathHelper.ConvertQuant2Euler(rightController.transform.rotation); fullTargetAngle = rightController.transform.eulerAngles; currentAngle = getCurrentAngle(startTrack, false); currentAngle = new Vector3(currentAngle.x, currentAngle.z, currentAngle.y); fullStartAngle = getCurrentAngle(startTrack, true); } //check if the track should be auto completed if (trackPieces[0].GetComponent <TrackPiece>().colliding) { targetPosition = trackPieces[0].transform.position; targetAngle = new Vector3(0, 1, 0) * trackPieces[0].transform.eulerAngles.y; fullTargetAngle = trackPieces[0].transform.eulerAngles; if (incline) { targetAngle = new Vector3(1, 0, 0) * trackPieces[0].transform.eulerAngles.x; } } //set angle to 0 if the straight button is being held if (straight && incline) { targetAngle = Vector3.zero; fullTargetAngle = Vector3.zero; } if (incline) { //adjust angle to make it like it was normal float angle = Mathf.Cos(currentAngle.y * Mathf.Deg2Rad) * xTargetAngle.x + Mathf.Sin(currentAngle.y * Mathf.Deg2Rad + Mathf.PI) * fullTargetAngle.z; angle -= Mathf.Sin((currentAngle.y - 90) * Mathf.Deg2Rad) * 90 + 90; if (angle > 90) { cancel = true; } targetAngle = new Vector3(angle, 0, 0); //theoretical position as if it was at a normal position float x = Mathf.Sin(currentAngle.y * Mathf.Deg2Rad) * targetPosition.x + Mathf.Cos(currentAngle.y * Mathf.Deg2Rad) * targetPosition.z; float y = targetPosition.y; //set that position so that future calculations use that position instead targetPosition = new Vector3(0, y, x); //calculate the same for startPosition //theoretical position as if it was at a normal position x = Mathf.Sin(currentAngle.y * Mathf.Deg2Rad) * startPosition.x + Mathf.Cos(currentAngle.y * Mathf.Deg2Rad) * startPosition.z; y = startPosition.y; //set that position so that future calculations use that position instead startPosition = new Vector3(0, y, x); } //rotate positions around the start angle Vector3 pivotAngle = -currentAngle; if (incline) { pivotAngle = -new Vector3(1, 0, 0) * fullStartAngle.x; pivotAngle += new Vector3(90, 0, 0); } targetPosition = MathHelper.RotatePointAroundPivot(targetPosition, startPosition, pivotAngle); if (!incline) { //the target position generated from this method becomes slightly off depending on the target angle //adjust for these issues Vector3 targetPositionOffset = new Vector3(0, 0, trackWidth / 2); targetPosition += targetPositionOffset; } if (!incline) { targetAngle -= new Vector3(0, 1, 0) * currentAngle.y; } else { //make sure angle is positive if (targetAngle.x < 0) { targetAngle = targetAngle + new Vector3(360, 0, 0); } targetAngle -= new Vector3(1, 0, 0) * fullStartAngle.x; } //reset current angle to the proper angle currentAngle = fullStartAngle; //set angle to 0 if the straight button is being held if (straight && !incline) { targetAngle = Vector3.zero; fullTargetAngle = Vector3.zero; } Vector3 angleDifference = targetAngle - startTrackAngleRelative; //make sure the smallest difference between the angles is found Vector3 smallestAngleDifference = new Vector3(Mathf.Abs(angleDifference.x), Mathf.Abs(angleDifference.y), Mathf.Abs(angleDifference.z)); //do 360 - angle if over 180 for each (see https://stackoverflow.com/questions/6722272/smallest-difference-between-two-angles) { float x1 = smallestAngleDifference.x; float y1 = smallestAngleDifference.y; float z1 = smallestAngleDifference.z; if (x1 > 180) { x1 = 360 - x1; } if (y1 > 180) { y1 = 360 - y1; } if (z1 > 180) { z1 = 360 - z1; } smallestAngleDifference = new Vector3(x1, y1, z1); } //get amount of tracks needed by dividing by length of one track's bone then dividing by amount of bones per track piece //int for now just to make things easier //for now just set to a static number //that many tracks can now be created with an angle of angle.y divided by each bone (tracksNeeded * boneAmount) //find the collision between the start line and the target line (x = (b2 - b1) / (m1 - m2)) //calculate the slope for the target angle float targetSlopeAngle = 90 - targetAngle.y; if (incline) { targetSlopeAngle = 90 - targetAngle.x; } float targetSlope = Mathf.Tan(targetSlopeAngle * Mathf.Deg2Rad); //calculate slope for the start float startSlopeAngle = 90 - startTrackAngleRelative.y; if (incline) { startSlopeAngle = 90 - startTrackAngleRelative.x; } float startSlope = Mathf.Tan(startSlopeAngle * Mathf.Deg2Rad); //the b value for the target angle (b = y - mx) float targetB = targetPosition.z - targetSlope * targetPosition.x; //the b value for the start angle (b = y - mx) float startB = startPosition.z - startSlope * startPosition.x; if (incline) { targetB = targetPosition.y - targetSlope * targetPosition.z; startB = startPosition.y - startSlope * startPosition.z; } //calculate the collision point float collisionX = (startB - targetB) / (targetSlope - startSlope); float collisionY = targetSlope * collisionX + targetB; if (!incline) { //check if that point is infront or behind the start point (https://math.stackexchange.com/questions/1330210/how-to-check-if-a-point-is-in-the-direction-of-the-normal-of-a-plane) Vector3 startNormal = new Vector3(Mathf.Cos(startSlopeAngle * Mathf.Deg2Rad), 0, Mathf.Sin(startSlopeAngle * Mathf.Deg2Rad)); float startNormalDistance = Vector3.Dot(startNormal, new Vector3(collisionX, 0, collisionY) - startPosition); //check if the collision point is past the startPosition if (startNormalDistance > 0 && targetAngle != Vector3.zero) { cancel = true; } //check for the target line as well Vector3 targetNormal = new Vector3(Mathf.Cos(targetSlopeAngle * Mathf.Deg2Rad), 0, Mathf.Sin(targetSlopeAngle * Mathf.Deg2Rad)); float targetNormalDistance = Vector3.Dot(targetNormal, new Vector3(collisionX, 0, collisionY) - targetPosition); //check if the collision point is past the startPosition if (targetNormalDistance < 0 && targetAngle != Vector3.zero) { cancel = true; } } else if (incline) { //check if that point is infront or behind the start point (https://math.stackexchange.com/questions/1330210/how-to-check-if-a-point-is-in-the-direction-of-the-normal-of-a-plane) Vector3 startNormal = new Vector3(0, Mathf.Sin(startSlopeAngle * Mathf.Deg2Rad), Mathf.Cos(startSlopeAngle * Mathf.Deg2Rad)); float startNormalDistance = Vector3.Dot(startNormal, new Vector3(0, collisionY, collisionX) - startPosition); //check if the collision point is past the startPosition if (startNormalDistance < 0 && targetAngle != Vector3.zero) { cancel = true; } //check for the target line as well Vector3 targetNormal = new Vector3(0, Mathf.Sin(targetSlopeAngle * Mathf.Deg2Rad), Mathf.Cos(targetSlopeAngle * Mathf.Deg2Rad)); float targetNormalDistance = Vector3.Dot(targetNormal, new Vector3(0, collisionY, collisionX) - targetPosition); //check if the collision point is past the startPosition if (targetNormalDistance > 0 && targetAngle != Vector3.zero) { cancel = true; } } //get distance from the start float distanceFromStart = Mathf.Sqrt(Mathf.Pow(collisionX - startPosition.x, 2) + Mathf.Pow(collisionY - startPosition.z, 2)); //get distance from target float distanceFromTarget = Mathf.Sqrt(Mathf.Pow(collisionX - targetPosition.x, 2) + Mathf.Pow(collisionY - targetPosition.z, 2)); if (incline) { distanceFromStart = Mathf.Sqrt(Mathf.Pow(collisionX - startPosition.z, 2) + Mathf.Pow(collisionY - startPosition.y, 2)); distanceFromTarget = Mathf.Sqrt(Mathf.Pow(collisionX - targetPosition.z, 2) + Mathf.Pow(collisionY - targetPosition.y, 2)); } //if the angle is 0, then get the normal difference, do not try to form a curve if (targetAngle == Vector3.zero) { distanceFromStart = startPosition.z - targetPosition.z; if (incline) { //uses y because when the angle is zero, y ends up being the horizontal variable distanceFromStart = targetPosition.y - startPosition.y; } //check to see if the target is behind the start track if ((targetPosition.z > startPosition.z && !incline) || (targetPosition.y < 0 && incline) || distanceFromStart < 0) { distanceFromStart = 0; } } //float trackLengthRequired = 2 * Mathf.PI * radius * ((180 - angle.y) / 360); //get amount of tracks needed by dividing by length of one track's bone then dividing by amount of bones per track piece //int for now just to make things easier //the amount of tracks need coming straight off the start track float startTracksNeeded = Mathf.Abs(distanceFromStart / (trackBoneSize * boneAmount)); float targetTracksNeeded = Mathf.Abs(distanceFromTarget / (trackBoneSize * boneAmount)); float curveTracksNeeded = 0; //if the controller is on the other side bool otherSide = targetPosition.x > startPosition.x; if (incline) { otherSide = targetPosition.z < startPosition.z; } //amount to check for for the first if statement in the curve float checkAmount = startTracksNeeded; if (Mathf.Min(startTracksNeeded, targetTracksNeeded) == checkAmount && !cancel) { //find intersection between line to the end of curve from the start of curve float startToEndCurveSlope = Mathf.Tan((((180 - targetAngle.y) / 2)) * Mathf.Deg2Rad); //the b value (b = y - mx) float startToEndCurveB = startPosition.z - startToEndCurveSlope * startPosition.x; if (incline) { startToEndCurveSlope = Mathf.Tan((((180 - targetAngle.x) / 2)) * Mathf.Deg2Rad); startToEndCurveB = startPosition.y - startToEndCurveSlope * startPosition.z; } //find intersection between this line and the target line (x = (b2 - b1) / (m1 - m2)) //this position will be the second point on the circle of the curve (end point), the first is the start track float circleTargetX = (startToEndCurveB - targetB) / (targetSlope - startToEndCurveSlope); float circleTargetY = startToEndCurveSlope * circleTargetX + startToEndCurveB; //find the normal for the start angle //y = rsinA, x = rcosA //these are the positions of these angles on a circle with a radius of 1 float targetNormalX = Mathf.Cos((-targetAngle.y + 360) * Mathf.Deg2Rad); float targetNormalY = Mathf.Sin((-targetAngle.y + 360) * Mathf.Deg2Rad); float startNormalX = Mathf.Cos(startTrackAngleRelative.y * Mathf.Deg2Rad); float startNormalY = Mathf.Sin(startTrackAngleRelative.y * Mathf.Deg2Rad); if (incline) { targetNormalX = Mathf.Cos((-targetAngle.x + 360) * Mathf.Deg2Rad); targetNormalY = Mathf.Sin((-targetAngle.x + 360) * Mathf.Deg2Rad); startNormalX = Mathf.Cos(startTrackAngleRelative.x * Mathf.Deg2Rad); startNormalY = Mathf.Sin(startTrackAngleRelative.x * Mathf.Deg2Rad); } //the radius would be equal to 1 for a circle like this. Find how much the distances between the points account for the radius of the circle float percentageOfRadius = Mathf.Sqrt(Mathf.Pow(startNormalX - targetNormalX, 2) + Mathf.Pow(startNormalY - targetNormalY, 2)); //radius of the curve using the percentage calculations from above float radius = Mathf.Sqrt(Mathf.Pow(circleTargetX - startPosition.x, 2) + Mathf.Pow(circleTargetY - startPosition.z, 2)) / percentageOfRadius; //calculate the cirumference of this circle multiplied by the amount this curve takes up of the whole circle float curveLength = 2 * Mathf.PI * radius * (smallestAngleDifference.y / 360f); if (incline) { radius = Mathf.Sqrt(Mathf.Pow(circleTargetX - startPosition.z, 2) + Mathf.Pow(circleTargetY - startPosition.y, 2)) / percentageOfRadius; curveLength = 2 * Mathf.PI * radius * (smallestAngleDifference.x / 360f); } curveTracksNeeded = (curveLength / (trackBoneSize * boneAmount)); //curve too small if (curveTracksNeeded < 1) { cancel = true; } startTracksNeeded = 0; //Find difference between circleTarget and the target position targetTracksNeeded = (Mathf.Sqrt(Mathf.Pow(circleTargetX - targetPosition.x, 2) + Mathf.Pow(circleTargetY - targetPosition.z, 2)) / (trackBoneSize * boneAmount)); if (incline) { targetTracksNeeded = (Mathf.Sqrt(Mathf.Pow(circleTargetX - targetPosition.z, 2) + Mathf.Pow(circleTargetY - targetPosition.y, 2)) / (trackBoneSize * boneAmount)); } if ((targetAngle.y == 0 && !incline) || (targetAngle.x == 0 && incline)) { targetTracksNeeded = distanceFromStart / (trackBoneSize * boneAmount); curveTracksNeeded = 0; } } else if (!cancel) { //find intersection between line to the start of curve from the end of curve float endToStartCurveSlope = Mathf.Tan((((180 - targetAngle.y) / 2)) * Mathf.Deg2Rad); //the b value (b = y - mx) float endToStartCurveB = targetPosition.z - endToStartCurveSlope * targetPosition.x; if (incline) { endToStartCurveSlope = Mathf.Tan((((180 - targetAngle.x) / 2)) * Mathf.Deg2Rad); endToStartCurveB = targetPosition.y - endToStartCurveSlope * targetPosition.z; } //find intersection between this line and the start line (x = (b2 - b1) / (m1 - m2)) //this position will be the second point on the circle of the curve (end point), the first is the target track float circleStartX = (endToStartCurveB - startB) / (startSlope - endToStartCurveSlope); float circleStartY = endToStartCurveSlope * circleStartX + endToStartCurveB; //y = rsinA, x = rcosA //these are the positions of these angles on a circle with a radius of 1 float targetNormalX = Mathf.Cos((-targetAngle.y + 360) * Mathf.Deg2Rad); float targetNormalY = Mathf.Sin((-targetAngle.y + 360) * Mathf.Deg2Rad); float startNormalX = Mathf.Cos(startTrackAngleRelative.y * Mathf.Deg2Rad); float startNormalY = Mathf.Sin(startTrackAngleRelative.y * Mathf.Deg2Rad); if (incline) { targetNormalX = Mathf.Cos((-targetAngle.x + 360) * Mathf.Deg2Rad); targetNormalY = Mathf.Sin((-targetAngle.x + 360) * Mathf.Deg2Rad); startNormalX = Mathf.Cos(startTrackAngleRelative.x * Mathf.Deg2Rad); startNormalY = Mathf.Sin(startTrackAngleRelative.x * Mathf.Deg2Rad); } //the radius would be equal to 1 for a circle like this. Find how much the distances between the points account for the radius of the circle float percentageOfRadius = Mathf.Sqrt(Mathf.Pow(startNormalX - targetNormalX, 2) + Mathf.Pow(startNormalY - targetNormalY, 2)); //radius of the curve using the percentage calculations from above float radius = Mathf.Sqrt(Mathf.Pow(circleStartX - targetPosition.x, 2) + Mathf.Pow(circleStartY - targetPosition.z, 2)) / percentageOfRadius; //calculate the cirumference of this circle multiplied by the amount this curve takes up of the whole circle float curveLength = 2 * Mathf.PI * radius * (smallestAngleDifference.y / 360f); if (incline) { radius = Mathf.Sqrt(Mathf.Pow(circleStartX - targetPosition.z, 2) + Mathf.Pow(circleStartY - targetPosition.y, 2)) / percentageOfRadius; curveLength = 2 * Mathf.PI * radius * (smallestAngleDifference.x / 360f); } curveTracksNeeded = (curveLength / (trackBoneSize * boneAmount)); //curve too small if (curveTracksNeeded < 1) { cancel = true; } //Find difference between circleTarget and the target position startTracksNeeded = (Mathf.Sqrt(Mathf.Pow(circleStartX - startPosition.x, 2) + Mathf.Pow(circleStartY - startPosition.z, 2)) / (trackBoneSize * boneAmount)); if (incline) { startTracksNeeded = (Mathf.Sqrt(Mathf.Pow(circleStartX - startPosition.z, 2) + Mathf.Pow(circleStartY - startPosition.y, 2)) / (trackBoneSize * boneAmount)); } targetTracksNeeded = 0; } Func <int> totalTracksNeeded = () => Mathf.CeilToInt(startTracksNeeded) + Mathf.CeilToInt(curveTracksNeeded) + Mathf.CeilToInt(targetTracksNeeded); if (otherSide) { if (!incline) { smallestAngleDifference = new Vector3(smallestAngleDifference.x, -smallestAngleDifference.y, smallestAngleDifference.z); } else if (incline) { smallestAngleDifference = new Vector3(-smallestAngleDifference.x, smallestAngleDifference.y, smallestAngleDifference.z); } } //check if the generation was canceled or the track is too big or small if (cancel || totalTracksNeeded() > 250 || (curveTracksNeeded < 3 && targetAngle != Vector3.zero && !incline)) { totalTracksNeeded = () => 0; } //angle to start from when curves start if part of the curve is drawn during the start tracks Vector3 startTrackAngle = Vector3.zero; //has the first piece been edited already bool firstPieceEdited = false; //Amount of tracks already placed down int startTrackAmount = trackPieces.IndexOf(startTrack) + 1; for (int i = 0; i < totalTracksNeeded(); i++) { //should the i not increment at the end bool reset = false; Vector3 eulerAngles = startTrackAngleRelative; eulerAngles += currentAngle; //the total angle going through one whole track piece Vector3 totalTrackAngle = Vector3.zero; //angle that the tracks start with if they have a startTrack value that is not -1 Vector3 startAngle = Vector3.zero; GameObject premadeTrackPiece = null; //should a premade track piece be used instead of creating a new one bool usePremadeTrackPiece = false; float percentageOfTrack = 1; if (i < Mathf.CeilToInt(startTracksNeeded)) { //set it to the part of the track nessesary to finish drawing the startTracksNeeded percentageOfTrack = 1; if (startTracksNeeded - i < 1) { percentageOfTrack = startTracksNeeded - i; int curveStartNum = (int)((1 - percentageOfTrack) * boneAmount); totalTrackAngle = (smallestAngleDifference / (curveTracksNeeded * boneAmount)) * curveStartNum; startAngle = Vector3.zero; startTrackAngle = totalTrackAngle; smallestAngleDifference -= startTrackAngle; //the remaining part of the track can be used to start the curve curveTracksNeeded -= curveStartNum / boneAmount; } } if (i >= Mathf.CeilToInt(startTracksNeeded) && i < Mathf.CeilToInt(startTracksNeeded) + Mathf.CeilToInt(curveTracksNeeded)) { //then it is time to create a curve instead of just a straight line coming off the start track //calculate the adjustment needed for the curve eulerAngles = smallestAngleDifference / curveTracksNeeded * (i - Mathf.CeilToInt(startTracksNeeded)) + startTrackAngleRelative; eulerAngles += startTrackAngle; eulerAngles += currentAngle; totalTrackAngle = smallestAngleDifference / curveTracksNeeded; //set it to the part of the track nessesary to finish drawing the curveTracksNeeded percentageOfTrack = 1; if (curveTracksNeeded - (i - Mathf.CeilToInt(startTracksNeeded)) < 1) { percentageOfTrack = curveTracksNeeded - (i - Mathf.CeilToInt(startTracksNeeded)); //this means there are more tracks after the curve, part of the curve track can be used for that if (targetTracksNeeded > 0) { int curveStartNum = (int)((1 - percentageOfTrack) * boneAmount); int curveEndNum = (int)((percentageOfTrack) * boneAmount); startAngle = (smallestAngleDifference / (curveTracksNeeded * boneAmount)) * curveEndNum; totalTrackAngle = Vector3.zero; //the remaining part of the track can be used for the target tracks needed targetTracksNeeded -= curveStartNum / boneAmount; } } } if (i >= Mathf.CeilToInt(startTracksNeeded) + Mathf.CeilToInt(curveTracksNeeded)) { //back to straight path, but in the angle of the target eulerAngles = targetAngle; eulerAngles += currentAngle; totalTrackAngle = Vector3.zero; //set it to the part of the track nessesary to finish drawing the targetTracksNeeded percentageOfTrack = 1; if (targetTracksNeeded - (i - Mathf.CeilToInt(startTracksNeeded) - Mathf.CeilToInt(curveTracksNeeded)) < 1) { percentageOfTrack = targetTracksNeeded - (i - Mathf.CeilToInt(startTracksNeeded) - Mathf.CeilToInt(curveTracksNeeded)); } } int secondCurveStart = -1; if (percentageOfTrack < 1 && i < Mathf.CeilToInt(startTracksNeeded)) { //the remaining track will be used for the curve secondCurveStart = (int)((percentageOfTrack) * boneAmount); } if (percentageOfTrack < 1 && i >= Mathf.CeilToInt(startTracksNeeded) && i < Mathf.CeilToInt(startTracksNeeded) + Mathf.CeilToInt(curveTracksNeeded) && targetTracksNeeded > 0) { //the remaining track will be used for the curve secondCurveStart = (int)((percentageOfTrack) * boneAmount); } //check to see if this can merge with the start track if (!firstPieceEdited && i == 0 && ((startTrack.GetComponent <TrackPiece>().percentageOfTrack != 1 && startTrack.GetComponent <TrackPiece>().secondCurveStart == -1) || startTrack.GetComponent <TrackPiece>().modified)) { if (startTracksNeeded > 0) { percentageOfTrack = startTrack.GetComponent <TrackPiece>().percentageOfTrack; int curveStartNum = (int)((1 - percentageOfTrack) * boneAmount); TrackPiece startTrackScript = startTrack.GetComponent <TrackPiece>(); startAngle = startTrackScript.totalAngle; if (startTrackScript.modified) { startAngle = startTrackScript.oldTotalAngle; } else { startTrackScript.oldTotalAngle = startTrackScript.totalAngle; } secondCurveStart = (int)((percentageOfTrack) * boneAmount); reset = true; firstPieceEdited = true; usePremadeTrackPiece = true; premadeTrackPiece = startTrack; } else { percentageOfTrack = startTrack.GetComponent <TrackPiece>().percentageOfTrack; int curveStartNum = (int)((1 - percentageOfTrack) * boneAmount); int curveEndNum = (int)((percentageOfTrack) * boneAmount); TrackPiece startTrackScript = startTrack.GetComponent <TrackPiece>(); startAngle = startTrackScript.totalAngle; if (startTrackScript.modified) { startAngle = startTrackScript.oldTotalAngle; } else { startTrackScript.oldTotalAngle = startTrackScript.totalAngle; } totalTrackAngle = (smallestAngleDifference / (curveTracksNeeded * boneAmount)) * curveStartNum; //subtrack by the amount not done startTrackAngle = totalTrackAngle; smallestAngleDifference -= startTrackAngle; //remove this amount as it was already dealt with here targetTracksNeeded -= curveStartNum / boneAmount; secondCurveStart = (int)((percentageOfTrack) * boneAmount); reset = true; firstPieceEdited = true; usePremadeTrackPiece = true; premadeTrackPiece = startTrack; } } if (startTrackAmount + i < trackPieces.Count || usePremadeTrackPiece) { GameObject trackPiece = null; if (usePremadeTrackPiece) { trackPiece = premadeTrackPiece; premadeTrackPiece.GetComponent <TrackPiece>().modified = true; } else { trackPiece = trackPieces[i + startTrackAmount]; } Vector3 oldPosition = trackPiece.transform.position; Vector3 oldAngles = trackPiece.transform.eulerAngles; //reset position and angle before adjusting the track trackPiece.transform.position = Vector3.zero; trackPiece.transform.localEulerAngles = Vector3.zero; if (targetAngle == Vector3.zero) { //force total track angle to be zero totalTrackAngle = Vector3.zero; } //adjust the track trackPiece.GetComponent <TrackPiece>().AdjustTrack(totalTrackAngle, startAngle, percentageOfTrack, secondCurveStart); //premade track piece would already be in the correct position if (!usePremadeTrackPiece) { //calculate adjustments //this finds the last bone plus half of the track size (because position is based off the center of the object Vector3 modifiedPosition = trackPieces[i + startTrackAmount - 1].transform.Find("Bottom_Rail/Joint_3_3/Joint_1_3/Joint_2_4/Joint_3_4/Joint_4_3/Joint_5_3/Joint_6_3/Joint_7_3/Joint_8_3/Joint_9_3/Joint_10_3").position; //need to offset it by trackBoneSize by the angle Vector3 offset = (new Vector3(Mathf.Sin(eulerAngles.y * Mathf.Deg2Rad), 0, Mathf.Cos(eulerAngles.y * Mathf.Deg2Rad)) * (trackBoneSize * 5)); if (incline || eulerAngles.x != 0 || eulerAngles.y != 0) { offset = (new Vector3(0, -Mathf.Sin(eulerAngles.x * Mathf.Deg2Rad), Mathf.Cos(eulerAngles.x * Mathf.Deg2Rad)) * (trackBoneSize * 5)); //rotate the offset by the y angle incase it needs to be pointing in a different direction offset = MathHelper.RotatePointAroundPivot(offset, Vector3.zero, new Vector3(0, 1, 0) * eulerAngles.y); } //subtract offset trackPiece.transform.position = modifiedPosition - offset; //set track rotation (after adjustment to make sure the adjustment process goes well) trackPiece.transform.localEulerAngles = eulerAngles; } else { //set it to what it was before trackPiece.transform.position = oldPosition; trackPiece.transform.localEulerAngles = oldAngles; } //set chail lift variables TrackPiece trackPieceScript = trackPiece.GetComponent <TrackPiece>(); trackPieceScript.chainLift = chainLift; trackPieceScript.chainSpeed = defaultLiftSpeed; } else { //calculate adjustments //this finds the last bone plus half of the track size (because position is based off the center of the object Vector3 modifiedPosition = trackPieces[i + startTrackAmount - 1].transform.Find("Bottom_Rail/Joint_3_3/Joint_1_3/Joint_2_4/Joint_3_4/Joint_4_3/Joint_5_3/Joint_6_3/Joint_7_3/Joint_8_3/Joint_9_3/Joint_10_3").position; //need to offset it by trackBoneSize by the angle Vector3 offset = (new Vector3(Mathf.Sin(eulerAngles.y * Mathf.Deg2Rad), 0, Mathf.Cos(eulerAngles.y * Mathf.Deg2Rad)) * (trackBoneSize * 5)); if (incline || eulerAngles.x != 0 || eulerAngles.y != 0) { offset = (new Vector3(0, -Mathf.Sin(eulerAngles.x * Mathf.Deg2Rad), Mathf.Cos(eulerAngles.x * Mathf.Deg2Rad)) * (trackBoneSize * 5)); //rotate the offset by the y angle incase it needs to be pointing in a different direction offset = MathHelper.RotatePointAroundPivot(offset, Vector3.zero, new Vector3(0, 1, 0) * eulerAngles.y); } if (targetAngle == Vector3.zero) { //force total track angle to be zero totalTrackAngle = Vector3.zero; } GameObject trackPiece = AddTrackPiece(totalTrackAngle, modifiedPosition, eulerAngles, startAngle, offset, percentageOfTrack, secondCurveStart); //set chail lift variables TrackPiece trackPieceScript = trackPiece.GetComponent <TrackPiece>(); trackPieceScript.chainLift = chainLift; trackPieceScript.chainSpeed = defaultLiftSpeed; } //reset i if nessesary (this must be the last thing in the loop) if (reset) { i--; } } //remove all unneeded track pieces, don't add to i since trackPieces.Count will be continuing to shrink for (int i = Mathf.CeilToInt(startTrackAmount + totalTracksNeeded()); i < trackPieces.Count;) { RemoveTrackPiece(trackPieces[i]); } //reset last track back to normal if nessesary if (totalTracksNeeded() == 0 && startTrack.GetComponent <TrackPiece>().modified) { TrackPiece trackPiece = startTrack.GetComponent <TrackPiece>(); Vector3 oldPosition = trackPiece.transform.position; Vector3 oldAngles = trackPiece.transform.eulerAngles; //reset position and angle before adjusting the track trackPiece.transform.position = Vector3.zero; trackPiece.transform.localEulerAngles = Vector3.zero; //adjust the track back the how it was trackPiece.AdjustTrack(trackPiece.oldTotalAngle, Vector3.zero, trackPiece.percentageOfTrack, -1); //set it to what it was before trackPiece.transform.position = oldPosition; trackPiece.transform.localEulerAngles = oldAngles; startTrack.GetComponent <TrackPiece>().modified = false; } }