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.07.2003, 18:00

Pogramm stürzt ab

Hallo,

ich wollte für einen Gast (http://www.scherfgen-software.net/index.…e13acb928040e0f) ein Pogramm schreiben. ( ein Intro, was ein Video abspielt). Nur, wenn ich das Pogramm ausführe, hängt
es, oder der Bildschirm flimmert, wird grün oder schwarz, und dann häüngt sich der PC ganz auf. Wenn man aber ganz genau hinguckt, sieht man im Hintergrund teile des Videos.

Hier das Pogramm: (Ausschnitt: Die CIntro-Klasse)


*.cpp:

Quellcode

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
#include "Missile.h"

        
tbVideo* g_pVideo = NULL;   // Das Video
char acVideoFilename[10] = "intro.avi"; // Der Dateiname

// Initialisiert den Spielzustand
tbResult CIntro::Init()
{
    // Laden...
    if(Load()) TB_ERROR("Fehler beim Laden des Spielzustands!", TB_ERROR);

    g_pVideo = new tbVideo;
    if(g_pVideo->Init(acVideoFilename))
    {
        // Fehler!
        Exit();
        TB_ERROR("Fehler beim Laden des Videos", TB_ERROR);
    }

    // Video mit Looping abspielen
    g_pVideo->Play(TRUE);

    return TB_OK;
}

// Fährt den Spielzustand herunter
tbResult CIntro::Exit()
{
    //  Video löschen und Entladen...
    TB_SAFE_DELETE(g_pVideo);
    Unload();

    return TB_OK;
}

// Lädt den Spielzustand
tbResult CIntro::Load()
{
    return TB_OK;
}

// Entlädt den Spielzustand
tbResult CIntro::Unload()
{
    return TB_OK;
}

// Bewegt den Spielzustand
tbResult CIntro::Move(float fTime) {
    // Wenn eine der typischen Tasten gedrückt wurde: zum Hauptmenü
    /* if(g_pbButtons[TB_KEY_NUMPADENTER] ||
       g_pbButtons[TB_KEY_RETURN] ||
       g_pbButtons[TB_KEY_SPACE] ||
       g_pbButtons[TB_MOUSE_BUTTON(0)] ||
       g_pbButtons[TB_MOUSE_BUTTON(1)])
    {
        // Beenden
        tbDelay(100);
        PostQuitMessage(0);
        return TB_OK;
        // g_pMissile->SetGameState(GS_MAIN_MENU);
    }
    else { */
    // Das Video verarbeiten
    g_pVideo->Process();
    // }

    return TB_OK;
}

// Rendert den Spielzustand
tbResult CIntro::Render(float fTime)
{
    SIntroVertex aVertex[4];

    // Wenn die Videotextur gerade gesperrt ist, warten wir so lange,
    // bis sie es nicht mehr ist.
    while(g_pVideo->GetRenderer()->IsTextureLocked()) {}

    // Die Szene beginnen
    tbDirect3D::GetDevice()->BeginScene();

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

    // Vertexformat und Videotextur setzen, Z-Buffer aus
    tbDirect3D::SetFVF(VERTEX_INTRO_FVF);
    tbDirect3D::SetTexture(0, g_pVideo->GetRenderer()->GetTexture());
    tbDirect3D::SetRS(D3DRS_ZENABLE, D3DZB_FALSE);

    // Die vier Vertizes erstellen (Rechteck)
    // Links unten
    aVertex[0].vPosition = tbVector3(0.0f, tbDirect3D::GetScreenSize().y, 0.5f);
    aVertex[0].fRHW = 1.0f;
    aVertex[0].Color = tbColor(0.0f, 0.0f, 0.0f);
    aVertex[0].vTex0 = tbVector2(0.0f, g_pVideo->GetRenderer()->GetBottomRightTex().y);

    // Links oben
    aVertex[1].vPosition = tbVector3(0.0f, 0.0f, 0.0f);
    aVertex[1].fRHW = 1.0f;
    aVertex[1].Color = tbColor(0.0f, 0.0f, 0.0f);
    aVertex[1].vTex0 = tbVector2(0.0f, 0.0f);

    // Rechts unten
    aVertex[2].vPosition = tbVector3(tbDirect3D::GetScreenSize().x, tbDirect3D::GetScreenSize().y, 0.5f);
    aVertex[2].fRHW = 1.0f;
    aVertex[2].Color = tbColor(0.0f, 0.0f, 0.0f);
    aVertex[2].vTex0 = g_pVideo->GetRenderer()->GetBottomRightTex();

    // Rechts oben
    aVertex[3].vPosition = tbVector3(tbDirect3D::GetScreenSize().x, 0.0f, 0.5f);
    aVertex[3].fRHW = 1.0f;
    aVertex[3].Color = tbColor(0.0f, 0.0f, 0.0f);
    aVertex[3].vTex0 = tbVector2(g_pVideo->GetRenderer()->GetBottomRightTex().x, 0.0f);

    // Als Dreiecksfolge zeichnen
    tbDirect3D::GetDevice()->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, aVertex, sizeof(SIntroVertex));

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

    // Szene beenden und darstellen
    tbDirect3D::GetDevice()->EndScene();
    tbDirect3D::GetDevice()->Present(NULL, NULL, NULL, NULL);

    return TB_OK;
}

