[Çözüldü] OpenGL çarpışma algılama

Başlatan travego0403, 26 Mayıs 2011 - 15:30:16

« önceki - sonraki »

0 Üyeler ve 1 Ziyaretçi konuyu incelemekte.

travego0403

Geçenlerde şurada verdiğim örnek programı biraz genişleterek bir oyuna çevirdim.
http://forum.ubuntu-tr.net/index.php/topic,26799.0.html
Platform 'a' ve 'd' tuşları le hareket ediyor.
Oyunda bir türlü top ile platformun çarpıştığını algılayan bir algoritma geliştiremedim.Son yazdığım kodlarda ise platform hareketli iken çarpışma olduğunu varsayıyor ve top sekiyor, platform hareketli değil ise hiç bir çarpışma algılanmıyor. Örnek kodlar aşağıda bir çözüm önerisi verirseniz sevinirim. :)
#include <stdlib.h>
#include <GL/glut.h>
#include <iostream>
#include <math.h>
using namespace std;
class Top{
private:
    double hizx;               //Hizi
    double hizy;
    double kx;                 //Konum
    double ky;
    double r;
public:
    Top(){       
        srand(time(NULL));
        kx=(double)(rand()%60)/80;   // X-Konum
        ky=(double)(rand()%40)/60;
        hizx=0.006;                 //Hiz
        hizy=0.006;
        r=0.03;
        if(rand()%1000>500){
                hizx=-hizx;
        }
        if(rand()%1000>500){
                hizy=-hizy;
        }
   
    }
   
    Top(double a,double b,double c,double d,double e):hizx(a),hizy(b),kx(c),ky(d),r(e)
    {  }
    double getr(){
        return r;
    }
    double getkx(){
        return kx;
    }
    double getky(){
        return ky;
    }
    double degisHizx(){
        hizx=-hizx;
    }
    double degisHizy(){
        hizy=-hizy;
    }
    void topCiz(){
        int i=0;
        double x;
        double y;
        glBegin(GL_POLYGON);
        while(i<=360){           
                x=r*cos(i*M_PI/180)-kx;
                y=r*sin(i*M_PI/180)+ky;
                glVertex2f(x,y);
                i++;       
        }
        glEnd();   
    }
    void operator ++ (){
        if(kx>0.9-r||kx<-0.9+r){            //Duvardan çarpma şartları
                hizx=-hizx;
        }
        kx+=hizx;
        ky+=hizy;
        if(ky>0.7-r||ky<-0.7+r){
                hizy=-hizy;
        }
    }
};
class Platform{
private:
    double merkezx,merkezy;
    double genislik;
    double yukseklik;
    double x,y;        //sol ust kosenin koordinatlari
   
public:
    Platform():merkezx(0),merkezy(0),genislik(0),yukseklik(0)
    {  }
    Platform(double a,double b,double c,double d):merkezx(a),merkezy(b),genislik(c),yukseklik(d){
        y=merkezy+yukseklik/2;   //sol ust kose y degeri
        x=merkezx-genislik/2;    //sol ust kose x degeri
    }
    void platformCiz(){
        glColor3f(1,1,1);
        glBegin(GL_POLYGON);
        glVertex2d(x,y);
        glVertex2d(x+genislik,y);
        glVertex2d(x+genislik,y-yukseklik);
        glVertex2d(x,y-yukseklik);
        glEnd();
    }
    double getMerkezx(){
        return merkezx;
    }
    double getMerkezy(){
        return merkezy;
    }
    double getYukseklik(){
        return yukseklik;
    }
    double getGenislik(){
        return genislik;
    }
    double getx(){
        return x;
    }
    double gety(){
        return y;
    }
    void operator ++ (){
        if(x+genislik+0.05<=0.9){         
                x+=0.05;
        }               //Platform kaydirma hizi
    }
    void operator -- (){
        if(x>=-0.9){         
                x-=0.05;
        }
    }
   
};
void sahne();
void klavye(unsigned char,int,int);
bool carpismaKontrol(Top* , Platform*);
Top t1;
Platform p1(0,-0.5,0.5,0.04);

