遊戲中掉落效果的實現

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);
       }


      同樣的下降過程中也是可以類似的處理。

最後貼幾張圖。。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章