summaryrefslogtreecommitdiffhomepage
path: root/not/Sprite.lua
blob: a4bd6b83588fc84c745c64bc85d4917773b5f275 (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
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