__________________________________


*.h

Quellcode

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
// Klasse für das Intro
class CIntro
{
public:
    // Struktur für einen Vertex
    #define VERTEX_INTRO_FVF (D3DFVF_XYZRHW | D3DFVF_TEX1)
    struct SIntroVertex
    {
    tbVector3   vPosition;
    float       fRHW;
    D3DCOLOR    Color;
    tbVector2   vTex0;
    };

    // Konstruktor
    inline CIntro() {ZeroMemory(this, sizeof(CIntro));}
    
    // Methoden
    tbResult Init();                // Initialisierung
    tbResult Exit();                // Herunterfahren
    tbResult Load();                // Laden
    tbResult Unload();              // Entladen
    tbResult Move(float fTime);     // Bewegen
    tbResult Render(float fTime);   // Rendern
};

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

29.07.2003, 18:22

Poste mal die Hauptfunktion.

3

29.07.2003, 18:43

Wie, die Hauptfunktion?

Das ist alles, was ich für das Intro geschrieben habe. Das eigentliche Pogramm:

*.h

Quellcode

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
#include <TriBase.h>
#include "intro.h"
#include "resource.h"

// Spielzustände
enum EGameState {
    GS_NONE,        // Kein Spielzustand
    GS_INTRO,       // Intro
    GS_MAIN_MENU    // Hauptmenü
};

// Die Spiel-Klasse
class CMissile
{
public:
    // Variablen
    // DirectX
    tbConfig                m_Config;       // Konfiguration
    PDIRECT3DSTATEBLOCK9    m_pStateBlock;  // Statusblock für Direct3D
    tbTextureManager*       m_pTexManager;  // Texturmanager

    // Die Spielzustände
    CIntro*                 m_pIntro;       // Intro
//  CMainMenu*              m_pMainMenu;    // Hauptmenü
    EGameState              m_GameState;    // Aktueller Spielzustand
    float                   m_fTime;        // Stoppuhr

    // Schriftarten
    tbFont*                 m_pFont1;
    tbFont*                 m_pFont2;
    tbFont*                 m_pFont3;
    tbFont*                 m_pFont4;
    tbFont*                 m_pFont5;
    tbFont*                 m_pFont6;
    tbFont*                 m_pFont7;

    // Methoden
    tbResult Init();                                // Initialisiert das Spiel komplett
    tbResult Exit();                                // Fährt das Spiel herunter
    tbResult Load();                                // Lädt die Spieldaten
    tbResult Unload();                              // Entlädt die Spieldaten
    tbResult Run();                                 // Lässt das Spiel laufen
    tbResult SetGameState(EGameState NewGameState); // Setzt einen neuen Spielzustand
    tbResult Move(float fTime);                     // Bewegt das Spiel
    tbResult Render(float fTime);                   // Rendert das Spiel
};

// Globale Variablen
extern CMissile*    g_pMissile;
extern float*       g_pfButtons;
extern BOOL*        g_pbButtons;
extern BOOL*        g_pbButtons;


*.cpp

Quellcode

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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
// Include-Dateien

#include "missile.h"

// Globale Variablen
CMissile* g_pMissile = NULL;
float* g_pfButtons = NULL;
BOOL* g_pbButtons = NULL;

