public async Task UsageWithFactory() { var wrapped = new TimeLimited(_Output); var timeConstraint = TimeLimiter.GetFromMaxCountByInterval(5, TimeSpan.FromMilliseconds(100)); var timeLimited = timeConstraint.Proxify <ITimeLimited>(wrapped); var watch = Stopwatch.StartNew(); for (var i = 0; i < 50; i++) { await timeLimited.GetValue(); } watch.Stop(); watch.Elapsed.Should().BeGreaterThan(TimeSpan.FromMilliseconds(900)); _Output.WriteLine($"Elapsed: {watch.Elapsed}"); var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(110)); Func <Task> cancellable = async() => { while (true) { await timeLimited.GetValue(cts.Token); } }; await cancellable.Should().ThrowAsync <OperationCanceledException>(); var res = await timeLimited.GetValue(); res.Should().Be(56); }
public void CreateBulletImpactDebris(Vector3 origin, Vector3 normal, float radius, int count, float startTimeInSeconds) { /* * Generate random points on the plane described by the impact position and * normal. * * Find two perpendicular vectors in plane to form a basis set. The second * is just the cross product of plane normal and first vector. The first * vector is any arbitrary vector parallel to plane. Equation of plane is: * * (P-O).N = 0 -> nx*x + ny*y + nz*z - (nx*ox+ny*oy+nz*oz) = 0 * * Where P = (x,y,z) is some arbitrary point on plane, O is a known point, * and N is the plane normal vector. Therefore: * * a = nx, b = ny, c = nz, d = -(N.O) * * We can solve for z: * * z = -(a*x + b*y + d) / c * * Then pick x and y to find z: * * x = 1, y = 2, z = -(a + 2b + d) / c * * If nz = 0, just pick x and z: * * y = -(a*x + c*z + d) / b * x = 1, z = 2, y = -(a + 2*c + d) / b * * Remember that this solves for the *point*, P. To get the axis, subtract * O. */ float a = normal.x; float b = normal.y; float c = normal.z; float d = -Vector3.Dot(normal, origin); Vector3 planeXAxis; Vector3 planeYAxis; if (Mathf.Abs(normal.z) < 1e-6) { if (Mathf.Abs(normal.y) < 1e-6) { // Normal along x axis, trivial to pick perpendicular axes planeXAxis = new Vector3(0, 0, 1); } else { planeXAxis = new Vector3(1, -(a + 2 * c + d) / b, 2) - origin; } } else { planeXAxis = new Vector3(1, 2, -(a + 2 * b + d) / c) - origin; } planeXAxis = Vector3.Normalize(planeXAxis); planeYAxis = Vector3.Normalize(Vector3.Cross(planeXAxis, normal)); const float delayTime = 0; float startTime = startTimeInSeconds; while (count-- > 0) { // Spawn cloud at a random location within a circular region Vector2 pos2d = RandomPosition2D(radius); Vector3 pos = origin + pos2d.x * planeXAxis + pos2d.y * planeYAxis; ExplosionSphere hemisphere = Instantiate(dustHemispherePrefab, pos, Quaternion.LookRotation(normal)) as ExplosionSphere; hemisphere.delayTime = startTime; hemisphere.transform.parent = this.transform; startTime += delayTime; // Launch pieces of flying debris in random directions along an outward- // facing hemisphere. Note that RandomPositionHemisphere() places a point // in a hemisphere with base in xy and axis along z (forward). Vector3 flyTowards = Quaternion.FromToRotation(Vector3.forward, normal) * Vector3.Normalize(RandomPositionHemisphere(radius)); int which = Random.Range(0, debrisFragmentPrefabs.Length); TimeLimited debris = Instantiate(debrisFragmentPrefabs[which], pos, Quaternion.identity) as TimeLimited; debris.transform.parent = this.transform; Rigidbody rb = debris.GetComponent <Rigidbody>(); rb.maxAngularVelocity = 30; rb.AddForce(rb.mass * (Vector3.up + flyTowards), ForceMode.Impulse); // slightly biased toward flying upward rb.AddRelativeTorque(10f * rb.mass * Vector3.right, ForceMode.Impulse); } }
// Update is called once per frame new void Update() { if (aimTime > 0 && aimTime <= aimIndicator) { sprite.color = Color.blue; } else if (damageable.IsInvincible()) { sprite.color = Color.red; } else if (recovery > 0) { sprite.color = Color.yellow; } else { sprite.color = Color.white; } aimTime -= Time.deltaTime; Vector3 aimVector; if (lockVector != Vector3.zero) { aimVector = lockVector; } else { aimVector = Target.transform.position; if (targetBody) { aimVector += (new Vector3(targetBody.velocity.x, targetBody.velocity.y, 0)) * Mathf.Min(lockTime, aimTime); } // Prevent aim from leaving the room aimVector.x = Mathf.Min(Mathf.Max(aimVector.x, constraint.bounds.min.x), constraint.bounds.max.x); aimVector.y = Mathf.Min(Mathf.Max(aimVector.y, constraint.bounds.min.y), constraint.bounds.max.y); } if (aimTime <= lockTime && lockVector == Vector3.zero) { lockVector = aimVector; } if (aimTime <= 0) { aimTime = aimDelay; if (Shot != null) { GameObject newShot = GameObject.Instantiate(Shot, transform.position, Quaternion.identity); Rigidbody2D shotBody = newShot.GetComponent <Rigidbody2D>(); if (shotBody) { Vector3 targetDirection = lockVector - transform.position; targetDirection.Normalize(); shotBody.velocity = targetDirection * shotSpeed; } TimeLimited timeLimited = newShot.GetComponent <TimeLimited>(); Scrollable scrollable = newShot.GetComponent <Scrollable>(); if (timeLimited) { timeLimited.Lifetime = 5.0f; if (scrollable) { scrollable.enabled = false; } } else { if (scrollable) { scrollable.viewCamera = ViewCamera; } } } lockVector = Vector3.zero; } aimRenderer.SetPosition(1, (aimVector - transform.position).normalized * aimLength); float aimRatio = aimTime / aimDelay; float lineWidth = Mathf.Lerp(maxAimWidth, minAimWidth, aimRatio); Color lineColor = Color.Lerp(maxAimColor, minAimColor, aimRatio); aimRenderer.startWidth = aimRenderer.endWidth = lineWidth; aimRenderer.startColor = aimRenderer.endColor = lineColor; if (recovery > 0) { recovery -= Time.deltaTime; if (recovery <= 0) { recovery = 0; damageable.DamagedByFaction = 0; } } else if (body.velocity == Vector2.zero && (Target.transform.position - transform.position).magnitude < dashAwayRange) { float xVel; float yVel; if (transform.localPosition.x > 0) { xVel = Random.Range(-1.0f, -0.5f); } else { xVel = Random.Range(0.5f, 1.0f); } if (transform.localPosition.y > 0) { yVel = Random.Range(-0.25f, 0.1f); } else { yVel = Random.Range(0.25f, 0.5f); } body.velocity = (new Vector2(xVel, yVel)).normalized * dashSpeed; } }