Skip to content

Applying Analytical Geometry

Luan Orlandi edited this page Feb 13, 2017 · 7 revisions

This is the final page. All analytical geometry concepts has been covered, from now we will apply them in the game.

Some of the code show here will not be the same in the game, details that may increase complexity and difficulty to understand what is happening.

Movement

Each ship in the game, including the player, moves with different movements. This difference is caused only by speed and acceleration different from each other. They are determined by the player input or AI.

With the speed and acceleration defined, the below method is applied in each update cycle of the game:

function Ship:move()
	-- define deceleration
	if self.acc.x == 0 and self.spd.x > 0 then self.acc.x = -self.dec end
	if self.acc.x == 0 and self.spd.x < 0 then self.acc.x = self.dec end
	if self.acc.y == 0 and self.spd.y > 0 then self.acc.y = -self.dec end
	if self.acc.y == 0 and self.spd.y < 0 then self.acc.y = self.dec end

	-- check if exceed maximum acceleration
	if self.acc:norm() > self.maxAcc then
		self.acc:normalize()
		self.acc.x = self.acc.x * self.maxAcc
		self.acc.y = self.acc.y * self.maxAcc
	end
	
	-- define speed
	self.spd:sum(self.acc)
	
	-- check if speed is almost zero
	if self.spd.x < self.minSpd and self.spd.x > -self.minSpd then self.spd.x = 0 end
	if self.spd.y < self.minSpd and self.spd.y > -self.minSpd then self.spd.y = 0 end
	
	-- check if exceed maximum speed
	if self.spd:norm() > self.maxSpd then
		self.spd:normalize()
		self.spd.x = self.spd.x * self.maxSpd
		self.spd.y = self.spd.y * self.maxSpd
	end
	
	-- define position
	self.pos:sum(self.spd)
	
	self.sprite:setLoc(self.pos.x, self.pos.y)
end

The first part of the code define deceleration, in the case for the ship has no acceleration (even though space doesn't have resistance to cause this, in a game like this is necessary, otherwise it would be complicated to play).

After this comes what we learn before, we normalize the acceleration vector to avoid a ship to move faster than it should. So, with the acceleration properly defined, we set the ship's speed with a simple sum of vectors.

The minimum speed is set to avoid small speeds, as a result of floating operations (you may have see bugs in games like this when a character slowly moves to a direction, without any input).

Maximum speed is also normalized, regardless if we have already fixed acceleration we may still have some ships don't use acceleration, for example one that has a constant movement, but is not the case for this game.

On the last lines, we set ship's position with a sum of vectors. The ship will move in the direction of the speed.

The vector position is just a object's class we have given to the game. The engine will move the ship, which is a sprite in the screen, by setting it's location, with setLoc() function.

Collision

Collisions has already been well explained. Here you will see examples of use in the game: the hit boxes of the player's ship and laser shot collision detection.

Hit box

Fail to load image :(

The player's hit boxes above are created in this code:

local deckSize = Vector:new(60 * window.scale, 60 * window.scale)

Player = {}
Player.__index = Player

function Player:new(pos)
	local P = {}
	setmetatable(P, Player)
	
	P.pos = pos

	P.area.size = Rectangle:new(
		Vector:new(0, 0), deckSize)

	P.area:newRectangularArea(
		Vector:new(0, 0),
		Vector:new(0.2 * deckSize.x, 1.0 * deckSize.y))

	P.area:newRectangularArea(
		Vector:new(0, -0.4 * deckSize.y),
		Vector:new(0.8 * deckSize.x, 0.2 * deckSize.y))

	return P
end

The deckSize is a vector of the sprite size (deck is a texture loaded in the memory).

From the image, we see that, for example, the ship has a hit box of the same height of the deck, but 20% (0.2) of the width. This rectangle has the same center of the bigger rectangle, so create it (0, 0) in the center and (0.2 * deckSize.x, 1.0 * deckSize.y) in size (the top right vector). The other hitbox is also added in the same way, with different values.

Collision detection

The function below receives all shots and ships in tables. Checking all collisions, it will damage ships in contact with a shot and destroying the shot if it hit a target, to avoid that it moves through the ship.

function shotsCheckCollision(shots, ship)
	local s = 1
	local hit = false
	
	while s <= #shots and not hit do
		local shot = shots[s]
		
		-- ship.aim indicates the orientation
		if shot.area:detectCollision(
			Vector:new(0, 1), shot.pos,
			ship.area, ship.aim, ship.pos) then
			
			hit = true
			ship:damaged(shot.dmg) -- apply shot damage to ship's hit points
			
			-- the shot is removed from the screen and table,
			-- to avoid that it can it another target again
			Shot.destroy(shot)
			table.remove(shots, s)
		else
			-- this shot has no collision with any ship
			-- move to the next shot
			s = s + 1
		end
	end
end

A shot can hit one target only in this function. While it hasn't hit a target, search one in the ship's table.


The wiki ends here. I hope you could learn something about the game, math, programming or anything with this wiki.

Feel free to contact me and give suggestion if you like: orlandi.luan@gmail.com