Multiplayer Tank – Del 3

Kollisionshantering

I föregående del utelämnades kollisionshanteringen för att det inte skulle bli för mycket på en gång. För detta projekt väljer vi en relativt enkel metod med kollisionshantering med cirklar (se tidigare artikel här).

För att detta ska fungera så måste vi definiera en radie för varje objekt som vi vill kolla kollision mot. Vi börjar med att göra en generell property som vi kallar för Radie i klassen GameObj

Tillägg till klassen GameObj

public virtual double Radie
{
	get
	{
		return (this.Gfx.Height / 2);
	}
	set
	{
	}
}

Med vår enkla generella property så blir alltså radien för objektet detsamma som halva höjden på grafiken till objektet.

Tillägg till klassen Explosion

public override double Radie
{
	get
	{
		return (26.0);
	}
	set
	{
	}
}

Eftersom grafiken till vår lilla explosion innehåller alla bildrutor till animationen så får vi ändra lite i property'n Radie för klassen Explosion. En radie på 26 pixlar passar bra till vår explosion.

Det enda som saknas nu är en metod för att kontrollera ifall en kollision inträffar. Eftersom vi vill kunna kontroller kollision mellan alla sorters objekt så väljer vi att skapa en ny metod CheckCollision i klassen GameObj.

Tillägg till klassen GameObj

public bool CheckCollision(GameObj target)
{
	bool collision;
	double xdiff = this.Position.X  - target.Position.X;
	double ydiff = this.Position.Y - target.Position.Y ;

	if ((xdiff * xdiff + ydiff * ydiff) < (this.Radie + target.Radie) * (this.Radie + target.Radie))
	{
		collision = true;
	}
	else
	{
		collision = false;
	}
	return (collision);
}

Vår metod returnerar en bool som talar om ifall vi har en kollision. Som inparameter tar metoden ett objekt av typen GameObj och det är det objektet som vi kollar kollision mot. Metoden för kollisionshantering som vi använder beskrivs här.

Nästa steg blir att använda vår metod. Vi ändrar lite i Game1.cs , närmare bestämt i Update() i loop'en som går igenom alla explosioner.

Tillägg till Game1.cs

for (int i = 0; i < allExplosions.Count; i++) //Loopa igenom alla explosioner
            {
                if (Player2.CheckCollision(allExplosions[i]))
                {
                    Player2.Life -= 1;

                }
                if (Player1.CheckCollision(allExplosions[i]))
                {
                    Player1.Life -= 1;

                }
                allExplosions[i].Update(gameTime); //Uppdatera explosion
                //Ta bort "färdiga" explosioner
                if (allExplosions[i].Active == false) allExplosions.RemoveAt(i);
            }

Samtidigt som vi loopar igenom alla explosioner och uppdaterar dem så kollar vi även ifall de kolliderar med Player1 eller Player2 och minskar då livet för berörd spelare.

Vi kontrollerar även ifall Player1 kolliderar med Player2 och gör en enkel och ganska trubbig algoritm för vad som skall hända. Vi gör följande tillägg till Update() i Game1.cs:

Tillägg till Game1.cs

if (Player1.CheckCollision(Player2))
{
	if (Player1.Speed < 1.0 && Player1.Speed < 1.0)
	{
		Player1.Speed = 0;
		Player2.Speed = 0;
		Player1.Position += Player2.Direction * Player2.Speed;
		Player2.Position += Player1.Direction * Player1.Speed;
	}
	else
	{
		if (Player1.Speed > Player2.Speed)
		{
			Player2.Life -= 5;
			Player1.Speed = 0F;
			Player2.Position = Player2.Position + Player1.Direction * 10F;
		}
		else
		{
			if (Player1.Speed == Player2.Speed)
			{
				Player2.Life -= 5;
				Player1.Speed = 0F;
				Player2.Position = Player2.Position + Player1.Direction * 10F;
				Player1.Life -= 5;
				Player2.Speed = 0F;
				Player1.Position = Player1.Position + Player2.Direction * 10F;
			}
			else
			{
				Player1.Life -= 5;
				Player2.Speed = 0F;
				Player1.Position = Player1.Position + Player2.Direction * 10F;
			}
		}
	}
}

Vår enkla algoritm kollar vilken tank som har högst hastighet vid kollisionen och ger skada till den andra tanken. Skulle vi ha samma hastighet (exempelvis vid en frontalkollision vid full hastighet) så tar båda spelare skada. Vi kollision så "puttas" tanken som tar skada och bådas hastighet sätts till noll. Vi börjar dock med att se till så att någon av tanksen håller en viss hastighet för att de ska kunna åsamka varandra skada.

Det finns flera möjligheter till förbättring vad gäller kollisionen och vad som skall hända. En variant är att avgöra hur pass "bra" träff man får in och anpassa skadan efter det. Man kan även kolla kollision med skotten och vid kollision detonera en explosion. Vad gäller kollisionen mellan spelarna så är den långt ifrån perfekt. Skulle exempelvis en spelare köra sakta in i sidan på en spelare som kör i full fart så tar spelaren som kör på skada. Det är bara att justera och prova fram en algoritm som funkar bra.

Vi måste även se till att det blir någon form av konsekvens av att man "dör". För att göra detta så skapar vi metoden Respawn i klassen Tank (ifall vi inte redan gjort detta).

Tillägg till klassen Tank

public void Respawn()
{
	Life = 100F;
	Random randomerare = new Random();
	Position = new Vector2(randomerare.Next(600), randomerare.Next(600));
	Angle = 0;

}

Dör en tank så återställer vi livet och slumpar ut en ny position.

Sist men inte minst så lägger vi till följande till Game1.cs i Update():

Tillägg till Game1.cs

if (Player2.Life < 0)
{
	Player1.Kills++;
	Player2.Respawn();
}
if (Player1.Life < 0)
{
	Player2.Kills++;
	Player1.Respawn();
}

När en spelare dör så återställer vi tanken och ger poäng till den andra spelaren.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *

Scroll to top