Skip to content

05 Tile collisions

fritzvd edited this page Oct 25, 2019 · 5 revisions

In deze tutorial gaan we kort stil staan bij

  • wat een tile engine is
  • hoe je kan kijken of een GameObject een Tile heeft geraakt

Tile Engines en collisions

In games is het vaak belangrijk om te weten wanneer een specifiek object tegen een ander iets is aangekomen. Dit noem je over het algemeen een collision (Nederlands: botsing). Maar bij de meeste games is het ook zo dat er onderscheid gemaakt wordt tussen statische objecten die onderdeel zijn van het level design (zoals muntjes of blokjes) of dynamische objecten (zoals spelers en vijanden).

In platform games zoals Mario of Sonic beweegt het karakter in een level waarin er "voorgrond" en "achtergrond" dingen zijn. Stiekem zijn de doosjes en muntjes die het karakter kan pakken vaak deel van de achtergrond. Je moet je eigenlijk voorstellen dat het "voorgrond" ding, dus je Player in ons geval langzaam over een raster beweegt zoals een schaakbord. De engine houdt dan bij waar het poppetje is en of bij een zekere tile is aangekomen.

Om hier even mee te spelen kan je zelf wat ontwerpen, of de mooie assets van Kenney weer gebruiken. Klik hier voor een pakketje met tiles voor een platform game.

In de tutorial wordt dit plaatje gebruikt:

tile

De GameEngine weet nog helemaal niets van de tiles, dus we moeten duidelijk maken wat voor typen we willen gaan toevoegen. In de World klasse voegen we nog code toe aan de setupGame methode. Of nog beter aan een nieuwe methode die wordt aangeroepen in setupGame.

We moeten de volgende dingen doen om tiles toe te voegen:

  • de plaatjes die we gebruiken voor de tiles inladen als een Sprite
  • nieuwe TileType definiëren en initialiseren.
  • TileTypes toevoegen aan een lijstje
  • grootte van tile meegeven
  • tileMap maken (hoe de verschillende tiles getekend moeten worden)
  • en uiteindelijk alles in een TileMap instantie gooien met de naam tileMap

In een nieuwe package genaamd tiles is FloorTile als volgt toegevoegd.

package tiles;

import nl.han.ica.oopg.objects.Sprite;
import nl.han.ica.oopg.tile.Tile;

public class FloorTile extends Tile {
	/**
	 * 
	 * @param sprite image to be drawn as a floor Tile.
	 */
	public FloorTile(Sprite sprite) {
		super(sprite);
	}
}
    private void initializeTileMap() {
        // Load Sprites
        Sprite floorSprite = new Sprite(this.MEDIA_URL.concat("platformPack_tile001.png"));
        // Create tile types with the right Tile class and sprite
        TileType<FloorTile> floorTileType = new TileType<>(FloorTile.class, floorSprite);

        TileType[] tileTypes = {floorTileType};
        int tileSize = 64;
        int tilesMap[][] = {
                {-1, -1, -1, -1, -1, -1, -1, },
                {-1, -1, -1, -1, -1, -1, -1, },
                {-1, -1, -1, -1, -1, -1, -1, },
                {-1, -1, -1, -1, -1, -1, -1, },
                {0, 0, 0, 0, 0, 0, 0, },
                {-1, -1, -1, -1, -1, -1, -1, },
                {-1, -1, -1, -1, -1, -1, -1, },
        };
        tileMap = new TileMap(tileSize, tileTypes, tilesMap);
    }

Als het goed is krijg je nu iets wat er zo uit ziet (wellicht met de speler op de verkeerde plek.)

Achtergrond met tiles

Op het moment gebeurt er nog niets interessants. We willen eigenlijk dat de speler niet door het platform heen kan gaan. Dus daarvoor moeten we nog toevoegen dat de speler altijd naar beneden valt (net zoals met zwaartekracht). En dat de speler dus niet door de ondergond heen kan zweven.

Eerst maar zwaartekracht toevoegen. Door de volgende regels toe te voegen aan de constructor van Player krijgt de speler een snelheid die neerwaarts gaat net zoals zwaartekracht:

        gravity = 0.2f;
        setGravity(gravity);

Als je het spel nu weer draait, zie je redelijk snel de speler uit het beeld verdwijnen. We hebben namelijk nog niets gedaan met de collision. Daarvoor bestaat de volgende methode in de interface ICollidableWithTiles: tileCollisionOccurred.

We willen nu in de desbetreffende methode ervoor zorgen dat wanneer de speler tegen de "vloer" aankomt deze niet verder naar beneden zakt maar blijft staan. Daarvoor passen we de Y-waarde van de player direct aan.

    @Override
    public void tileCollisionOccurred(List<CollidedTile> collidedTiles) {
        PVector vector;
        for (CollidedTile ct : collidedTiles) {
            if (ct.getTile() instanceof FloorTile) {
                try {					
                    vector = world.getTileMap().getTilePixelLocation(ct.getTile());
                    setY(vector.y - getHeight());
                } catch (TileNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
      
    }

Als het goed is zie je nu dat de player blijft staan. Je kan allerhande collisions bedenken die je met de TileCollision kan doen. Denk aan een Portal-achtige game waar je door op de ene plek door het portal gaat, bij de andere portal uit kan komen. Of een Mario-achtige game waar een muntje verstopt zit in een doosje. Spring er tegen aan en het muntje komt uit het doosje.