1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
local bulletData = require "data.bulletData"
local Loot = require "objects.loot"
local Shot = {}
Shot.__index = Shot
function Shot:new(bulletType, target, firer, friendly)
local vx = target.x - firer.x
local vy = target.y - firer.y
local length = math.sqrt(vx*vx + vy*vy)
local cos, sin = vx / length, vy / length
local offset = (config.bullet.size + (firer.physicsShape and firer.physicsShape:getRadius() or 0)) / 2
local fireX = firer.x + cos * offset
local fireY = firer.y + sin * offset
local obj = {
type = bulletType,
x = fireX, y = fireY,
speed = { x = cos*config.bullet.speed, y = sin*config.bullet.speed },
orientation = math.asin(sin),
r = config.bullet.size,
damage = (bulletData[bulletType] and bulletData[bulletType].damage) or 100,
mass = (bulletData[bulletType] and bulletData[bulletType].mass) or 0.1,
friendly = friendly == nil and true or friendly
}
setmetatable(obj, Shot)
G.BodyLifeCycleManager:create(obj, config.bullet.size, "dynamic")
return obj
end
function Shot:die()
local shots = G.currentRoom.objects.shots
table.remove(shots, utils.indexof(shots, self))
G.BodyLifeCycleManager:destroy(self.physicsBody)
end
function Shot:onContact(other, contact)
local sort = other.objectType
local data = bulletData[self.type]
local dieOnThisContact = true
-- when contact with enemy, deal damage
if sort == "enemy" then
other:takeDamage(self.damage)
other:onHit(self)
if data and data.afterHit then
data.afterHit(other.x, other.y, other.type)
end
end
if sort == "player" then
if not self.friendly then
G.player:takeDamage(self.damage)
else
dieOnThisContact = false
end
end
if sort == "loot" or sort == "shot" then
dieOnThisContact = false
end
-- bouncy heart
if sort ~= "player" and data and data.bouncy then
-- if heart can still bounce
if not self.bounced then self.bounced = 0 end
if self.bounced <= data.bouncy then
dieOnThisContact = false
local dx = other.x - self.x
local dy = other.y - self.y
local angle = utils.atan2(dy, dx)
self.physicsBody:setLinearVelocity(math.cos(angle) * config.bullet.speed,
math.sin(angle) * config.bullet.speed)
self.bounced = self.bounced + 1
-- if not, then die or break
else
dieOnThisContact = true
if math.random(3) == 1 then
local lootItem = Loot:new("brokenheart", other.x, other.y)
table.insert(G.currentRoom.objects.loots, lootItem)
end
end
end
if dieOnThisContact then
self:die()
end
end
function Shot:update(dt)
if self.physicsBody and not self.physicsBody:isDestroyed() then
self.x = self.physicsBody:getX()
self.y = self.physicsBody:getY()
end
end
return Shot
|