// Windows-Hauptfunktion
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   char* pcCommandLine,
                   int iShowCommand)
{
    tbResult r;

    // Spiel initialisieren
    g_pMissile = new CMissile;
    r = g_pMissile->Init();
    if(r == TB_CANCELED)
    {
        // Der Konfigurationsdialog wurde abgebrochen!
        // Das Programm "leise" verlassen.
        TB_SAFE_DELETE(g_pMissile);
        return 0;
    }
    else if(r)
    {
        g_pMissile->Exit();
        TB_SAFE_DELETE(g_pMissile);
        MessageBox(NULL, "Fehler beim Initialisieren des Spiels!",
                   "Fehler", MB_OK | MB_ICONEXCLAMATION);
        return 1;
    }

    // Spiel laufen lassen
    if(g_pMissile->Run())
    {
        g_pMissile->Exit();
        TB_SAFE_DELETE(g_pMissile);
        MessageBox(NULL, "Fehler im Spiel!",
                   "Fehler", MB_OK | MB_ICONEXCLAMATION);
        return 1;
    }

    // Spiel verlassen
    g_pMissile->Exit();
    TB_SAFE_DELETE(g_pMissile);

    return 0;
}


// Lädt das Spiel
tbResult CMissile::Load()
{

    // Direct3D initialisieren
    if(tbDirect3D::Init(&m_Config, "Missile",
                        NULL, LoadIcon(GetModuleHandle(NULL),
                        MAKEINTRESOURCE(IDI_ICON1))))
    {
        // Fehler!
        TB_ERROR("Fehler beim Initialisieren von Direct3D!", TB_ERROR);
    }

    // Statusblock für Direct3D erstellen
    tbDirect3D::GetDevice()->CreateStateBlock(D3DSBT_ALL, &m_pStateBlock);

    // Texturmanager erstellen
    if(tbTextureManager::Init())
    {
        // Fehler!
        TB_ERROR("Texturmanager konnte nicht initialisiert werden!", TB_ERROR);
    }

    // DirectInput initialisieren
    if(tbDirectInput::Init())
    {
        // Fehler!
        TB_ERROR("DirectInput konnte nicht initialisiert werden!", TB_ERROR);
    }

    // Speicher für die analogen Knöpfe reservieren
    g_pfButtons = new float[tbDirectInput::GetNumButtons()];
    g_pbButtons = new BOOL[tbDirectInput::GetNumButtons()];

    // Schriftarten laden
    m_pFont1 = new tbFont;
    if(m_pFont1->Init("Data\\fonts\\font1.tga", "Data\\fonts\\font1.tbf"))
    {
        // Fehler!
        TB_ERROR("Fehler beim Laden der Schriftart Data\\fonts\\font1!", TB_ERROR);
    }

    m_pFont2 = new tbFont;
    if(m_pFont2->Init("Data\\fonts\\font2.tga", "Data\\fonts\\font2.tbf"))
    {
        // Fehler!
        TB_ERROR("Fehler beim Laden der Schriftart Data\\fonts\\font2!", TB_ERROR);
    }

    m_pFont3 = new tbFont;
    if(m_pFont3->Init("Data\\fonts\\font3.tga", "Data\\fonts\\font3.tbf"))
    {
        // Fehler!
        TB_ERROR("Fehler beim Laden der Schriftart Data\\fonts\\font3!", TB_ERROR);
    }

    m_pFont4 = new tbFont;
    if(m_pFont4->Init("Data\\fonts\\font4.tga", "Data\\fonts\\font4.tbf"))
    {
        // Fehler!
        TB_ERROR("Fehler beim Laden der Schriftart Data\\fonts\\font4!", TB_ERROR);
    }
    m_pFont5 = new tbFont;
    if(m_pFont5->Init("data\\fonts\\font5.tga", "Data\\fonts\\font5.tbf"))
    {
        // Fehler!
        TB_ERROR("Fehler beim Laden der Schriftart Data\\fonts\\font5!", TB_ERROR);
    }

    m_pFont6 = new tbFont;
    if(m_pFont6->Init("data\\fonts\\font6.tga", "Data\\fonts\\font6.tbf"))
    {
        // Fehler!
        TB_ERROR("Fehler beim Laden der Schriftart Data\\fonts\\font6!", TB_ERROR);
    }
    m_pFont7 = new tbFont;
    if(m_pFont7->Init("data\\fonts\\font7.tga", "Data\\fonts\\font7.tbf"))
    {
        // Fehler!
        TB_ERROR("Fehler beim Laden der Schriftart Data\\fonts\\font7!", TB_ERROR);
    }

    return TB_OK;
}