int main(int argc, char** argv) {
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_DOUBLE);
    glutInitWindowSize(600,600);
    glutCreateWindow("Oyun");   
    glutDisplayFunc(sahne);   
    glutKeyboardFunc(klavye);
    glutIdleFunc(sahne);
    glutMainLoop(); 
    return 0;

   
}
void sahne(){
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glColor3f(0,1,0); 
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_LINE_LOOP);
    glVertex2f(-0.9,0.7);               //Kutuyu çiz
    glVertex2f(0.9,0.7);
    glVertex2f(0.9,-0.7);
    glVertex2f(-0.9,-0.7);
    glEnd();   
    t1.topCiz();   
    p1.platformCiz();
    if(carpismaKontrol(&t1,&p1)){
        t1.degisHizy();       
    }
    glutSwapBuffers();
    ++t1;
}
void klavye(unsigned char tus,int x,int y){
    if(tus=='a'){
        --p1;
    }
    if(tus=='d'){
        ++p1;
    }
    if(tus==27){
        exit (0);
    }
    sahne();
}
bool carpismaKontrol(Top *top1, Platform *pl1){
    bool durum=false;
   
    double pl1x,pl1y,top1x,top1y,r;
    double pl1genislik,pl1yukseklik;
    pl1x=pl1->getMerkezx();
    pl1y=pl1->getMerkezy();
    pl1yukseklik=pl1->getYukseklik();
    pl1genislik=pl1->getGenislik();
    top1x=top1->getkx();
    top1y=top1->getky();
    r=top1->getr();
    double farkx,farky;
    farkx=fabs(pl1x-top1x);
    farky=fabs(pl1y-top1y);
    if((farkx<=(pl1genislik/2+r))&&(farky<=(pl1yukseklik/2+r))){
        durum=true;
    }   
   
    return durum;   
   
}



Mesaj tekrarı yüzünden mesajınız birleştirildi. Bu mesajın gönderim tarihi : 27 Mayıs 2011 - 15:29:45

Tamam arkadaşlar sorunu çözdüm, sorun classlardaki ufak tefek hatalardan kaynaklanıyormuş.En yakın zamanda kodları paylaşırım.
Konu kilitlenebilir ve silinebilir.
"Matematik bir dildir ve bu dilde şairlere fizikçi denir." Richard Feynman

Erdem

Çözüldüğüne sevindim  8) Aslında ben de bu konu üzerinde bir şeyler yazmak istiyordum. Ama hafta içi vaktim olamayabiliyor bazen..

Basit olarak aslında bir daire ile dikdörtgensel bir cismin çarpışma algılaması yapılabiliyor. Ama ikinci yöntem bana çok ilginç geldi. Burada bir cismi rastgele bir eksene yansıtıyoruz ve projeksiyon vektörünü buluyoruz. Daha sonra bu cisimlerin eksen üzerinde yansımalarını kullanarak çarpışma algılamasını hazırlıyoruz.

Gerçekten çok ilginç  ;) Ben de kendi yazdığım oyun için bir çarpışma algılaması yapmadım. Ama yaptığımda burada bahsedilen teknikleri kullanmayı düşünüyorum.

http://www.metanetsoftware.com/technique/tutorialA.html
Eğer Arch Linux tabanlı bir dağıtıma geçmek isterseniz Arcolinux D sürümünü buradan indirebilirsiniz.

Elektronik

travego0403

Evet çarpışmaların algılanması oyunlarda başlı başına bir derya. :)
Bu oyunda iki dikdörtgenin çarpışmasını kullandım. Fazla bir hassasiyet aramadığım için işimi görüyor.
Yukarıdaki kodda asıl sorun platformun o anki konumunu veren üye fonksiyonlarda imiş, onları düzeltince çalıştı. :D
"Matematik bir dildir ve bu dilde şairlere fizikçi denir." Richard Feynman

Erdem

#3
Aslında bir daire ile bir dikdörtgenin de çarpışma algılamasını yapabilirsin. Basit dediğim yöntem bu şekildeydi.

Bir daire ile bir dikdörtgenin çarpışma algılamasını yapabilmek için ilkönce dikdörtgenin dairenin merkezine en yakın noktasını buluyorsun. Burada kırmızı kısımlar.



if (merkez.x < kutu.x) {
    enyakın.x = kutu.x;
}

Bu üstteki şekillerin hepsinde görüldüğü üzere dairenin merkezi dikdörtgenin solundaysa en yakın nokta kutu'nun x koordinatına eşit oluyor.



Eğer dairenin merkezi dikdörtgenin sağındaysa gene bu x koordinatını buluyoruz. SDL için Rect denilen dikdörtgen yapılar vardır. Bu yapılarla bir alan ifade edebiliriz. SDL koordinat konumu olarak bir dikdörtgenin sol üst köşesini kabul ediyor. Bu dikdörtgen yapılar sadece x y koordinatları ve genişlik yükseklik bilgisi tutuyor.Bu yüzden x koordinatını bulmak için:

