This is the relevent portion of our cyclist code. Things I didn't mention before are how we raise VZPlayer's NeckHeight rather than try to change the origin of the bike model, and also how set down a wheelie based on speed or time.
Code:
public class VZAngleTracker
{
public void AddAngle(float speed)
{
mSamples[mIndex++] = speed;
mIndex = mIndex % kNumSamples;
}
public float GetPreviousAngle(int frames)
{
int index = mIndex - frames;
while (index < 0)
index += kNumSamples;
return mSamples[index];
}
static int kNumSamples = 45;
float[] mSamples = new float[kNumSamples];
int mIndex = 0;
}
public VZCycle : VZPlayer
{
VZAngleTracker mLookUpTracker = new VZAngleTracker();
float mOriginalNeckHeight;
float mOriginalMaxSpeed;
bool mWheelie = false;
float mWheelieStartSpeed = 0.0f;
float mWheelieStartTime = 0.0f;
void Start()
{
mOriginalNeckHeight = NeckHeight;
mOriginalMaxSpeed = MaxSpeed;
}
void Update()
{
HandleWheelies();
}
void HandleWheelies()
{
Vector3 angles = Controller.Head.localEulerAngles;
float headAngle = angles.x;
if (headAngle < 180.0f)
headAngle += 360.0f;
mLookUpTracker.AddAngle(headAngle);
const float kNeckVelocity = 0.5f;
const float kWheelieNeckOffset = 0.3f;
if (!mWheelie)
{
NeckHeight -= Time.deltaTime * kNeckVelocity;
if (NeckHeight < mOriginalNeckHeight)
NeckHeight = mOriginalNeckHeight;
// Check if we accelerated and are going somewhat fast.
float headDelta = headAngle - mLookUpTracker.GetPreviousAngle(10);
float lookAngle = angles.y;
if ((lookAngle > 345.0f || lookAngle < 20.0f) &&
Speed() > mOriginalMaxSpeed - 3.0f &&
headDelta < -15.0f &&
headAngle < 355)
{
// Pop a wheelie
mWheelie = true;
mWheelieStartSpeed = Speed();
mWheelieStartTime = Time.time;
}
}
else
{
NeckHeight += Time.deltaTime * kNeckVelocity;
if (NeckHeight > mOriginalNeckHeight + kWheelieNeckOffset)
NeckHeight = mOriginalNeckHeight + kWheelieNeckOffset;
// Update our wheelie start speed if we go above it. The bike is usually still accelerating when a wheelie starts,
// which makes it too easy to hold above mWheelieStartSpeed
if (Speed() > mWheelieStartSpeed)
mWheelieStartSpeed = Speed();
// See if we have diverged from our original wheelie speed by too much or held on too long
bool done = mWheelieStartSpeed - Speed() > 0.8f ||
Time.time - mWheelieStartTime > 8.0f ||
(headAngle - mLookUpTracker.GetPreviousSpeed(10) > 15.0f && headAngle > 370);
if (done)
{
// No more wheelie
mWheelie = false;
}
}
}
}