C++多小球非對心彈性碰撞(HGE引擎)

程序是一個月前完成的,以前一直沒正兒八經的來整理下這個程序,感受比較簡單,不過即便簡單的東西也要跟你們分享下。html

 

開篇

    開始上代碼以前我先說下我爲啥寫的這個程序,大三的時候學習C#接觸過GDI+而發現原來作圖形界面的程序也能夠這麼簡單。以後便開始用GDI+作起動畫、遊戲等,其中便有一個模擬多小球碰撞的,在CSDN上有分享過(  http://pan.baidu.com/s/1qWjTkmS ),不過如今回頭想一想那個程序仍是存在不少問題的,好比:沒考慮非對心碰撞問題,或者說是球體斜碰問題,幀率低問題,碰撞檢測精度不夠致使小球粘連問題(使用的是球體像素整型)。說到這裏想必使用過GDI+的同窗都會有一個想法就是GDI+用來作遊戲效率確實不行。因而呢轉戰C++,正好本身的畢設要寫一個C++ 2D遊戲,因此在寫遊戲項目之餘,便花費一天時間寫了這個模擬球體「彈性斜碰」程序。至於爲何要花這麼長時間,是由於大多數時間我都花在了這個「斜碰」問題上,這也是我要寫這篇博客的主要緣由,網上關於小球彈性 斜碰的程序確實不多。不信能夠百度下。

上代碼

模擬小球碰撞嘛,因此小球的實體類是必須的(Ball.h)
#pragma once
#include <math.h>
#include "hge.h"
class CBall
{
public:
    CBall();
    CBall(float _x,float _y,float _speedX ,float _speedY,float _radius ,DWORD _color,float _density = 1.0f);
    ~CBall(){};
public:
    bool IsCollision(CBall *ball,float dt);  //碰撞檢測
    void CollisionWith(CBall *ball);         //彈性正碰
    void CollisionWith2(CBall *ball);        //彈性斜碰
    void SwapColor(CBall *ball);             //好玩點,加個交換顏色
    void MoveNext(float dt,float _width,float _height);

//因爲程序不大,方便起見全部就都public了
public:
    float x;        //x軸座標
    float y;        //y軸座標
    float speed_x;  //x軸方向速度
    float speed_y;  //x軸方向速度
    float radius;   //球體半徑
    float density;  //密度
    float weight;   //質量
    DWORD color;    //混合顏色
};
從Ball的類成員定義中能夠看出來,球體的大概屬性基本包括全面了,不過多了個Color這個屬性是用來設置球體顏色的,由於圖片素材是純白實心圓,在使用color顏色進行頂點着色時候可直接設置得到該顏色的圓。
 
下面依次說下各個成員方法的做用,部分有代碼。
 
(1)構造方法 CBall( float  _x, float  _y, float  ...  , float  _density  =   1 .0f ); 對成員變量初始化,須要注意,密度默認是1.0f,而質量經過體積和密度的計算求得。【 球體質量 m=ρ*v , v = 4/3*π*r^3】。
 
(2)碰撞檢測,返回當前對象時候與參數ball發生碰撞,dt是一幀的時間。
bool CBall::IsCollision(CBall *ball,float dt)
{
    //計算的是下一刻的位置,以避免發生粘連
    float disX = (this->x+this->speed_x*dt)-(ball->x+ball->speed_x*dt);
    float disY = (this->y+this->speed_y*dt)-(ball->y+ball->speed_y*dt);
    float dis = sqrt(disX*disX+disY*disY);
    //判斷下一刻是否 發生碰撞
    if(dis < this->radius+ball->radius)
        return true;
    return false;
}
 
(3)彈性正碰  void  CBall : : CollisionWith(CBall  * ball) 根據動能定理和動量守恆定律得出公式
    //彈性正碰撞公式
     //v1' = [ (m1-m2)*v1 + 2*m2*v2 ] / (m1+m2)
     //v2' = [ (m2-m1)*v2 + 2*m1*v1 ] / (m1+m2)
碰撞後,兩小球的速度,方向,會發生改變。
 
