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

12.08.2012, 21:50

SFML2 | Jump & Run - Wie Klassen verwalten?

Hallo,
ich habe zum Test ein kleines 2D-Jump&Run geschrieben.
Man kann noch nicht viel machen, außer herumlaufen, herumspringen und dabei kollidieren.
Ich habe folgende Klassen:

CGame: Rendert das gesamte Bild

CLevel: Rendert ein Array von Blöcken (CBlock-Instanzen(sf::Sprite)), überprüft Tastendrücke und Kollisionen, und steuert den View des Levels

CPlayer: Enthält Informationen über den Spieler

Der Code ist zwar vom Speicherverbrauch, etc. sauber geschrieben, allerdings gefällt mir die gesamte Umsetzung der Klassenverwaltung nicht.
Ich würde gerne den Spieler über seine eigene Klasse bewegen und auf Kollision überprüfen. Allerdings geht das nicht, da ich ja kein Zugriff auf CGame hab und somit nicht das gesamte Bild rendern kann, sondern nur den Spieler.
Außerdem hab ich keinen Zugriff auf das Array der CBlock-Instanzen und kann somit nicht auf Kollision prüfen.
Ich habe schon versucht, eine CLevel Instanz per Pointer zu übergeben, aber aufgrund einer Kreisdeklaration oder wie das heißt, war auch das nicht möglich.
Was ich auf jeden Fall vermeiden wollte, ist Singletons als globale Variablen zu "missbrauchen".

Kurz und knapp:
Was sollten die Klassen neues können:

CGame: Spieler.CheckMovement (Tastenabfrage), Level.CheckScrolling (Horiz. Scrollen der Welt)

CLevel: Eig. nichts mehr

CPlayer: CheckMovement, dazu CheckCollision und Move

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Nathax« (13.08.2012, 10:06)


2

13.08.2012, 19:50

Du kannst deinen gesamten Bewegungs-Code in die CPlayer Klasse auslagern.

Dannach lässt du CPlayer einmal einen Zeiger auf seine sf::Rect klasse zurückgeben und dann prüfst du in der CGame Klasse ob das Rect Kollidiert oder nicht.
und wenn es Kollidiert könntest du es in der CGame Klasse auch gleich verschieben.

3

13.08.2012, 20:13

Das Problem ist dann ja aber, dass im Bewegungs-Code der CPlayer-Klasse vor dem Bewegen eine Kollisionsabfrage stattfinden muss.
Allerdings hat CPLayer weder Zugriff auf m_Block von CLevel (,um selbst die Kollisionsabfrage zu machen) noch auf die Kollisionabfrage von CGame.

4

13.08.2012, 20:16

vor dem Bewegen muss keine Kollisionsabfrage stattfinden.
du bewegst erst den spieler, prüfst dann in der CGame Klasse ob das so geht.
Und dann zeichnest du es auf den Bildschirm

5

13.08.2012, 20:17

Dann überreich ihr doch Pointer auf die Instanzen!

Edit: Oops LuggLugg schneller 8)

6

14.08.2012, 18:08

Ich werd mal noch ein bisschen herumexperimentieren.
Bis jetzt war bei der Pointerübergabe halt immer das Problem, dass wie ich schon im Startpost geschrieben habe, eine Kreisdeklaration stattfindet,
d.h. sich die Klassen gegenseitig deklarieren müssten.
Wenn ich etwas neues herausbekomme melde ich micht natürlich.
Über andere Lösungsmöglichkeiten würde ich natürlich gerne trotzdem informiert werden.

eXpl0it3r

Treue Seele

Beiträge: 386

Wohnort: Schweiz

Beruf: Professional Software Engineer

  • Private Nachricht senden

7

14.08.2012, 20:03

Bis jetzt war bei der Pointerübergabe halt immer das Problem, dass wie ich schon im Startpost geschrieben habe, eine Kreisdeklaration stattfindet,
d.h. sich die Klassen gegenseitig deklarieren müssten.
Dann machst du wahrscheinlich etwas falsch bei deinen Hederfiles. Nutzt du Include-Guards?

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
#ifndef CGAME_HPP
#define CGAME_HPP

