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
|
require "not.Object"
--- `Sprite`
-- Abstract class for drawable animated entities.
Sprite = Object:extends()
Sprite.animations =--[[table with animations]]nil
Sprite.current =--[[animations.default]]nil
Sprite.image =--[[love.graphics.newImage]]nil
Sprite.frame = 1
Sprite.delay = .1
-- Constructor of `Sprite`.
-- TODO: Sprites' in general don't take actual Image in constructor. That is not only case of Decoration.
function Sprite:new (imagePath)
if type(imagePath) == "string" then
self:setImage(Sprite.newImage(imagePath))
end
end
-- Cleans up reference to image on deletion.
function Sprite:delete ()
self.image = nil
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/255 and b == 64/255) or
(r == 0 and g == 240/255 and b == 6/255) 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:setAnimations (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 prototype
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
-- Sprite's position. Can be overriden to add functionality.
function Sprite:getPosition () return 0,0 end
-- Sprite's angle. Can be overriden to add functionality.
function Sprite:getAngle () return 0 end
-- Sprite's horizontal and vertical mirrors. Can be overriden to add functionality.
function Sprite:getHorizontalMirror () return 1 end
function Sprite:getVerticalMirror () return 1 end
-- Sprite's drawing offset from position. Can be overriden to add functionality.
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: Sprite@draw requires a serious review!
-- 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 (debug)
local i, q = self:getImage(), self:getQuad()
local x, y = self:getPosition()
local angle = self:getAngle()
local scaleX = self:getHorizontalMirror()
local scaleY = self:getVerticalMirror()
-- 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)
local draw_x = math.floor(x)
if i and not self.hidden then
love.graphics.setColor(1, 1, 1, 1)
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 prototype
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
return Sprite
|