Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

29.04.2014, 19:44

Ball über Terrain führen, Ball klebt fest

Hallo,

ich habe folgendes Problem: ich möchte einen Ball über ein Terrain führen, sodass er mit Höhen und Tiefen kollidiert bzw. diese mitläuft. Soweit klappt das auch alles, leider bewegt sich mein Ball aber nicht unabhängig vom Terrain sondern er bleibt daran kleben. Man fährt so zu sagen mit Ball und Terrain über die Höhen eines unsichtbaren Terrains.
Hier sind die beiden Dateien in denen ich, zumindest in einer den Fehler, vermute. Wäre super, wenn mir jemand den entscheidenden Hinweis geben könnte :) (über diverse Schönheitsfehler darf hinweg gesehen werden)

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
    //Terrain Zeichnen
    D3D.SetRS(D3DRS_CULLMODE, D3DCULL_NONE);
    D3D.SetRS(D3DRS_LIGHTING, FALSE);

    D3D->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
    D3D->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
    D3D->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
    D3D.SetTexture(0, g_pTerrainTexture);

    D3D->SetStreamSource(0, g_TerrainVertex->GetVB(), 0, sizeof(TerrainVertex));
    D3D->SetFVF(CUSTOMFVF);
    D3D->SetIndices(g_TerrainIndex->GetIB());
    D3D->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,WIDTH*HEIGHT,0,(WIDTH-1)*(HEIGHT-1)*2);

    //Ende Terrain, Licht wieder an

    D3D.SetRS(D3DRS_LIGHTING, TRUE);

    // Motion-Blurring
    if(D3D.GetCaps().SrcBlendCaps & D3DPBLENDCAPS_BLENDFACTOR)
    {
        // Alpha-Blending aktivieren und verhindern, dass in den Z-Buffer geschrieben wird
        D3D.SetRS(D3DRS_ZWRITEENABLE, FALSE);
        D3D.SetRS(D3DRS_ALPHABLENDENABLE, TRUE);
        D3D.SetRS(D3DRS_SRCBLEND, D3DBLEND_BLENDFACTOR);
        D3D.SetRS(D3DRS_DESTBLEND, D3DBLEND_INVBLENDFACTOR);

        // 9 Samples
        for(float f = 0.1f; f <= 1.0f; f += 0.1f)
        {
            // Blendfaktor (Opazität) dieses Samples bestimmen
            DWORD dwFactor = (DWORD)((1.0f - f) * 63.0f);
            D3D.SetRS(D3DRS_BLENDFACTOR, 0xFF000000 | dwFactor | (dwFactor << 8) | (dwFactor << 16));

        }

        D3D.SetRS(D3DRS_ZWRITEENABLE, TRUE);
        D3D.SetRS(D3DRS_ALPHABLENDENABLE, FALSE);
    }

    // ------------------------------------------------------------------

    // Alle Bälle rendern
    for(DWORD dwBall = 0; dwBall < 16; dwBall++)
    {
        if(m_aBall[dwBall].m_bExists)
        {
            // Rendern!
            m_aBall[dwBall].Render(fTime);
        }
    }
    // Szene beenden
    D3D->EndScene();

    return TB_OK;
}