class CGame
{

};

#endif // CGAME_HPP
Wenn du diese Präprozessor Statements einfügst, sollte es kein Problem sein, wenn header A, B inkludiert und B, A. ;)
Oder aber ich habe dich falsch verstanden. :)
Blog: https://dev.my-gate.net/
—————————————————————————
SFML: https://www.sfml-dev.org/
Thor: http://www.bromeon.ch/libraries/thor/
SFGUI: https://github.com/TankOs/SFGUI/

Powerpaule

Treue Seele

Beiträge: 162

Wohnort: Berlin

Beruf: Softwareentwickler

  • Private Nachricht senden

8

14.08.2012, 20:15

Wenn du diese Präprozessor Statements einfügst, sollte es kein Problem sein, wenn header A, B inkludiert und B, A. ;)
Oder aber ich habe dich falsch verstanden.
Na ja das ist dann aber trotzdem ein Problem, weil durch die Kreisdeklaration jede Klasse die andere kennen muss, und es daher immer dazu kommt, dass eine der beiden Klassen der anderen noch nicht bekannt ist.
Bis jetzt war bei der Pointerübergabe halt immer das Problem, dass wie ich schon im Startpost geschrieben habe, eine Kreisdeklaration stattfindet,
d.h. sich die Klassen gegenseitig deklarieren müssten.
Das kannst du durch Vorwärtsdeklaration und das Includen erst in den cpp-Files lösen:

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
// game.h
class CPlayer;

class CGame {
   CPlayer* player;
};

// game.cpp

#include "game.h"
#include "player.h"

// player.h

class Player {
   CGame* game;
};

// player.cpp

#include "game.h"

#include "player.h"


Dann klappt es. Das funktioniert solange du Player nur als Pointer benutzt, denn der Compiler muss dann nur wissen, dass es diesen Typ gibt, nicht aber wie groß er ist (da ein Pointer immer gleich groß ist)

ABER im Grunde solltest du sowas nicht verwenden, da es eher schlechtes Design ist, wenn 2 Klassen sich komplett gegenseitig kennen. Da wäre es besser, ein Interface zu schreiben, was die Methoden definiert, die Player benutzen darf, Game implementiert dann dieses Interface und Player bekommt nur einen Pointer vom Typ des Interfaces.
Für so ein kleines Spiel ist das jetzt aber vielleicht erstmal egal.

9

14.08.2012, 21:45

Vielen Dank euch allen!
Ja, ich benutze Include-Guards, aber die bringen in dem Fall nichts gg. die Kreisdeklaration.
Bezüglich des Interfaces, dafür wollte ich ja CGame nehmen.
Ich werd mal gucken wie ichs mache und berichten.

10

14.08.2012, 21:53

Du verstehst vlt noch nicht wie einfach sich dein Problem lösen lässt.
Die Player Klasse muss deine Spielwelt nicht kennen.
Sie muss sich auch nicht um die Kollisionsabfrage kümmern.

Die Player Klasse gibt nur einmal einen Pointer auf ihren Rect zurück und die Game Klasse schaut dann nach ob etwas passiert ist.
Das musst du so machen denn stell dir mal vor du hast nicht nur Blöcke in deinem Spiel sondern auch gegner.
Das lässt du dann alles zentral in der Game Klasse auf Kollisionen überprüfen.

und die Game Klasse hat als include nur "Player.hpp" und der Player hat als include eben NICHT "Game.hpp". :!:

Bei C++ ist man auf eine starke "Baumstruktur" angewiesen. Kollisionsabfragen müssen dann schonmal ausgelagert werden.

Problem solved.

edit: Die Player Klasse kümmert sich natürlich weiterhin um die Tastatureingaben und das Rendern.

Werbeanzeige