summaryrefslogtreecommitdiffhomepage
path: root/not/Sprite.lua
blob: 25d85f10099764cb823d771b286b6b01284c0e66 (plain)
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