else if (merkez.x > kutu.x + kutu.genişlik) {
    enyakın.x = kutu.x + kutu.genişlik;
}



Eğer dairenin merkezinin x koordinatı kutunun sağında veya solunda değilse ortasındadır. Bu durumda da enyakın noktanın x koordinatı dairenin merkezinin x koordinatına eşit oluyor.

else enyakın.x = merkez.x;

y koordinatları için de aynı mantığı tekrar ettikten sonra dairenin merkezi ile x ve y koordinatlarını bulduğumuz enyakın noktanın arasındaki uzaklığı hesaplıyoruz. Eğer bu uzaklık dairenin yarıçapından küçükse evet çarpışma olmuştur diyoruz, değilse olmamıştır.

Ama dediğim gibi en çok ilk verdiğim bağlantıdaki hoşuma gitti  :D Örneğin bir daire ile bir dikdörtgenin çarpışma algılamasında daireyi sürükleyerek neler olduğunu görebiliyorsun.

Eğer Arch Linux tabanlı bir dağıtıma geçmek isterseniz Arcolinux D sürümünü buradan indirebilirsiniz.

Elektronik

heartsmagic

Silmek ne demek, böyle güzel başlıklar her daim kalmalı forumda :)
Bir süre daha fikir paylaşımı olabilir diye açık bırakalım başlığı.
Hayattan çıkarı olmayanların, ölümden de çıkarı olmayacaktır.
Hayatlarıyla yanlış olanların ölümleriyle doğru olmalarına imkân var mıdır?


Böylece yalan, dünyanın düzenine dönüştürülüyor.

travego0403

Programın son halini vereyim. Zaman buldukça geliştirmeye devam ederiz :)
Elimden geldiğince nesne yönelimli yazmaya çalıştım, bu konuda tecrübeli arkadaşlar fikirlerini bildirirlerse sevinirim.
İleride topun çarpacağı başka nesnelerde ekleyeceğim, çarptığı zaman kaybolacak. Belki oyun başladıktan sonra topun hızı arttırılabilir oyunun zorlaşması için.
Bilinen buglar:
*Top platforma yandan çarparsa platformun içine giriyor.İnşallah zaman bulursam düzelteceğim. :D
*Şimdilik topa verilen ilk sürat (Sürat != Hız Hız vektörel bir büyüklüktür) değişmediği için, top sürekli yatayla 45 derecelik bir açıyla gelip gidiyor. Top platforma çarptığı anda platform hareketli ise topun yönü fizik yasalarına uygun şekilde değişmelidir.

#include <stdlib.h>
#include <GL/glut.h>
#include <iostream>
#include <math.h>
using namespace std;
class Top{
private:
    double hizx;               //Hizi
    double hizy;
    double kx;                 //Konum
    double ky;
    double r;
public:
    Top(){       
        srand(time(NULL));
        kx=(double)(rand()%60)/80;   // X-Konum
        ky=(double)(rand()%40)/60;
        hizx=0.007;                 //Hiz
        hizy=0.007;
        r=0.03;
        if(rand()%1000>500){
                hizx=-hizx;
        }
        if(rand()%1000>500){
                hizy=-hizy;
        }
   
    }
   