// Setzt einen neuen Spielzustand
tbResult CMissile::SetGameState(EGameState NewGameState)
{
    tbResult r = TB_OK;

    // Alten Spielzustand entladen
    switch(m_GameState)
    {
    case GS_INTRO:      m_pIntro->Exit();           break;
    // case GS_MAIN_MENU:   m_pMainMenu->Exit();        break;
    }

    // Zeit zurücksetzen
    m_fTime = 0.0f;

    // Neuen Spielzustand laden
    m_GameState = NewGameState;
    switch(m_GameState)
    {
    case GS_INTRO:      r = m_pIntro->Init();       break;
    // case GS_MAIN_MENU:   r = m_pMainMenu->Init();    break;
    }

    // Eventuelle Fehler abfangen
    if(r) TB_ERROR("Fehler beim Laden des Spielzustands!", TB_ERROR);

    return TB_OK;
}

// Initialisiert das Spiel komplett
tbResult CMissile::Init()
{
    tbResult r;

    // Alles zurücksetzen
    ZeroMemory(this, sizeof(CMissile));

    // Die TriBase-Engine initialisieren und den Konfigurationsdialog aufrufen
    if(tbInit()) return TB_ERROR;
    r = tbDoConfigDialog(&m_Config);
    if(r == TB_CANCELED) return TB_CANCELED;
    else if(r) TB_ERROR("Engine konnte nicht initialisiert werden!", r);

    // Laden...
    if(Load()) TB_ERROR("Fehler beim Laden des Spiels!", TB_ERROR);

    // Klassen für alle Spielzustände erstellen
    m_pIntro = new CIntro;
    // m_pMainMenu = new CMainMenu;

    // Wir beginnen beim Intro!
    SetGameState(GS_INTRO);

    return TB_OK;
}

// Bewegt das Spiel
tbResult CMissile::Move(float fTime)
{
    tbResult r = TB_OK;

    // Eingabegeräte abfragen
    tbDirectInput::GetState(g_pfButtons, g_pbButtons);

    // Aktuellen Spielzustand bewegen
    switch(m_GameState)
    {
    case GS_INTRO:      r = m_pIntro->Move(fTime);      break;
    // case GS_MAIN_MENU:   r = m_pMainMenu->Move(fTime);   break;
    }

    // Eventuelle Fehler abfangen
    if(r) TB_ERROR("Fehler beim Bewegen des Spielzustands!", TB_ERROR);

    // Zeit addieren
    m_fTime += fTime;

    return TB_OK;
}

// Rendert das Spiel
tbResult CMissile::Render(float fTime)
{
    tbResult r = TB_OK;

    // Aktuellen Spielzustand rendern
    switch(m_GameState)
    {
    case GS_INTRO:      r = m_pIntro->Render(fTime);    break;
    // case GS_MAIN_MENU:   r = m_pMainMenu->Render(fTime); break;
    }

    // Eventuelle Fehler abfangen
    if(r) TB_ERROR("Fehler beim Rendern des Spielzustands!", TB_ERROR);

    // Bildpuffer anzeigen
    if(tbDirect3D::Present())
    {
        // Anzeigen ist fehlgeschlagen!
        // Wahrscheinlich läuft das Programm im Vollbildmodus und es
        // wurde zwischenzeitlich minimiert.
        // Wir initialisieren das Spiel komplett neu.

        // Aktuellen Spielzustand entladen
        switch(m_GameState)
        {
        case GS_INTRO:      m_pIntro->Unload();     break;
        // case GS_MAIN_MENU:   m_pMainMenu->Unload();  break;
        }

        // Das ganze Spiel entladen und dann wieder neu laden
        Unload();
        Load();

        // Aktuellen Spielstatus neu laden
        switch(m_GameState)
        {
        case GS_INTRO:      m_pIntro->Load();       break;
        // case GS_MAIN_MENU:   m_pMainMenu->Load();    break;
        }
    }

    return TB_OK;
}

// Move- und Render-Funktion (Kapselung)
tbResult Move(float fTime) {return g_pMissile->Move(fTime);}
tbResult Render(float fTime) {return g_pMissile->Render(fTime);}

// Lässt das Spiel laufen
tbResult CMissile::Run()
{
    // Nachrichtenschleife betreten
    if(tbDoMessageLoop(::Move, ::Render))
    {
        // Fehler!
        TB_ERROR("Fehler in der Nachrichtenschleife!", TB_ERROR);
    }

    return TB_OK;
}

