-
Notifications
You must be signed in to change notification settings - Fork 16
Applying Analytical Geometry
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.
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.
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.
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.
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