// __________________________________________________________________
// Initialisiert einen Level
tbResult CGame::InitLevel(int iLevel)
{
    // Sound für neuen Level abspielen
    g_pBreakanoid->m_apSound[2]->PlayNextBuffer();

    // Neuen Level setzen
    m_iLevel = iLevel;
    m_bPaused = FALSE;
    m_bGameOver = FALSE;

    //Textur laden
    g_pTerrainTexture = tbTextureManager::Instance().GetTexture("Bubbles.jpg");
    if(g_pTerrainTexture == NULL) return TB_ERROR;

    // Höhendaten einlesen
    float flt_HeightData[WIDTH][HEIGHT];
 
     std::ifstream f_DataFile;
 
     f_DataFile.open("Gebirge.raw", std::ios::binary);
 
     if (f_DataFile.is_open())
     {

        for (int x=0;x< WIDTH;x++)        {

            for (int z=0; z< HEIGHT;z++)           
            {
                cv_Vertices[z*WIDTH + x].vPosition = tbVector3(float(x)-15.0f,f_DataFile.get()/50,float(z)-4.0f);

                cv_Vertices[z*WIDTH + x ].vTexture = tbVector2((((float)(x) / (float)(HEIGHT - 1) - 0.5f) * 200.0f* 0.01f),(((float)(-z) / (float)(HEIGHT - 1) + 0.5f) * 200.0f* 0.01f)) ; 
                
            }
        }
    }else{
        return TB_ERROR;
    }

    f_DataFile.close();

    //Vertexbuffer erstellen
    g_TerrainVertex = new tbVertexBuffer;
    if (g_TerrainVertex->Init(WIDTH*HEIGHT*sizeof(TerrainVertex), sizeof(TerrainVertex), CUSTOMFVF, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DPOOL_DEFAULT ))
     {
        return TB_ERROR;
     }

    // Nun der Index-Buffer (16 Bits pro Index)
    g_TerrainIndex = new tbIndexBuffer;
    if(g_TerrainIndex->Init((WIDTH-1)*(HEIGHT-1)*6 * sizeof(short), sizeof(short), D3DFMT_INDEX16,D3DUSAGE_WRITEONLY, D3DPOOL_MANAGED))
    {
        // Fehler!
        return TB_ERROR;
    }

     // Alle Vertizes eintragen und den Vertex-Buffer aktualisieren
    g_TerrainVertex->AddVertices(WIDTH*HEIGHT, cv_Vertices);
    if(g_TerrainVertex->Update()) return TB_ERROR;

    // Den Index-Buffer ausfüllen
    short s_Indices[(WIDTH-1)*(HEIGHT-1)*6];
 
     for (int x=0;x< WIDTH-1;x++)    {

        for (int y=0; y< HEIGHT-1;y++)        {
            s_Indices[(x+y*(WIDTH-1))*6+2] = x+y*WIDTH;
            s_Indices[(x+y*(WIDTH-1))*6+1] = (x+1)+y*WIDTH;
            s_Indices[(x+y*(WIDTH-1))*6] = (x+1)+(y+1)*WIDTH;

            s_Indices[(x+y*(WIDTH-1))*6+3] = (x+1)+(y+1)*WIDTH;
            s_Indices[(x+y*(WIDTH-1))*6+4] = x+y*WIDTH;
            s_Indices[(x+y*(WIDTH-1))*6+5] = x+(y+1)*WIDTH;

        }
    }

    g_TerrainIndex->AddIndices((WIDTH-1)*(HEIGHT-1)*6, s_Indices);
    if(g_TerrainIndex->Update()) return TB_ERROR;

// __________________________________________________________________
// Erstellt einen neuen Ball
int CGame::CreateBall(tbVector3 vPosition,
                      tbVector3 vVelocity,
                      BOOL bGrabbed)
{
    CBall* pBall;

    // Freien Ball suchen
    for(int iBall = 0; iBall < 16; iBall++)
    {
        pBall = &m_aBall[iBall];

        if(!pBall->m_bExists)
        {
            // Freier Ball gefunden! Ausfüllen!
            // Speicherbereich zurücksetzen.
            ZeroMemory(pBall, sizeof(CBall));

            pBall->m_bExists = TRUE;
            pBall->m_pGame = this;
            pBall->m_vPosition = vPosition;
            pBall->m_vVelocity = vVelocity;

            // Index des neuen Balls liefern
            return iBall;
        }
    }

    // Kein Platz mehr!
    return -1;
}


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Bewegt einen Ball
tbResult CBall::Move(float fTime)
{
    BOOL        bWall;
    tbVector3   vBlock;
    tbVector3   yTerrain;
    float       fDistLeft;
    float       fDistRight;
    float       fDistTop;
    float       fDistBottom;
    float       fMinDist;
    int         iSound;
    int         iBuffer;
    

    // Position verändern
    m_vPosition += m_vVelocity * fTime;

        // Auf die Pfeiltasten reagieren (m_vPaddleVel ändern)
    m_vVelocity.x += g_pfButtons[TB_KEY_RIGHT] * 10.0f * fTime;
    m_vVelocity.x -= g_pfButtons[TB_KEY_LEFT] * 10.0f * fTime;
    m_vVelocity.z += g_pfButtons[TB_KEY_UP] * 10.0f * fTime;
    m_vVelocity.z -= g_pfButtons[TB_KEY_DOWN] * 10.0f * fTime;

    m_KollPos = m_vPosition + tbVector3(-7.0f,0.0f,2.0f);

        // Kollision mit dem Terrain berechnen
    for(DWORD dwTerrain = 0; dwTerrain < WIDTH*HEIGHT; dwTerrain++)
    {       
        
            yTerrain = m_pGame->cv_Vertices[dwTerrain].vPosition;
            

            // Befindet sich der Ball im Kollisionsbereich?
            if((m_KollPos.x + 0.25f >= yTerrain.x - 1.0f &&
               m_KollPos.x - 0.25f <= yTerrain.x + 1.0f &&
               m_KollPos.z + 0.25f >= yTerrain.z - 0.5f &&
               m_KollPos.z - 0.25f <= yTerrain.z + 0.5f))
            {
                //m_vPosition.x += 1.0f;
                m_vPosition.y = yTerrain.y + 0.25f;

            }
    }


    // Kollision mit den Blöcken berechnen
    for(DWORD dwBlock = 0; dwBlock < 64; dwBlock++)
    {
        if(m_pGame->m_aBlock[dwBlock].m_iEnergy > 0)
        {
            vBlock = m_pGame->m_aBlock[dwBlock].m_vPosition;
            
            // Befindet sich der Ball im Kollisionsbereich?
            if(m_vPosition.x + 0.25f >= vBlock.x - 1.0f &&
               m_vPosition.x - 0.25f <= vBlock.x + 1.0f &&
               m_vPosition.z + 0.25f >= vBlock.z - 0.5f &&
               m_vPosition.z - 0.25f <= vBlock.z + 0.5f)
            {

                // Entfernung des Balls von allen Blockseiten berechnen
                fDistLeft = fabsf(m_vPosition.x + 0.25f - (vBlock.x - 1.0f));
                fDistRight = fabsf(m_vPosition.x - 0.25f - (vBlock.x + 1.0f));
                fDistTop = fabsf(m_vPosition.z - 0.25f - (vBlock.z + 0.5f));
                fDistBottom = fabsf(m_vPosition.z + 0.25f - (vBlock.z - 0.5f));

                // Minimale Distanz berechnen
                fMinDist = TB_MIN(fDistLeft, TB_MIN(fDistRight, TB_MIN(fDistTop, fDistBottom)));

                // Wenn die Distanz zur linken oder rechten Seite am kleinsten ist...
                if(fMinDist == fDistLeft || fMinDist == fDistRight)
                {
                    // Ball an der z-Achse abprallen lassen
                    m_vVelocity.x *= -1.0f;
                }
                else
                {
                    // Ball an der x-Achse abprallen lassen
                    m_vVelocity.z *= -1.0f;
                }

                // Kollision ist immer nur mit einem einzigen Block möglich!
                break;
            }
        }
    }

    return TB_OK;
}

// __________________________________________________________________
// Rendert einen Ball
tbResult CBall::Render(float fTime)
{
    tbMatrix mWorld;

    // Ball rendern
    tbDirect3D& D3D = tbDirect3D::Instance();
    D3D.Instance().SetTransform(D3DTS_WORLD, tbMatrixTranslation(GetAbsPosition()));
    m_pGame->m_pBallModel->Render();

    // Motion-Blurring
    if(!m_bGrabbed &&
       D3D.GetCaps().SrcBlendCaps & D3DPBLENDCAPS_BLENDFACTOR)
    {
        // Alpha-Blending aktivieren und verhindern, dass in den Z-Buffer geschrieben wird
        D3D.SetRS(D3DRS_ZWRITEENABLE, FALSE);
        D3D.SetRS(D3DRS_ALPHABLENDENABLE, TRUE);
        D3D.SetRS(D3DRS_SRCBLEND, D3DBLEND_BLENDFACTOR);
        D3D.SetRS(D3DRS_DESTBLEND, D3DBLEND_INVBLENDFACTOR);

        // 9 Samples
        for(float f = 0.1f; f <= 1.0f; f += 0.1f)
        {
            // Blendfaktor (Opazität) dieses Samples bestimmen.
            // Wir lassen ihn von 0 bis 63 reichen.
            DWORD dwFactor = (DWORD)((1.0f - f) * 63.0f);

            // Blendfaktor setzen. Wir kopieren den Wert auf alle Farbkanäle.
            D3D.SetRS(D3DRS_BLENDFACTOR, 0xFF000000 | dwFactor | (dwFactor << 8) | (dwFactor << 16));

            // Position zurückrechnen und Ball rendern
            D3D.Instance().SetTransform(D3DTS_WORLD,
                                        tbMatrixTranslation(GetAbsPosition() - f * m_vVelocity * 0.1f));
            m_pGame->m_pBallModel->Render();
        }

        // Render-States zurücksetzen
        D3D.SetRS(D3DRS_ZWRITEENABLE, TRUE);
        D3D.SetRS(D3DRS_ALPHABLENDENABLE, FALSE);
    }
    return TB_OK;
}


Danke vorab!

Urmeli

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Urmeli« (29.04.2014, 22:54)


DeKugelschieber

Community-Fossil

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

2

29.04.2014, 21:30

Und du glaubst das liest so einer?

Erstmal nimm nicht den normalen Code Tag, sondern den mit Syntax highlighting (cpp).
Dann brich das noch bitte auf den relevanten Code runter. Wir müssen und wollen nich alles lesen. Man kann zwar viel posten, aber das hier ist doch etwas sehr viel ^^

3

29.04.2014, 22:52

Habs so gut es geht verkürzt und in cpp-Code umgewandelt

DeKugelschieber

Community-Fossil

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

4

29.04.2014, 23:10

Jetzt ist, zumindest mir noch etwas unklar wie du es gerne hättest?
Soll der Ball jetzt mitlaufen oder soll er quasi springen und dabei nur mit dem Terrain kollidieren können?

5

30.04.2014, 07:23

Er soll quasi über das Terrain laufen, bzw mit den Pfeiltasten darüber bewegbar sein und Unebenheiten mitfahren. Er springt nicht, sondern fährt eher und wenn er mit einem "Berg" kollidiert soll diese Berg-Form in der Bewegung des Balls sichtbar sein. Der Ball hebt sich dabei aber nicht vom Terrain ab.

6

30.04.2014, 13:53

Sorry ich muss nochmal fragen, kann mir noch nicht vorstellen was du genau willst.

Wird es 3D sein, mit freier Kamera oder 2D?
Falls 2D, guckt man von oben drauf oder von seitlich?

MFG
Bilder zu meinem Projekt: ParSim

DeKugelschieber

Community-Fossil

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

7

30.04.2014, 14:28

Das Terrain soll um den Ball herum sichtbar sein?

Ich meine das erste Problem (Ball bleibt stecken) lässt sich ja lösen indem man schlicht die Höhe auf die des Terrains setzt (+Radius des Balls natürlich).
Aber das zweite verstehe ich immer noch nicht.

8

30.04.2014, 14:47

Erst möchtest du den Ball "führen", jetzt "läuft" er?

Ich glaube dein Problem liegt im grundlegenden Ansatz.
Du setzt die Position bei einer Kollision, mit einer AABB um den Kollisionspunkt und einer AABB um jeweils jeden Terrainvertex, auf die Höhe an die des kollidierten Terrainvertex'.
Dabei treten zwei Probleme auf:
  1. Du setzt die y-Position des Balls immer auf den letzten kollidierten Vertex, der im Vertexbuffer gefunden wird. Dass dies nicht immer korrekt ist, kannst du dir ja selbst vorstellen ;)
  2. Wenn ein Ball mit einem Terrain kollidiert gibt es verschiedene Kräfte, die wirken: Gravitation, Kollisionskraft (vom Kollisionspunkt in Richtung der aktuellen Bewegung des Balls) und die Gegenkraft (die Kraft, die auf den Körper exakt in entgegengesetzter Richtung zu seiner Bewegung wirkt). Du setzt jedoch einfach die Höhe des Balls auf die des Terrains (und ein bisschen höher)

