Programmera spel i C++ för nybörjare/Collision detect


Det finns egentligen hur många sätt att kontrollers om en spelpjäs/sprite slagit i någonting, det vi i vardagslag kallar ”collision detect”. En bra svensk term saknas (krockupptäckt?). Du har säkert spelat ett dataspel någon gång där du är säker på att du träffade motståndaren bara för att se att den ändå bara fortsätter helt oskadad, alternativt att någon missade dig men att du träffas och dör ändå. Då har du råkat ut för en bug i spelets ”colllision detect”.

Kollision mot fast objekt redigera

Om man har en rörlig spelare i en fast värld kan man helt enkelt se om spelaren krockar genom att beräkna spelarens x,y-koordinater.

En värld inom väggar redigera

Om man har fasta väggar i spelet kan man helt enkelt beräkna om figurens x,y position gör att den krockar med en vägg. Flera av de första spelen bygger på den tekniken som Pong, Spaceinvaders och Breakout. Liksom merparten av de första plattformspelen som Donkey Kong och Super Mario. Det fungerar bara om man har hinder som man kan beräkna i förväg om man träffar eller inte och om man inte vill bli helt galen av alla matematiska beräkningar bör det inte vara alltför många väggar.

Labyrint redigera

En variant är när man rör sig i en labyrint som i t.ex. Pacman. Då kan man istället skapa spelplanen av rutor (sk. tiling) och med programkod ange om man kan gå ut ur sin egen ruta och in i intilliggande. Det är samtidigt en övning i logiska beräkningar. Ge varje ruta ett värde:

  • 0: Gå ut genom alla sidor
  • 1: Stopp uppåt
  • 2: Stopp höger
  • 4: Stopp neråt
  • 8: Stopp vänster

Dessa värden kan slås ihop för kombinerade rutor. Ett värde på 15 ger då att man inte kan gå in/ut alls medan ett värde på 10 visar att man bara kan gå uppåt och neråt. På det sättet kan man ganska lätt skriva en AI som hittar runt själv i labyrinten för t.ex. spöken. Detta system fungerar för alla spelplaner som bygger på "tiling" men passar bäst i labyrinter och liknande spelpaner när man bara har två val: "kan gå" eller "kan inte gå". Det passar sämre i stora världar med enstaka hinder eller spelplaner där olika terräng påverkar förflyttningens hastighet som t.ex. om man kör på en bilbana eller bredvid den.

Färgkarta redigera

Ännu ett sätt är att skapa två (eller fler) bilder över samma spelplan. Spelaren ser en bild och en annan bild används av programmet men är osynlig för spelaren. På den osynliga kartan fyller man i färger som i sin tur avgör hur spelpjäserna kan förflytta sig på spelplanen. Anta att du har en pansarvagn. På spelplanen finns en väg, öppna fält, ett träsk och rätt över spelplanen finns en å med en bro över. På den dolda bilden ritar man ut exakt samma karta men med olika tydliga färger för olika terrängtyper. Genom att veta var pansarvagnen befinner sig på spelkartan (x.y-koordinater) kan man se var den samtidigt befinner sig på den dolda kartan. Man ger vägen en färg på den dolda kartan och säger att om alla fyra hörnpixlarna på pansarvagnen befinner sig på vägen går pansarvagnen dubbelt så fort. Om alla fyra hörnpixlarna är på fälten är farten normal. Om någon pixel befinner sig på färgen för träsket halveras farten och om någon hörnpixel kommer ut i ån blir hastigheten framåt 0 (man måste fortfarande kunna backa). Färgerna kan vara vilka som helst med enkla RGB värden. Enklast är en bmp bild med standard VGA palett som sparas om i 32 bit färgformat, då kan inte färgvärdena förändras. Om man har ett spel med både markbundna och flygande enheter kan man ha ännu en bild som visar hinder på höjden (träd, spärrballonger o.dyl.). Så länge man har olika färger för olika hindertyper finns egentligen inga begränsningar.

Kollision mellan rörliga objekt redigera

Det finns egentligen tre olika sätt att kontrollera om två rörliga objekt kolliderar med varandra, t.ex. om en u-båt skickar iväg en torped mot ett fartyg på havsytan. (se mer: http://www.sfml-dev.org/wiki/en/sources/simple_collision_detection).

Cirkeltest redigera

Man beräknar radien i en bestämd cirkel runt de två olika föremålen och om radierna överlappar har en kollision skett. Detta är ett snabbt sätt att kontrollera kollisionen, men fungerar bäst på cirkelrunda föremål som t.ex. i ett biljardspel. Om man tänker sig ett långsmalt föremål, som ett krigsfartyg, som man ritar en cirkel runt ser man lätt att det uppstår ett stort område där fartyget inte finns, men som ändå beräknas som fartyg vid en kollision. Dvs. tänk dig att du skjuter en torped efter fartyget mot dess akter men missar och skjuter alldeles bredvid längs fartygets sida. Om du då beräknar ytan för en träff som en cirkel med samma radie åt sidorna som avståndet mellan för och akter, kommer spelet att anta att torpeden träffat och fartyget sänks trots att du egentligen missade fartyget.

Boxtest eller kartongtest redigera

Tänk dig att din u-båt skickar iväg en torped som läggs in i en osynlig skokartong exakt så stor att torpeden ryms. Tänk dig också att fartyget som skall träffas finns i en osynlig skokartong exakt så stor så att fartyget ryms i den. Om de två osynliga skokartongerna stöter in i varandra har det skett en kollision. På engelska kallas detta för ”bounding box collision”. Denna typ av beräkning passar bäst till avlånga föremål som krigsfartyg och torpeder. Om man programmerar 2D spel finns inga skokartonger utan bara en rektangel runt, men du förstår säkert skillnaden.

Pixeltest redigera

Pixeltest, eller ”pixel perfect” som det kallas på engelska, kontrollerar om en pixel från krigsfartyget finns under en given pixel på torpeden. Om så är fallet uppstår en kollision. Detta sätt ger det absolut mest rättvisa resultatet, det går helt enkelt inte att skjuta bredvid en fiende och ändå få en träff. Nackdelen är att det tar mycket längre tid att beräkna pixlar än att göra en snabb matematisk beräkning baserad på mittpunkter som inte tar hänsyn till spelpjäsernas exakta form.