313 lines
6.5 KiB
Lua

emptyBoxCollider =
{
new = function(options)
local obj =
{
_orientation = options.orientation or 0,
surface = options.surface,
position = getIndexedPos(options.position),
force = options.force,
boxHalfs =
{
ends = options.boxLengths.ends / 2,
sides = options.boxLengths.sides / 2
},
childColliders = {},
childColliderOffsets = {},
}
if not obj.force then
obj.force = game.forces.enemy
end
obj.childColliders.top = obj.surface.create_entity{
name = options.nameEnds,
force = obj.force,
position = obj.position,
}
obj.childColliders.bottom = obj.surface.create_entity{
name = options.nameEnds,
force = obj.force,
position = obj.position,
}
obj.childColliders.left = obj.surface.create_entity{
name = options.nameSides,
force = obj.force,
position = obj.position,
}
obj.childColliders.right = obj.surface.create_entity{
name = options.nameSides,
force = obj.force,
position = obj.position,
}
setmetatable(obj, emptyBoxCollider.mt)
obj.setOrientation(obj._orientation)
return obj
end,
destroy = function(self)
for k,v in pairs(self.childColliders) do
if v.valid then
v.destroy()
end
end
end,
valid = function(self)
local val = true
for k,v in pairs(self.childColliders) do
if not v.valid then
val = false
break
end
end
if not val then
self.destroy()
end
return val
end,
moveChildColliders = function(self)
self.childColliders.top.teleport(math3d.vector2.add(self.position, self.childColliderOffsets.up))
self.childColliders.bottom.teleport(math3d.vector2.sub(self.position, self.childColliderOffsets.up))
self.childColliders.right.teleport(math3d.vector2.add(self.position, self.childColliderOffsets.right))
self.childColliders.left.teleport(math3d.vector2.sub(self.position, self.childColliderOffsets.right))
end,
setOrientation = function(self, orient)
self._orientation = orient
self.childColliderOffsets.up = math3d.vector2.rotate({0,self.boxHalfs.sides}, math.pi * 2 * orient)
self.childColliderOffsets.right = math3d.vector2.rotate({self.boxHalfs.ends,0}, math.pi * 2 * orient)
for k,v in pairs(self.childColliders) do
v.orientation = orient
end
self.moveChildColliders()
end,
teleport = function(self, pos)
self.position = getIndexedPos(pos)
self.moveChildColliders()
end,
getHealth = function(self)
local lowest = self.childColliders.top.health
for k,v in pairs(self.childColliders) do
if v.health < lowest then
lowest = v.health
end
end
return lowest
end,
setHealth = function(self, health)
for k,v in pairs(self.childColliders) do
v.health = health
end
end,
getSpeed = function(self)
local highest = self.childColliders.top.speed
for k,v in pairs(self.childColliders) do
if v.speed > highest then
speed = v.speed
end
end
return highest
end,
setSpeed = function(self, speed)
for k,v in pairs(self.childColliders) do
v.speed = speed
end
end,
setOperable = function(self, operable)
for k,v in pairs(self.childColliders) do
v.operable = operable
end
end,
get_driver = function(self)
for k,v in pairs(self.childColliders) do
local driver = v.get_driver()
if driver then
return driver
end
end
return nil
end,
set_driver = function(self, driver)
if driver == nil then
for k,v in pairs(self.childColliders) do
v.set_driver(nil)
end
end
end,
get_passenger = function(self)
for k,v in pairs(self.childColliders) do
local passenger = v.get_passenger()
if passenger then
return passenger
end
end
return nil
end,
set_passenger = function(self, passenger)
if passenger == nil then
for k,v in pairs(self.childColliders) do
v.set_passenger(nil)
end
end
end,
isPosInside = function(self, pos)
local delta = math3d.vector2.sub(getIndexedPos(pos), self.position)
local tX = delta[1]
local tY = delta[2]
local up = math3d.vector2.mul(self.childColliderOffsets.up, 1.1)
local right = math3d.vector2.mul(self.childColliderOffsets.right, 1.1)
local b1X = up[1]
local b1Y = up[2]
local b2X = right[1]
local b2Y = right[2]
--https://i.imgur.com/zQrgq0B.png
local a = (tY * b2X - tX * b2Y) / (b1Y * b2X - b1X * b2Y)
local b = (tY * b1X - tX * b1Y) / (b2Y * b1X - b2X * b1Y)
return math.abs(a) < 1 and math.abs(b) < 1, a, b
end,
ejectPlayers = function(self)
local rad = math.ceil(math.sqrt(self.boxHalfs.ends^2 + self.boxHalfs.sides^2))
local x = self.position[1]
local y = self.position[2]
local players = self.surface.find_entities_filtered{
area = {{x - rad, y - rad}, {x + rad, y + rad}},
type = "character",
}
for k, curPlayer in pairs(players) do
local pos = getIndexedPos(curPlayer.position)
local inside, a, b = self.isPosInside(pos)
if inside then
local deltaVec
if math.abs(a) > math.abs(b) then
local delta
if a > 0 then
delta = 1.2 - a
else
delta = -1.2 - a
end
deltaVec = math3d.vector2.mul(self.childColliderOffsets.up, delta)
else
local delta
if b > 0 then
delta = 1.2 - b
else
delta = -1.2 - b
end
deltaVec = math3d.vector2.mul(self.childColliderOffsets.right, delta)
end
curPlayer.teleport(math3d.vector2.add(pos, deltaVec))
end
end
end,
isChildEntity = function(self, ent)
for k,v in pairs(self.childColliders) do
if v == ent then
return true
end
end
return false
end,
}
emptyBoxCollider.mt =
{
__index = function(t, k)
if k == "valid" then
return emptyBoxCollider.valid(t)
elseif k == "orientation" then
return t._orientation
elseif k == "health" then
return emptyBoxCollider.getHealth(t)
elseif k == "speed" then
return emptyBoxCollider.getSpeed(t)
elseif k == "get_inventory" then
return function(...)
local params = {...}
return setmetatable({},
{__index = function(_t, _k)
return function(...)
for key, curCol in pairs(t.childColliders) do
curCol[k](unpack(params))[_k](...)
end
end
end})
end
elseif type(emptyBoxCollider[k]) == "function" then
return function(...)
return emptyBoxCollider[k](t, ...)
end
else
return emptyBoxCollider[k]
end
end,
__newindex = function(t, k, v)
if k == "orientation" then
emptyBoxCollider.setOrientation(t, v)
elseif k == "health" then
emptyBoxCollider.setHealth(t, v)
elseif k == "speed" then
emptyBoxCollider.setSpeed(t, v)
elseif k == "operable" then
emptyBoxCollider.setOperable(t, v)
end
end,
}