-- Ground drop: dropped items that players can pick up Drop = {} Drop.__index = Drop DropType = { WEAPON = 1, CONSUMABLE = 2, } DropState = { IDLE = 1, PICKUP = 2, DROP = 3, QUEUED_PICKUP = 4, FALLING = 5, } function Drop:new(image, config) self = setmetatable({}, Drop) self.image = image self.type = config.type or DropType.WEAPON self.item = config.item or {} self.x = config.x or 0 self.y = config.y or 0 self.width = self.image:getWidth() self.height = self.image:getHeight() self.state = config.state or DropState.IDLE self.bobTimer = math.random() * math.pi * 2 self.animTimer = 0 self.animDuration = 0.3 self.startX = self.x self.startY = self.y self.targetX = self.x self.targetY = self.y self.arcHeight = -24 self.alpha = 1 self.velY = 0 self.grounded = false self.bounceVelY = 0 return self end function Drop:setPickup(targetX, targetY) self.state = DropState.PICKUP self.animTimer = 0 self.startX = self.x self.startY = self.y self.targetX = targetX self.targetY = targetY self.alpha = 1 end function Drop:setDrop(targetX, targetY) self.state = DropState.DROP self.animTimer = 0 self.startX = targetX self.startY = targetY self.targetX = targetX self.targetY = targetY self.alpha = 0 end function Drop:isSolid(px, py, roomCollision) if px < 0 or px >= Config.ROOM_W or py < 0 or py >= Config.ROOM_H then return true end if roomCollision then return Utils.maskIsSolidAt(px, py, roomCollision) end return false end function Drop:update(dt, roomCollision) if self.state == DropState.IDLE then self.bobTimer = self.bobTimer + dt * 3 elseif self.state == DropState.PICKUP then self.animTimer = self.animTimer + dt local t = math.min(1, self.animTimer / self.animDuration) local linear = t local ease = 1 - (1 - t) * (1 - t) self.x = self.startX + (self.targetX - self.startX) * ease self.y = self.startY + (self.targetY - self.startY) * ease + self.arcHeight * math.sin(math.pi * linear) self.alpha = 1 - t if t >= 1 then self.state = nil end elseif self.state == DropState.DROP then self.animTimer = self.animTimer + dt local t = math.min(1, self.animTimer / self.animDuration) local linear = t local ease = t * t self.x = self.startX + (self.targetX - self.targetX) * ease self.y = self.startY + (self.targetY - self.startY) * ease + self.arcHeight * math.sin(math.pi * linear) self.alpha = math.min(1, t * 2) if t >= 1 then self.state = DropState.IDLE self.alpha = 1 self.bobTimer = 0 end elseif self.state == DropState.FALLING then self.velY = self.velY + Config.GRAVITY * dt if self.velY > 600 then self.velY = 600 end self.y = self.y + self.velY * dt local pLeft = math.floor(self.x) local pRight = math.ceil(self.x + self.width) - 1 local pBot = math.ceil(self.y + self.height) - 1 local onGround = false for col = pLeft, pRight do if self:isSolid(col, pBot + 1, roomCollision) then onGround = true break end end if onGround then self.y = pBot - self.height if self.velY > 120 then self.bounceVelY = -self.velY * 0.25 else self.bounceVelY = 0 end self.velY = 0 self.grounded = true end if self.grounded then self.y = self.y + self.bounceVelY * dt self.bounceVelY = self.bounceVelY + Config.GRAVITY * dt local pBot = math.ceil(self.y + self.height) - 1 local settled = true for col = pLeft, pRight do if self:isSolid(col, pBot + 1, roomCollision) then self.y = pBot - self.height self.bounceVelY = 0 settled = false break end end if settled then self.state = DropState.IDLE self.bobTimer = 0 self.bounceVelY = 0 self.velY = 0 end end if self.y + self.height > Config.ROOM_H then self.y = Config.ROOM_H - self.height self.velY = 0 self.grounded = true self.bounceVelY = 0 self.state = DropState.IDLE self.bobTimer = 0 end end end function Drop:draw() if self.alpha <= 0 then return end local drawY = self.y if self.state == DropState.IDLE then drawY = drawY + math.sin(self.bobTimer) * 2 end love.graphics.setColor(1, 1, 1, self.alpha) love.graphics.draw(self.image, self.x, drawY) love.graphics.setColor(1, 1, 1, 1) end function Drop:getBounds() return self.x, self.y, self.x + self.width, self.y + self.height end return Drop