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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
require "data.directions"
local Body = require "objects.Body"
local enemyData = require "data.enemyData"
local Enemy = {}
Enemy.__index = Enemy
local FrameTimer = require "utils.frameTimer"
function Enemy:new(name, location)
local data = enemyData[name]
local obj = {
type = name,
presetLocation = (type(location) == "string" and location) or nil,
x = (type(location) == "table" and location.x) or nil,
y = (type(location) == "table" and location.y) or nil,
body = Body:new("circle",
data.size or nil, nil,
data.zoom or 1
),
speed = data.speed or nil,
health = data.health or nil,
stunned = false,
frameTimer = FrameTimer:new(config.frameRate,
(data.sprite and data.sprite.totalFrames) or 1),
movePattern = data.movePattern or nil,
}
setmetatable(obj, Enemy)
return obj
end
function Enemy:isBlocked()
end
function Enemy:move(dt)
if self.stunned and self.stunned > 0 then
self.stunned = self.stunned - dt
return false
end
if self.movePattern == "vertical" then
self:moveVertical(G.player.x, dt)
else self:moveTo(G.player.x, G.player.y, dt)
end
end
function Enemy:moveTo(x, y, dt)
local dv = self.speed * dt
local function getDelta(axis, destination, direction)
-- delta is either +1 or -1, represents the direction
local delta = (self[axis] < destination and 1) or (self[axis] > destination and -1) or 0
-- check if the movement is blocked, if so delta is 0, meaning no movement
local isBlocked = utils.isBlocked(self.body, self.x, self.y, direction, axis, dv*delta)
if isBlocked then delta = 0 end
return delta
end
local dx = getDelta("x", x, Direction.RIGHT) -- RIGHT and LEFT means the same for isBlocked()
local dy = getDelta("y", y, Direction.DOWN) -- the same for DOWN and UP
self.x = self.x + dx * dv
self.y = self.y + dy * dv
end
function Enemy:moveVertical(toX, dt)
self:moveTo(toX, self.y, dt)
end
function Enemy:facing()
local dx = self.x - G.player.x
local dy = self.y - G.player.y
local angle = math.atan2(dy, dx)
local dir
if angle >= -math.pi / 4 and angle < math.pi / 4 then
dir = Direction.LEFT
elseif angle >= math.pi / 4 and angle < 3 * math.pi / 4 then
dir = Direction.UP
elseif angle >= -3 * math.pi / 4 and angle < -math.pi / 4 then
dir = Direction.DOWN
else
dir = Direction.RIGHT
end
return dir
end
function Enemy:getsAttacked(damage)
self.health = self.health - damage
if self:isDead() then
self:die()
end
end
function Enemy:isDead()
return self.health <= 0
end
function Enemy:die()
-- drop loots
for i, item in ipairs(enemyData[self.type].drops) do
local temp = math.random(10) / 10
if temp <= item.chances then
local offset = (i - 1) * 5
loot.drop(self.x + offset, self.y + offset, item.type)
end
end
end
function Enemy:stun(duration)
self.stunned = duration
end
return Enemy
|