/// <summary> /// Attempts to generate a bouncy richochet path. Not guaranteed to leave make path successful /// </summary> /// <param name="mode"></param> /// <param name="path"></param> /// <param name="angleBundle"></param> void attemptBonucyRicochetPath(ricochetMode mode, RicochetPath path, Vector3 angleBundle) { Vector3 launchVector = generateLaunchVector(angleBundle); //Calculating launch direction Vector3 objectPositionWhenContactMade = generateStartingContactPoint(mode) + launchVector * _ricochetObjectRadius; //Calculating the starting point //Calculating the ricochet points... path.ricochetPositions.Add(objectPositionWhenContactMade); RaycastHit hitResults = new RaycastHit(); for (int i = 0; i < maxNumberofBounces; i++) { Physics.SphereCast(objectPositionWhenContactMade, _ricochetObjectRadius, launchVector, out hitResults, maxPathSegmentLength, interactingLayers, QueryTriggerInteraction.Ignore); if (hitResults.collider == null) //Nothing was hit... { path.ricochetPositions.Add(objectPositionWhenContactMade + launchVector * maxPathSegmentLength); break; } else if (hitResults.collider.gameObject.layer == LayerMask.NameToLayer(destinationLayer)) { //Found where it was supposed to go! End here objectPositionWhenContactMade = objectPositionWhenContactMade + hitResults.distance * launchVector; path.ricochetPositions.Add(objectPositionWhenContactMade); path.isSuccessful = true; break; } else //Just hit a bouncing surface { objectPositionWhenContactMade = objectPositionWhenContactMade + hitResults.distance * launchVector; path.bounces++; path.ricochetPositions.Add(objectPositionWhenContactMade); launchVector = Vector3.Reflect(launchVector, hitResults.normal); } } }
void drawReceptionAngle(Vector3 position, ricochetMode mode, float length) { Vector3 angleBundle = getAngleBundle(mode); Color drawColor = getDrawingColor(mode); Vector3 pathVector = Vector3.zero; //Receiving from right pathVector = Quaternion.AngleAxis(angleBundle.x, Vector3.up) * Vector3.forward; DebugExtension.DebugCapsule(position, position + pathVector * length, drawColor, _ricochetObjectRadius); //Receiving from left pathVector = Quaternion.AngleAxis(angleBundle.x, Vector3.down) * Vector3.forward; DebugExtension.DebugCapsule(position, position + pathVector * length, drawColor, _ricochetObjectRadius); //Receiving from up pathVector = Quaternion.AngleAxis(angleBundle.y, Vector3.left) * Vector3.forward; DebugExtension.DebugCapsule(position, position + pathVector * length, drawColor, _ricochetObjectRadius); if (angleBundle.z != 0) { //Receiving from down pathVector = Quaternion.AngleAxis(angleBundle.z, Vector3.right) * Vector3.forward; DebugExtension.DebugCapsule(position, position + pathVector * length, drawColor, _ricochetObjectRadius); } }
/// <summary> /// Generates the point at which this path shoudl start (from the player bullseye). /// This code relies on the assumption that for each bullseye later, a certain part of its bottom middle resion will be overlapped by the previous layer /// </summary> Vector3 generateStartingContactPoint(ricochetMode mode) { Vector3 startingPoint = Vector3.zero; startingPoint.z = target.position.z; //Setting the rects needed for the calculations... Rect targetRect = new Rect(); Rect overlappingRect = new Rect(Vector3.zero, Vector3.zero); switch (mode) { case ricochetMode.hit: targetRect = hitRect; break; case ricochetMode.nearmiss: targetRect = nearMissRect; overlappingRect = bufferRect; break; case ricochetMode.miss: targetRect = missRect; overlappingRect = nearMissRect; break; } startingPoint.y = Random.Range(targetRect.yMin, targetRect.yMax); if (overlappingRect.size.SqrMagnitude() != 0 && startingPoint.y <= overlappingRect.max.y) { //Only choose an x from the sides if (Random.Range(0, 2) == 1) { startingPoint.x = Random.Range(overlappingRect.xMin, targetRect.xMin); } else { startingPoint.x = Random.Range(overlappingRect.xMax, targetRect.xMax); } } else { //Choose any x startingPoint.x = Random.Range(targetRect.xMin, targetRect.xMax); } return(startingPoint); }
/// <summary> /// Returns the angle limits to a particular ricochet path mode /// </summary> /// <param name="mode"></param> /// <returns></returns> Vector3 getAngleBundle(ricochetMode mode) { switch (mode) { case ricochetMode.hit: return(maxHitAngles); case ricochetMode.nearmiss: return(maxNearMissAngles); case ricochetMode.miss: return(maxMissAngles); default: return(Vector3.zero); } }
Color getDrawingColor(ricochetMode mode) { switch (mode) { case ricochetMode.hit: return(Color.red); case ricochetMode.nearmiss: return(Color.yellow); case ricochetMode.miss: return(Color.green); default: return(Color.white); } }
/// <summary> /// Generates a straight path to the corruption sphere. /// If the scene is set up properly, this code should never leave path unsuccessful. /// </summary> /// <param name="mode"></param> /// <param name="path"></param> void generateGuaranteedPath(ricochetMode mode, RicochetPath path) { Vector3 launchVector = Vector3.forward; Vector3 objectPositionWhenContactMade = generateStartingContactPoint(mode) + launchVector * _ricochetObjectRadius; //Calculating the starting point //Calculating the ricochet points... path.ricochetPositions.Add(objectPositionWhenContactMade); RaycastHit hitResults = new RaycastHit(); Physics.SphereCast(objectPositionWhenContactMade, _ricochetObjectRadius, launchVector, out hitResults, maxPathSegmentLength, destinationLayerMask, QueryTriggerInteraction.Ignore); if (hitResults.collider == null) //Nothing was hit... { return; //Worse case scenario } else { objectPositionWhenContactMade = objectPositionWhenContactMade + hitResults.distance * launchVector; path.ricochetPositions.Add(objectPositionWhenContactMade); path.isSuccessful = true; } }
/// <summary> /// Genertates a richochet path. If the scene is set up properly, this is guaranteeded to return a successful path. Check just in case, though. /// </summary> /// <param name="mode"></param> /// <returns></returns> public RicochetPath GenerateSuccessfulPath(ricochetMode mode) { RicochetPath path = new RicochetPath(); path.mode = mode; Vector3 angleBundle = getAngleBundle(mode); for (int attempt = 0; attempt < 100; attempt++) { attemptBonucyRicochetPath(mode, path, angleBundle); if (path.isSuccessful) { break; } path.reset(); } if (!path.isSuccessful) { generateGuaranteedPath(mode, path); } return(path); }