tbResult CMissile::Exit()
{
    // Kein Spielstatus (aktuellen Spielstatus entladen)
    SetGameState(GS_NONE);

    // Entladen...
    Unload();

    // Die Klassen für die Spielzustände löschen
    TB_SAFE_DELETE(m_pIntro);
//  TB_SAFE_DELETE(m_pMainMenu);

    // Die Engine herunterfahren
    tbExit();

    return TB_OK;
}

// Entlädt das Spiel
tbResult CMissile::Unload()
{
    // Schriftarten löschen
    TB_SAFE_DELETE(m_pFont1);
    TB_SAFE_DELETE(m_pFont2);
    TB_SAFE_DELETE(m_pFont3);
    TB_SAFE_DELETE(m_pFont4);
    TB_SAFE_DELETE(m_pFont5);
    TB_SAFE_DELETE(m_pFont6);
    TB_SAFE_DELETE(m_pFont7);

    // DirectX-Klassen löschen
    TB_SAFE_RELEASE(m_pStateBlock);
    TB_SAFE_DELETE_ARRAY(g_pfButtons);
    TB_SAFE_DELETE_ARRAY(g_pbButtons);
    tbDirect3D::Exit();
    tbDirectInput::Exit();
    tbTextureManager::Exit();

    return TB_OK;
}


Das ist das einzige, was ich seit 3 Tagen zustande gebracht habe. Dafür habe ich 100 Ideen und ein paar fertige Codeschnippsel.

Bei dieser Gelegenheit kann ich doch mal Fragen: Bei meinem Spiel steuert man eine 3D-Rakete. Also fast so ähnlich wie bei Galactica. Düfte ich von diesem Spiel teile (Hauptmenü) übernehmen.

Aber, schüssi,

Chrissi

4

29.07.2003, 19:47

Mir ist etwas aufgefallen. Wenn ich das Color-Tag deaktiviere:

struct SIntroVertex
{
tbVector3 vPosition;
float fRHW;
// D3DCOLOR Color;
tbVector2 vTex0;
};

Dann flimmert das Bild, es wird immer zwischen dem Videobild und einem Grün "durchgeschaltet". (Video-Grüner Bildschirm,Video-Grüner Bildschirm,Video-Grüner Bildschirm,Video-Grüner Bildschirm...)

Vielleicht hilft das weiter...

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

5

29.07.2003, 19:59

Tipp: Du rufst in Deinem Programm zweimal pro Frame die Present-Methode auf. Das darfst Du nicht tun.

6

29.07.2003, 20:47

Hey,

das funktioniert auch bei mir.

Nur weiß ich nicht, wie ich das Viedo in Orginalgröße(!) in die Mitte tun kann... Ich habe verschidene Sachen schon probiert, aber ist ja egal...

7

30.07.2003, 10:57

Ich hatte da an soetwas gedacht: Screenheight/Videoheight/2 oder so.

Anonymous

unregistriert

8

30.07.2003, 12:59

Endlich Zeugnisse.
Nun ja,

das Pogramm funktioniert. Nun habe ich genau das Gleiche Problem. Das Video soll in die Mitte.

9

31.07.2003, 09:41

David hat gerade eben gesagt, dass er die Frage nicht so richtig verstanden hat.

Also, das Video (z.B. 300x400px) soll GANZ genau in die Mitte, ohne gestreckt zu werden. (auf 1024x768px).

Ausserdem habe ich noch eine Frage: (die letzte!) Ich möchte, das das Video NUR einmal angezeigt werden soll: Dannach soll ein Text angezeigt werden (À la "drücken sie enter")

Aber im Moment ist es noch nicht so wichtig. Ich arbeite gerade am Hauptmenü....

Schüssi,

Chrissi

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

10

31.07.2003, 10:03

Ändere doch einfach die Position und die Größe des Rechtecks. Rechne den Mittelpunkt des Bildschirms aus und ziehe davon die Hälfte der Videogröße ab, um den Startpunkt zu erhalten. Die Videogröße kennst Du ja. Zum Beispiel:

Video: 320x240
Bildschirm: 800x600

Linke obere Ecke für Video:
x = 800/2 - 320/2 = 400 - 160 = 240
y = 600/2 - 240/2 = 300 - 120 = 180

Werbeanzeige