// Simulates the frisbee with empirically based model in the z and y-axis, and simple constant velocity on the x-axis void simulateFrisbee() { FrisbeeLocation cutoff = null; int cutoffIndex = 0; //Find a cutoff point where the frisbee is likely to still be in mid-flight foreach (FrisbeeLocation loc in throwBuffer) { //cutoff default simulationBegin is 0.7 times the travel distance from throw start to throw end if (loc.pos.z - throwBuffer[0].pos.z > simulationBegin * (throwBuffer[throwBuffer.Count - 1].pos.z - throwBuffer[0].pos.z)) { cutoff = loc; break; } cutoffIndex++; } if (cutoff != null) { //Calculate the velocities and angle to ground plane FrisbeeLocation prevLoc = throwBuffer[cutoffIndex - 4]; double vz0 = (cutoff.pos.z - prevLoc.pos.z) / (cutoff.time - prevLoc.time); double vy0 = (cutoff.pos.y - prevLoc.pos.y) / (cutoff.time - prevLoc.time); double vx0 = (cutoff.pos.x - prevLoc.pos.x) / (cutoff.time - prevLoc.time); Vector3 forwardDirection = cutoff.pos - prevLoc.pos; forwardDirection.Normalize(); float pitch = Vector3.Angle(forwardDirection, Vector3.ProjectOnPlane(forwardDirection, Vector3.up)); //window of numerical integration is set to 0.001s List <FrisbeeLocation> simulated = pred.simulate3D(cutoff.pos.x, cutoff.pos.y, cutoff.pos.z, vx0, vy0, vz0, pitch, 0.001F); //debug /*Debug.Log("Simulation len: " + simulated.Count); * Debug.Log("ThrowBuffer len: " + throwBuffer.Count); * Debug.Log("Cutoff and prev y-pos: " + cutoff.pos.y + " " + prevLoc.pos.y); * Debug.Log("Cutoff and prevloc timestamps" + cutoff.time + " " + prevLoc.time); * Debug.Log("Simulation parameters: " + cutoff.pos.y + " " + vz0 + " " + vy0 + " " + pitch);*/ simulationTrail.Create(simulated); endingSpeedText.text = "Ending speed before simulation: " + cutoff.forwardSpeed.ToString("F1") + " m/s"; } }
// called every frame void Update() { //playback speed control if (Input.GetKeyDown("g")) { if (speed >= 1.0F) { speed = 0.0F; } if (speed < 1.0F) { speed = speed + 0.25F; } } // Copy throwbuffer from ThrowController // Detects when we need to initialize if ((throwController.InPlayback() || throwController.WaitingForThrow()) && !initPlayback) { throwBuffer = throwController.getThrowBuffer(); if (throwBuffer != null) { initPlayback = true; transitioningToThrow = true; frisbeeMeshRenderer.sharedMaterial = playMaterial; // deprecated //trail.Deactivate(); //Debug.Log("Detached trail!"); // Create actual trail of the throw in the beginning of playback loop trail.Create(throwBuffer); //Simulate the frisbee and create simulated trail simulateFrisbee(); updateGreenPercentage(); } //Debug.Log("Init playback!"); pauseUntil = Time.time + 1.5F; //Slight pause before starting playback } else if (throwController.Throwing()) { if (transitioningToThrow) { transitioningToThrow = false; trail.Reset(); // clear trail for new throw simulationTrail.Reset(); // clear simulation trail // deprecated previous implementation using Unity builtin Trail //trail.Activate(); //Debug.Log("Attached trail!"); } initPlayback = false; frisbeeMeshRenderer.sharedMaterial = recMaterial; frisbeeModel.transform.localRotation = throwController.getCurrentRot(); frisbeeModel.transform.localPosition = throwController.getCurrentPos(); } else if (initPlayback && (Time.time > pauseUntil)) { UpdatePositionFromList(); } }