Um einen exakten Ansatz zu nutzen, musst du zunächst etwas über Impulse (Momentum) lernen:
http://en.wikipedia.org/wiki/Momentum

Die animierten Grafiken dort und die entsprechenden Formeln für elastische und inelastische Kollisionen sollten dir ein allgemeines und ausreichendes Verständnis für solche Kollisionen geben. Wenn du diese Gesetze anwendest, sollte sich dein Ball auf dem Terrain, bzw. auch in Interaktion mit den "Blocks" realistisch verhalten:
  • über Unebenheiten springt er, da die Gravitation ihn nicht sofort runter zieht (sondern exponential)
  • kollidiert er mit dem Terrain wird er nicht einfach "drüber gefahren", sondern fängt an zu springen und nonlineare Geschwindigkeit zu zeigen
  • wenn du entsprechend noch Reibung implementierst und den Ball rollen lässt, wird auch das (besonders, wenn du ihn texturierst) deutlich realistischer sein
EnvisionGame(); EnableGame(); AchieveGame(); - Visionen kann man viele haben. Sie umzusetzen und auf das Ergebnis stolz zu sein ist die eigentliche Kunst.

9

01.05.2014, 09:14

Ich hoffe Urmeli wurde jetzt nicht von den ganzen Infos erschlagen. :wacko:

Zitat

Er soll quasi über das Terrain laufen, bzw mit den Pfeiltasten darüber bewegbar sein und Unebenheiten mitfahren. Er springt nicht, sondern fährt eher...


Ich glaub sowas ausgefeiltes ist nicht beabsichtigt gewesen und auch eher was für Fortgeschrittene. :D

MFG
Bilder zu meinem Projekt: ParSim

Werbeanzeige