    Top(double a,double b,double c,double d,double e):hizx(a),hizy(b),kx(c),ky(d),r(e)
    {  }
    double getr(){
        return r;
    }
    double getkx(){
        return kx;
    }
    double getky(){
        return ky;
    }
    double degisHizx(){
        hizx=-hizx;
    }
    double degisHizy(){
        hizy=-hizy;
    }
    void topCiz(){
        int i=0;
        double x;
        double y;
        glBegin(GL_POLYGON);
        while(i<=360){           
                x=r*cos(i*M_PI/180)+kx;
                y=r*sin(i*M_PI/180)+ky;
                glVertex2f(x,y);
                i++;       
        }
        glEnd();   
    }
    void operator ++ (){
        if(kx>0.9-r||kx<-0.9+r){            //Duvardan çarpma şartları
                hizx=-hizx;
        }
        kx+=hizx;
        ky+=hizy;
        if(ky>0.7-r||ky<-0.7+r){
                hizy=-hizy;
        }
    }
};
class Platform{
private:
    double merkezx,merkezy;
    double genislik;
    double yukseklik;
    double x,y;        //sol ust kosenin koordinatlari
   
public:
    Platform():merkezx(0),merkezy(-0.5),genislik(0.5),yukseklik(0.06)
    {  }
    Platform(double a,double b,double c,double d):merkezx(a),merkezy(b),genislik(c),yukseklik(d){
       
    }
    void platformCiz(){
        y=merkezy+yukseklik/2;   //sol ust kose y degeri
        x=merkezx-genislik/2;    //sol ust kose x degeri
        glColor3f(1,1,1);
        glBegin(GL_POLYGON);
        glVertex2d(x,y);
        glVertex2d(x+genislik,y);
        glVertex2d(x+genislik,y-yukseklik);
        glVertex2d(x,y-yukseklik);
        glVertex2d(x,y);
        glEnd();
    }
    double getMerkezx(){
        x=merkezx-genislik/2;    //sol ust kose x degeri
        return merkezx;
    }
    double getMerkezy(){
        y=merkezy+yukseklik/2;   //sol ust kose y degeri
        return merkezy;
    }
    double getYukseklik(){
        return yukseklik;
    }
    double getGenislik(){
        return genislik;
    }
    double getx(){
        return x;
    }
    double gety(){
        return y;
    }
    void operator ++ (){ // Platformu saga kaydirmak icin
        if(merkezx+genislik/2<0.9){         
                merkezx+=0.05;         //Platform kaydirma hizi
        }             
    }
    void operator -- (){
        if(merkezx-genislik/2>-0.9){         
                merkezx-=0.05;
        }
    }
   
};
void sahne();
void klavye(unsigned char,int,int);
bool carpismaKontrol(Top* , Platform*);
Top t1;
Platform p1(0,-0.5,0.5,0.06);
int sayac=0;

int main(int argc, char** argv) {
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_DOUBLE);
    glutInitWindowSize(600,600);
    glutCreateWindow("Oyun");   
    glutDisplayFunc(sahne);   
    glutKeyboardFunc(klavye);
    glutIdleFunc(sahne);
    glutMainLoop(); 
    return 0;

   
}
void sahne(){
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glColor3f(0,1,0); 
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_LINE_LOOP);
    glVertex2f(-0.9,0.7);               //Kutuyu çiz
    glVertex2f(0.9,0.7);
    glVertex2f(0.9,-0.7);
    glVertex2f(-0.9,-0.7);
    glEnd();   
    t1.topCiz();   
    p1.platformCiz();
    if(carpismaKontrol(&t1,&p1)){
        t1.degisHizy();
    }
    glutSwapBuffers();
    ++t1;
}
void klavye(unsigned char tus,int x,int y){
    if(tus=='a'){
        --p1;
    }
    if(tus=='d'){
        ++p1;
    }
    if(tus==27){
        exit (0);
    }
    sahne();
}
bool carpismaKontrol(Top *top, Platform *platform){
    bool durum=false;
    double topx,topy,r;
    topx=top->getkx();
    topy=top->getky();
    r=top->getr();
       
    double platformx,platformy,platformGenislik,platformYukseklik;
    platformx=platform->getx();
    platformy=platform->gety();
    platformYukseklik=platform->getYukseklik();
    platformGenislik=platform->getGenislik();
   
    double platformSol,platformSag,platformUst,platformAlt;
    platformUst=platformy;
    platformAlt=platformy-platformYukseklik;
    platformSol=platformx;
    platformSag=platformx+platformGenislik;
   
    if(topx-r>=platformSol&&topx+r<=platformSag&&topy-r<=platformUst&&topy+r>=platformAlt){
        cout<<"Gummmmmm :)) Top sektirme sayiniz:"<<++sayac<<endl;       
        durum=true;       
    }
    return durum;
}
"Matematik bir dildir ve bu dilde şairlere fizikçi denir." Richard Feynman

Erdem

Güzel ben de bir tane pong yapmayı planlıyorum  :D

Aslında oyunun çarpışma algılaması ve animasyon bölümlerini hazırlamayı düşünüyorum. Bu yüzden test programı olarak yapmayı düşündüm. Ama hem vakit azlığı hem de aynı anda GL başlık dosyaları için D ilintileri yazmak durumunda olduğum için biraz yavaş gidiyor  :D

Aklıma gelenler...

