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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
--- `Sprite`
-- Abstract class for drawable animated entities.
Sprite = {
animations =--[[table with animations]]nil,
current =--[[animations.default]]nil,
image =--[[love.graphics.newImage]]nil,
frame = 1,
delay = .1,
}
Sprite.__index = Sprite
--[[ Constructor of `Sprite`.
function Sprite:new (imagePath)
local o = setmetatable({}, self)
o:init(imagePath)
return o
end
]]
-- Cleans up reference to image on deletion.
function Sprite:delete ()
self.image = nil
end
-- Initializes new Sprite instance.
function Sprite:init (imagePath)
if type(imagePath) == "string" then
self:setImage(Sprite.newImage(imagePath))
end
end
-- Creates new Image object from path. Key-colours two shades of green. Static.
function Sprite.newImage (path)
local imagedata = love.image.newImageData(path)
local transparency = function(x, y, r, g, b, a)
if (r == 0 and g == 128 and b == 64) or
(r == 0 and g == 240 and b == 6) then
a = 0
end
return r, g, b, a
end
imagedata:mapPixel(transparency)
local image = love.graphics.newImage(imagedata)
return image
end
-- Sets an Image as an image.
function Sprite:setImage (image)
self.image = image
end
-- Returns current image Image.
function Sprite:getImage ()
return self.image
end
-- Sets new animations list.
function Sprite:setAnimationsList (t)
if t then
self.animations = t
self:setAnimation("default")
end
end
-- Sets current animation by table key.
function Sprite:setAnimation (animation)
self.frame = 1
self.delay = Sprite.delay -- INITIAL from metatable
self.current = self.animations[animation]
end
-- Returns current animation table.
function Sprite:getAnimation ()
return self.current
end
-- Get frame quad for drawing.
function Sprite:getQuad ()
if self.animations and self.current then
return self.current[self.frame]
end
end
-- TODO: Following five methods are stupid, do something about them!
-- Sprite can't be moved by itself. Positioning should be handled by children's methods.
function Sprite:getPosition ()
return 0,0
end
-- Sprite can't be rotated by itself. Rotation should be handled by children's methods.
function Sprite:getAngle ()
return 0
end
-- Sprite can't be mirrored by itself. Mirroring should be handled by children's methods.
function Sprite:getHorizontalMirror ()
return 1
end
function Sprite:getVerticalMirror ()
return 1
end
-- Sprite can't be offset by itself. Offsetting should be handled by children's methods.
function Sprite:getOffset ()
return 0,0
end
-- Drawing self to LOVE2D buffer.
-- If there is no Quad, it will draw entire image. It won't draw anything if there is no image.
-- TODO: it doesn't follow same pattern as `not.Hero.draw`. It should implement so it can be called from `not.World`.
-- TODO: change children if above changes are in effect: `not.Platform`, `not.Decoration`.
function Sprite:draw (offset_x, offset_y, scale)
local offset_x = offset_x or 0
local offset_y = offset_y or 0
local i, q = self:getImage(), self:getQuad()
local x, y = self:getPosition()
local angle = self:getAngle()
local scaleX = self:getHorizontalMirror()*(scale or 1)
local scaleY = self:getVerticalMirror()*(scale or 1)
-- pixel grid ; `approx` selected to prevent floating characters on certain conditions
local approx = math.floor
if (y - math.floor(y)) > 0.5 then approx = math.ceil end
local draw_y = (approx(y) + offset_y) * scale
local draw_x = (math.floor(x) + offset_x) * scale
if i then
love.graphics.setColor(255,255,255,255)
if q then
love.graphics.draw(i, q, draw_x, draw_y, angle, scaleX, scaleY, self:getOffset())
else
love.graphics.draw(i, draw_x, draw_y, angle, scaleX, scaleY, self:getOffset())
end
end
end
-- Animation updating.
function Sprite:update (dt)
if self.animations and self.current then
self.delay = self.delay - dt
if self.delay < 0 then
self.delay = self.delay + Sprite.delay -- INITIAL from metatable
self:goToNextFrame()
end
end
end
-- Moving to the next frame.
function Sprite:goToNextFrame ()
if self.current.repeated or not (self.frame == self.current.frames) then
self.frame = (self.frame % self.current.frames) + 1
else
self:setAnimation("default")
end
end
|