1. 計算運動參數
運動特徵: 豎直方向受到重力作用,水平方向有空氣阻力作用
第一種情況: 起拋點位置和掉落點位置處於同一水平面中。已知開始拋起的點位置和掉落目標位置,由此可以求出兩點之間的距離 distance;
運動軌跡如下所示:
①根據rand 函數產生出[0,1]之間的數值,作爲運動總的時間。並且heigt 也可以根據則會個隨機值擴大些,作爲運動的高度
t = seed()
height = 16 * seed() * seed();
②根據 sV/2 * t/2 = heght, 可以求出 sV
sV = 4*height / 4
③ 根據 sV = g * (t/2) . 求出
g= 2*sV /t;
④ 假設,水平方向,受到空氣阻力的作用,速度會減少,減少到 0.75 sH, 則根據水平方向速度距離關係,可以推導
(sH + 0.75 sH)/2 * t = distance => sH = (8/7) * distance / t
進一步,可以知道水平方向的減速度
hg = 0.25* sH / t
這樣,就可以實時計算出運動的位置了
Vector3 tDist = dirDistance * (initSpeedH * t - 0.5f * hVelocity * t * t);
tDist.y += initSpeedV * t- gVelocity * t * t * 0.5f;
第二種情況:起跑點和掉落點不是處於同一水平面中
這個時候,需要把紅色部分給加上來,纔是完整的運動軌跡。即確定紅色那部分運動時間,以及水平方向運動距離
① 第一種情況中的①②③ ,因爲計算都是用的運動的前半部分,都是一樣的。根據y 的差值結合計算出來變量,可以知道花費的時間
tAdd= Math::pow(2 * △y / g, 0.5f);
② 整個運動時間,也要加上剛纔計算出來的時間
t = t + tAdd;
③ 同樣假設,水平方向,受到空氣阻力的作用,速度會減少,減少到 0.75 sH, 則根據水平方向速度距離關係,可以推導
(sH + 0.75 sH)/2 * (t+tAdd) = distance => sH = (8/7) * distance / (t+tAdd)
進一步,可以知道水平方向的減速度
hg = 0.25* sH /(t+tAdd)
這樣,就可以實時計算出運動的位置了
Vector3 tDist = dirDistance * (initSpeedH * t - 0.5f * hVelocity * t * t);
tDist.y += initSpeedV * t- gVelocity * t * t * 0.5f;
第三種情況 如下所示,掉落到坑裏去了;此時,同樣需要計算出那部分運動的時間,tMus, 並減去這部分時間,來計算水平方向的減速度
源碼如下:
bool GoodsFallEffect::calcData(Vector3 & startPos,Vector3 & endPos)
{
if (!mRecord)
{
return false;
}
mContext.dirDistance = endPos - startPos;
float length = mContext.dirDistance.length();
mContext.dirDistance.normalize();
float cx = length;
float cy = 0;
float seed = rnd();
float height =10*seed *seed;//*Math::Pow(seed,0.5f);;
float t= seed; // second units
float n = 2 * height; //得到解
if (cx > 0)
{
if(endPos.y - startPos.y <3.0f)
{
mContext.initSpeedH = 1.3f * length / t;
mContext.initSpeedV = 4*height /t;
mContext.gVelocity = 2* mContext.initSpeedV / t;
mContext.angle = atanf(mContext.initSpeedV / mContext.initSpeedH);
mContext.initSpeed = Math::Pow(mContext.initSpeedH * mContext.initSpeedH + mContext.initSpeedV * mContext.initSpeedV, 0.5f);
mContext.hVelocity = 0.5f *mContext.initSpeedH / t;
mContext.maxHightTime = t*500.0f;
mContext.sumTime = t*1000.0f;
}
else
{
mContext.initSpeedV = 4*height /t;
mContext.gVelocity = 2*mContext.initSpeedV / t;
float devia = Math::Abs(endPos.y - startPos.y);
float tAdd = Math::Pow(2*devia / mContext.gVelocity, 0.5f);
// 此處有個近視,length
if(endPos.y > startPos.y)
{
mContext.initSpeedH = 1.3f * length / (t+tAdd);
mContext.maxHightTime = (t+tAdd)*500.0f;
mContext.sumTime = (t+tAdd)*1000.0f;
}
else
{
mContext.initSpeedH = 1.3f * length / (t-tAdd);
mContext.maxHightTime = (t-tAdd)*500.0f;
mContext.sumTime = (t-tAdd)*1000.0f;
}
}
}
else
{
mContext.initSpeedH = 0;
mContext.angle = PI/2.0f;
mContext.initSpeed = 20/seed;
}
Vector3 tDist = mContext.dirDistance *(mContext.initSpeedH * t *0.5f - 0.5f * mContext.hVelocity * 0.5f * t * 0.5f * t);
mContext.rotateAxis= Vector3(height * mContext.dirDistance.z - tDist.z * mContext.dirDistance.y, tDist.z * mContext.dirDistance.x - tDist.x * mContext.dirDistance. z, tDist.x * mContext.dirDistance.y - height *mContext.dirDistance. x);
return true;
}
2. 旋轉
運動參數計算好了,需要控制物品的的旋轉,模擬自然物品拋起來的自轉。此時採用四元數的旋轉,關鍵在於旋轉軸的選擇。
這裏我們選擇拋物線所在平面的法向量作爲旋轉軸。 取拋物線上兩個點向量做叉乘,此處選擇最高點和水平點;
Vector3 tDist = dirDistance *(initSpeedH * t *0.5f - 0.5f * hVelocity * 0.5f * t * 0.5f * t);
rotateAxis= Vector3(height * dirDistance.z - tDist.z * dirDistance.y, tDist.z * dirDistance.x - tDist.x * dirDistance. z, tDist.x * dirDistance.y - height *dirDistance. x);
...
node->rotate(mContext.rotateAxis,mAngle);
3. 大小變化
控制拋起過程中物品的逐漸變大,下降過程中的逐漸減小
配置文件中配置物品拋起來剛開始的minSize,最高點的maxSize, 如果上升中,即運動時間runTime < t/2 ; 既可以
if(mRunTime < maxHightTime){
f = (float)mRunTime/(float)mContext.maxHightTime;
scale = mContext.startScale + f*(mContext.maxHightScale - mContext.startScale);
scale = Clamp(scale,0.0f,mContext.maxHightScale);
}
同樣的下降過程中也是可以類似的處理。
最後貼幾張圖。。