Verschiedene Tiletypen - 2D

Lukas1995

Mitglied
Guckuck :)

Ich habe leider überhaupt nichts richtiges gefunden zu dem Thema.

In meinem 2d Jump'n'Run Spiel funktionieren die Grundfunktionen wunderbar, Kartenanzeige, einfache Physik, Kollisionen mit den Tiles, läuft wunderbar.
Nun wollte ich das alles etwas erweitern, und zwar wollte ich mehr Tiletypen haben. Also nicht nur Würfel, mit denen man kollidiert und nicht durch gehen kann. Sowas wie Stacheln, sodass der Spieler sterben soll, wenn man draufhüpft, oder auch Plattformen, durch die man zwar durchspringen kann, aber sobald man drauffällt von oben nicht durch kann. Der Problem liegt sicher an dem Aufteilung der Klassen.

Ich habe eine Klasse Tile, in der ich die BildID speichere und die eine abstrakte Funktion "collidesWith" hat. Da wird angegeben, in welche Richtung sich der Spieler gerade bewegt (dadurch wird der Spieler bei einem Block auch an die richtige Position gestellt), dann wird das der Spieler / das Projektil / was auch immer angegeben, und dann die Position des Tiles.

Java:
public abstract class Tile {
	
	protected int tileID;

	public Tile(int tileID) {
		this.tileID = tileID;
	}

	public int getTileID() {
		return this.tileID;
	}

	public abstract boolean collidesWith(Direction direction, Sprite sprite, int x, int y);
}

Davon werden alle anderen Tyletypen abgeleitet, wie zum Beispiel BlockTile, wo auch die Kollision stattfinden und der Spieler zurückgesetzt wird.

Java:
public class Block extends Tile {

	public Block(int tileID) {
		super(tileID);
	}

	public boolean collidesWith(Direction direction, Sprite sprite,
			int x, int y) {
		if (direction == Direction.LEFT) {
			Vector2f pos = sprite.getPosition();
			sprite.setPosition(new Vector2f((x + 1) * 32, pos.y));
			
			return true;
		}

		if (direction == Direction.RIGHT) {
			float width = sprite.getShape().getWidth();
			Vector2f pos = sprite.getPosition();
			sprite.setPosition(new Vector2f(x * 32 - width, pos.y));
			
			return true;
		}

		if (direction == Direction.BOTTOM) {
			float height = sprite.getShape().getHeight();
			Vector2f pos = sprite.getPosition();
			sprite.setPosition(new Vector2f(pos.x, y * 32 - height + 1));
			
			return true;
		}

		if (direction == Direction.TOP) {
			Vector2f pos = sprite.getPosition();
			sprite.setPosition(new Vector2f(pos.x, (y + 1) * 32));
			
			return true;
		}

		return false;
	}
}

Durch die Funktion kann ich leider nur angeben, ob eine Kollision stattfand oder nicht. Wenn ich dann aber zum Beispiel einen Stachel-Block haben möchte, dann funktioniert das ja nicht mehr so gut, da meine Sprite-Klasse keine Variable für Leben hat und somit auch nciht sterben kann. Ich hab schon daran gedacht, dass man noch sowas wie eine Funktion "getTileType" einbaut, die die Art des Tiles zurückgibt und dann in entsprechenden Klassen (Player/Enemy...) darauf reagiert wird. Zusätzlich sollte der Spieler noch einen Schub anch oben bekommen, wenn er einen Stachel berührt, damit er die Chance hat, da weg zu kommen. Ich auch schon daran gedacht, in der Klasse "Collision", die dazu da ist, alle relevanten Tiles auf Kollisionen zu überprüfen, eine ArrayList <Tile> zurückzugeben, damit bekäme man alle Tiles, mit denen man kollidiert und kann so einmal durchlaufen und für jedes Tile entsprechend reagiere, wenn er nötig ist. Problem wäre dann, das ich, wenn ich zum Beispiel zwischen 2 Stacheln stehe, 2 mal Leben abgezogen bekomme, was ich ja nicht will.

Ich habe noch ein Bild angehängt, wie ich das mit den Kollisionen mache. Die grünen Kreuze beim roten Rechteck (Spieler) stellen Kollisionspunkte da, die in Tiles umgerechnet werden und so das Tile ermittelt wird, wo der Punkt sich befindet. Deswegen ist der Spieler auch 1 Pixel in den Boden "eingelassen". Da sieht man, dass er mit 2 stacheln kollidiert, aber er soll die Reaktion nur einmal machen, und nciht zweimal für beide Stacheln.

grafik.png

Ich hoffe das Problem ist einigermaßen verständlich... wäre sehr dankbar für einen Ansatz zur Lösung, ich stehe momentan sehr auf dem Schlauch :)
 

s4ke

Bekanntes Mitglied
Dein Problem kommt daher, dass du da etwas Design-technisch falsch machst. eine coolidesWith Methode sollte imho wie der Name schon sagt, nur prüfen ob eine Kollision vorhanden ist und sonst keinen Nebeneffekt haben. Wenn du in deinem Gameloop einfach immer einen check machst, ob der Spieler mit etwas kollidiert (ganz einfacher Fall: einfach mit allen kollidirbaren Objekten bruteforce testen, das kann man später optimieren) und abhängig davon etwas auslösen. Auf GAR KEINEN Fall sollte so etwas in der collidesWith Methode passieren, sonst passieren Fehler wie du sie schon bemerkt hast.
 

Lukas1995

Mitglied
Das heißt, dass ich so eine Kollisionsmethode eher in die spezifischen Klassen auslagern soll, die diese brauchen, wie den Spieler oder andere Objekte, und ihn dort so anpasse, wie er benötigt wird?
 
T

TryToHelp

Gast
Ich würde es eventuell so machen, das du zum einen die Kollisionsdetection hast und eine weitere Methode, die du aufrufst, wenn es eine kollision gab, die dann was macht, und diese wird dann in jeder Klasse neu bzw anders implementiert, aber die Kollisionsdedektion von der Action getrennt ;-)
 

Ähnliche Java Themen


Oben