Sınıf tasarımı için bir TemelOyun nesnesi olabilir daha sonra bunun diğer özelliklerini üst sınıflar devralırlar. Örneğin HareketliOyunNesnesi ve HareketsizOyunNesnesi gibi.. Çiz, Güncelle gibi işlevler TemelOyunNesnesinde abstract olarak tanımlanabilir. Yani bu işlevleri üst sınıflar kendileri belirlerler..

Oyun döngüsünü ilklendir, içerik yükle, çiz, güncelle gibi bölümlere ayırabiliriz. Böylece kodun bakımını yapmak daha kolay olur.

Vector işlemleri için basit bir Vector2 yapısı tanımlanabilir. Daha sonra bunların toplama, çıkarma, normal bulma vs.. gibi işlevleri yazılabilir. Vector2 kullanmayan bir oyun düşünemiyorum  ;)

void operator++ hem biraz burada mantıksız olmuş hem de böyle tanımlanmaz. Ama örneğin Vector2 yapısı, sınıfı için kesinlikle yapmak isterdik :) O zaman da geleneksel olarak şöyle yazabilirdik.

inline Vector2D operator+(const Vector2D & soldaki, const Vector2D & sagdaki)
{
    Vector2D sonuc(soldaki);
    sonuc.x += sagdaki.x;
    sonuc.y += sagdaki.y;

    return sonuc;
}


Yandan çarpıp içine girme  ;D durumunu yukarda anlattığım mantıkla dene bakalım. Ben game programming gems diye bir kitapta eğer hız vektörse ve örneğin platformu geçebilecek şekilde büyük bir değeri varsa platforma hiç uğramadan içinden geçebileceğini okumuştum. Bunun çözüm yöntemi de orada anlatıyor.

45 derecelik açı olayını da bahsettiğim gibi bir Vector2 ile halledebilirsin.

Bir de platformun hareketi biraz daha akıcı olabilir

Ayrıca örneğin topun hareket et ya da güncelle kodunda.

// hareketEt  <-- normal şekilde hareket eder
// çarpışmaVarMı <-- çarpışma varsa topu platformun sınırlarına taşı

(daha bir şey çizmediğimiz için istediğimiz gibi geri alabiliriz)

//çiz

şeklinde olabilir. Bunun bir örneğini ben burada kullandım.

https://github.com/erdemoncel/oyun/blob/master/src/oyun.d

Örneğin oyuncu ekran sınırları dışına gitmişse tekrar geri alıyoruz.

Şimdilik aklıma gelenler bunlar. İyi kodlamalar  :D
Eğer Arch Linux tabanlı bir dağıtıma geçmek isterseniz Arcolinux D sürümünü buradan indirebilirsiniz.

Elektronik

travego0403

Güzel fikirlerin için teşekkürler  ;)

Vektör konusunda hem okuduğum bölümle alakalı(bazı derslerdeki hesaplamalarda program yazıpta hesaplatmak basit oluyor :D) hemde bu gibi programlarda kullanabileceğim bir 3 boyutlu bir  vektör sınıfı yazmıştım. Skaler çarpım, vektörel çarpım gibi konulardada da geliştiriyordum. Bilgisayarda sistem değişikliği yapınca yarım kaldı, kayboldu gitti.Kesinlikle böyle bir sınıf gerekli.
"Matematik bir dildir ve bu dilde şairlere fizikçi denir." Richard Feynman

Hatti

glutKeyboardUpFunc işlevini de tanımlarsak tahtanın hareketini akıcı hale getirme imkanı olur.

glutKeyboardFunc ve glutKeyboardUpFunc işlevlerinden aldığımız değerleri bellekte klavyenin tuşlarının durumunu tutmak için kullanacağımız bir bayrak değişkenleri dizisine atayarak daha sonra buradan sorgulama yapmak hızlı sonuç verecektir.

Geliştirmeye devam  :)

travego0403

@Hatti
glutKeyboardUpFunc işlevini bilmiyorum acaba nasıl kullanıldığını argüman olarak neleri aldığını basit bir örnek ile gösterebilirmisin? Bide bu 2.plattformu koyunca program mevcut haliyle bir oyuncu klavyeden tuşa basarken diğer oyuncunun tuşları algılanmıyor.Yani iki platform aynı anda hareket etmiyor, söylediğin gibi bir diziye aktarıp buradan okumayla bu sorunda aşılabilir sanırsam.
"Matematik bir dildir ve bu dilde şairlere fizikçi denir." Richard Feynman

Hatti