(4)彈性斜碰,文章的主角,因爲計算比較複雜因此須要用到向量(Vector)。
void CBall::CollisionWith2(CBall *ball)
{
    //參考資料:
    //http://www.cnblogs.com/kenkofox/archive/2011/09/06/2168944.html
    //http://tina0152.blog.163.com/blog/static/119447958200910229109326/

    //球心點
    float x1 = this->x ;
    float y1 = this->y ;
    float x2 = ball->x ;
    float y2 = ball->y ;

    //碰撞處切平面向量t,及其法向量s
    hgeVector s(x2-x1, y2-y1);
    s.Normalize();//標準化矢量
    hgeVector t(x2-x1, y2-y1);
    t.Rotate(3.1415926f/2);
    t.Normalize();

    //速度向量
    hgeVector v1(this->speed_x,this->speed_y);
    hgeVector v2(ball->speed_x,ball->speed_y);

    //先算v1(v1x, v1y)在s和t軸的投影值,分別設爲v1s和v1t
    //再算v2(v2x, v2y)在s和t軸的投影值,分別設爲v2s和v2t:
    float v1s = v1.Dot(&s);
    float v1t = v1.Dot(&t);
    float v2s = v2.Dot(&s);
    float v2t = v2.Dot(&t);

    //轉換後於s向量上的彈性正碰撞。質量不等
    //彈性正碰撞公式
    //v1' = [ (m1-m2)*v1 + 2*m2*v2 ] / (m1+m2)
    //v2' = [ (m2-m1)*v2 + 2*m1*v1 ] / (m1+m2)
    float m1 = this->weight;
    float m2 = ball->weight;

    float temp_v1s = ((m1-m2)*v1s + 2*m2*v2s )/ (m1+m2);
    v2s = ((m2-m1)*v2s + 2*m1*v1s )/ (m1+m2);
    v1s = temp_v1s;

    //首先求出v1t和v2t在t軸的向量v1t'和v2t'(將數值變爲向量)
    //再求出v1s'和v2s'在s軸的向量v1s'和v2s'(將數值變爲向量)
    hgeVector v1tVector = t*v1t;
    hgeVector v1sVector = s*v1s;
    hgeVector v2tVector = t*v2t;
    hgeVector v2sVector = s*v2s;

    //新速度矢量
    hgeVector v1_new = v1tVector+v1sVector;
    hgeVector v2_new = v2tVector+v2sVector;

    //劃分紅x,y方向份量速度
    this->speed_x = v1_new.x;
    this->speed_y = v1_new.y;
    ball->speed_x = v2_new.x;
    ball->speed_y = v2_new.y;
}
 
(5)交換顏色,發生碰撞後的兩個小球進行顏色交換,純屬娛樂。
void CBall : :SwapColor(CBall  *ball)
 
(6)小球移動,參數 _width,_height分別是窗口的寬高,由於這個方法內包含邊界碰撞的檢測和反彈。
void CBall::MoveNext(float dt,float _width,float _height)
{
    float moveX = speed_x*dt;
    float moveY = speed_y*dt;
    //x方向邊界
    if (x+moveX<radius||x+moveX>_width-radius)
        speed_x = -speed_x;
    //Y方向邊界
    if(y+moveY<radius||y+moveY>_height-radius)
        speed_y = -speed_y;

    x+=speed_x*dt;
    y+=speed_y*dt;
}

 

主函數,使用 HGE引擎,看源文件吧這裏不詳細說了。
(HGE是一個小型的2D遊戲引擎,基於DirectX8,相關學習資料下載: http://pan.baidu.com/s/1dDtdd2h
 

結束語

大四快畢業了,如今才發現大學期間學的確實太少,玩的太多(DotAer哈哈),好多感慨,都化成兩個字「時間」。回想起當初剛上大一的時候,拿着書本照着上面一字不差的敲着C程序代碼,直到程序運行出來還不能理解程序是怎麼個原理,怎麼實現的,不過還好「時間」告訴了我。從大一學的 枯燥 只能用來ACM的C/C++到大二終於見到圖形界面卻又笨拙而不適合圖形界面開發的Java再到大三時讓圖形界面開發簡單至極卻又低效沒法知足遊戲開發的C#到最後又回到了最初那個高效而複雜的讓人抓狂的C++,就這樣走完了大學四年。同窗如今有很多出去工做了的,不過給個人感受就是你們好像都是隻知其一;不知其二,拿着恰好養活本身的工資,在不斷地學習着,不過時待同窗們都能找到本身滿意的工做,也但願本身找工做能順利。寫這篇文章是還在考慮要不要參加藍橋杯的決賽,畢竟我都大四了,並且最近的事情會好多。很差意思思路有點斷篇。言歸正傳,畢設在作一個「仿《保衛蘿蔔》塔防遊戲」,框架基本上搭建差很少了,還有部分須要完善的地方,在此先發個不完整版, http://pan.baidu.com/s/1dDEbK4L ,框架僅供參考。畢竟我是菜鳥級的,不少東西都只知其一;不知其二,因此 程序有什麼不妥的地方還望不吝提出。先謝謝了!
 
相關文章
相關標籤/搜索