summaryrefslogtreecommitdiff
path: root/obj.lua
blob: 59a68d5d98e65747676b378f935210ae44bb7258 (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
local world = require "world"
local pi = math.pi

local obj = {}

obj.max_size = 20
local types = {}

function obj.load_types()
	for _, f in ipairs(love.filesystem.getDirectoryItems "objects") do
		local ts = assert(love.filesystem.load("objects/"..f))()
		for t, v in pairs(ts) do
			types[t] = v
		end
	end
end
 
function obj.new(type, pos, data, ...)
	world.last_id = world.last_id + 1
	local o = setmetatable(
		{id = world.last_id, data = data or {}, type = type}, obj)
	o.data.pos = pos
	o:init(...)
	return o
end

function obj.load(id, data)
	local o = setmetatable({id = id, data = data, type = data.type}, obj)
	o:init()
	return o
end
function obj.is_obj(v)
	return getmetatable(v) == obj
end

function obj:__index(v)
	if obj[v] then
		return obj[v]
	else
		return types[rawget(self, "type")][v]
	end
end

function obj:overload(m, ...)
	if types[self.type][m] then
		return types[self.type][m](self, ...)
	end
end

function obj:init(...)
	self.chunk = world.chunk(unpack(self.data.pos))
	self.chunk.objects[self.id] = self
	world.objects[self.id] = self
	return self:overload("init", ...)
end

function obj:tick(...)
	if self.data.vel then
		local vx, vy = unpack(self.data.vel)
		self.data.pos[1] = self.data.pos[1] + vx
		self.data.pos[2] = self.data.pos[2] + vy
	end
	if self.data.avel then
		self.data.angle = (self.data.angle or 0) + self.data.avel / pi
	end

	if self.hitbox then
		local x, y = unpack(self.data.pos)
		for o in world.in_box(
				x - obj.max_size, y - obj.max_size,
				x + obj.max_size, y + obj.max_size) do
			if o.hitbox and o ~= self then
				local dist = o.hitbox + self.hitbox
				local ox, oy = unpack(o.data.pos)
				local dx, dy = ox - x, oy - y
				if dx*dx + dy*dy < dist*dist then
					local angle = math.atan2(dy, dx)
					-- reposition self outside of collided object
					self.data.pos[1] =
						self.data.pos[1] - math.cos(angle) * dist + dx
					self.data.pos[2] =
						self.data.pos[2] - math.sin(angle) * dist + dy
					self:collision(o, angle)
					o:collision(self, pi - angle)
				end
			end
		end
	end

	self:overload("tick", ...)

	local chunk = world.chunk(unpack(self.data.pos))
	if chunk ~= self.chunk then
		self.chunk.objects[self.id] = nil
		chunk.objects[self.id] = self
		self.chunk = chunk
	end
end

function obj:draw(...)
	love.graphics.push()
	love.graphics.translate(unpack(self.data.pos))
	if self.data.angle then
		love.graphics.rotate(self.data.angle)
	end
	self:overload("draw", ...)
	love.graphics.pop()
end

function obj:collision(collided)
	return self:overload("collision", collided)
end

function obj:remove()
	self.chunk.objects[self.id] = nil
	world.objects[self.id] = nil
	return self:overload "remove"
end

return obj