-- Spawner | |
Classes.CrabAttachment_CrabAttachment_BeamBlasterSpawner = Class(CrabAttachmentSpawner) | |
CrabAttachment_CrabAttachment_BeamBlasterSpawner.spawnClassName = "CrabAttachment_BeamBlaster" | |
-- Enemy | |
Classes.CrabAttachment_BeamBlaster = Class(CrabAttachment) | |
function CrabAttachment_BeamBlaster:SetupActiveState() | |
self.animSetBottom = { | |
disarmed = "CrabGiant_Laser_Idle", | |
arming = "CrabGiant_Laser_Warmup", | |
armed = "CrabGiant_Laser_Ready", | |
blastStart = "CrabGiant_Laser_Ready", | |
blasting = "CrabGiant_Laser_Ready", | |
blastStop = "CrabGiant_Laser_Cooldown", | |
} | |
self.animSetTop = { | |
disarmed = "CrabGiant_Laser_Top", | |
arming = "CrabGiant_Laser_Top", | |
armed = "CrabGiant_Laser_Top", | |
blastStart = "CrabGiant_Laser_Top", | |
blasting = "CrabGiant_Laser_Top", | |
blastStop = "CrabGiant_Laser_Top", | |
} | |
self.blasterBottomSprite = self:Sprite(self.animSetBottom.disarmed, self.defLayer, 0) | |
self.blasterTopSprite = self:Sprite(self.animSetTop.disarmed, self.defLayer, 15) | |
self:AddPiece(self.blasterBottomSprite) | |
self:AddPiece(self.blasterTopSprite) | |
self.armed = false | |
end | |
function CrabAttachment_BeamBlaster:Arm(finishFunc) | |
FadeOutDestroyComponent(self, "chargeAc", 0.15) | |
self:DelayCall(0.6, self.activeMachine, function() | |
self.chargeAc = game.loopManager:PlaySound("crabLaserCharge", 1, Vec2(0, 0)) | |
self.machine:Add(function() | |
FadeOutDestroyComponent(self, "chargeAc", 0.15) | |
end) | |
self:PlayAnim(self.blasterBottomSprite, self.animSetBottom.arming) | |
self:PlayAnim(self.blasterTopSprite, self.animSetTop.arming, self.machine, function() | |
self:PlayAnim(self.blasterBottomSprite, self.animSetBottom.armed) | |
self:PlayAnim(self.blasterTopSprite, self.animSetTop.armed) | |
self.emitter = self:Emitter("BurnyParticlesBurstBeam2", self.defLayer, 13, Vec2(0, 28)) | |
self.emitter.palette = "Pink" | |
self:AddPiece(self.emitter) | |
self.armed = true | |
CallCallback(finishFunc) | |
end) | |
end) | |
end | |
local jPatternDef = | |
Bp_Shoot(11, | |
function(pattern, i, num) | |
pattern.dir = Vec2(0, -1) | |
local alpha = (i - 1) / (num - 1) | |
alpha = alpha < 0 and 0 or alpha > 1 and 1 or alpha | |
pattern.offset = Vec2(alpha * 64 - 32, 0) / 32 | |
pattern.speed = 160 + (1 - math.abs(alpha - 0.5) * 2) * 40 | |
end, | |
Sp_UseDef(BaseEnemy.unvauntableBulletDef) | |
) | |
function CrabAttachment_BeamBlaster:DoBlast(finishFunc) | |
if game.gameSessionInfo.difficulty == "judgement" then | |
self.activeMachine:Add(self:StartBulletPattern(jPatternDef, Vec2(0, 0))) | |
end | |
FadeOutDestroyComponent(self, "chargeAc", 0.15) | |
self.fireAc = game.loopManager:PlaySound("crabLaserFire", 1, Vec2(0, 0)) | |
self.activeMachine:Add(function() | |
FadeOutDestroyComponent(self, "fireAc", 0.15) | |
end) | |
local beamSet = BeamSpecial.beamSetBurst | |
local laserOffset = Vec2(0, 28) | |
local laser = self.activeMachine:Add(self:CreateLaser({ laserOffset = laserOffset, beamSet = beamSet, })) | |
laser.scale = Vec2(0.2, 1) | |
self:AddPiece(laser) | |
local attachTick = self.activeMachine:Add(Tick{ | |
owner = self, | |
tickWorld = self.world.postPhysTickWorld, | |
priority = 2000, | |
func = function(dt) | |
laser.pos = self.phys.pos * 32 + laserOffset | |
end, | |
}) | |
local maxWidth = 50 | |
local maxScale = maxWidth / beamSet.width | |
local attackDur, sustainDur, releaseDur = 0.08, 0.25, 0.2 | |
local sync = Synchronizer{} | |
sync:Add(self.blasterTopSprite) | |
self:InterpLaser(laser, maxScale, attackDur, sustainDur, releaseDur, function(state) | |
if state == 'attack' then | |
self:PlayAnim(self.blasterBottomSprite, self.animSetBottom.blastStart) | |
self:PlayAnim(self.blasterTopSprite, self.animSetTop.blastStart, self.machine, function() | |
self:PlayAnim(self.blasterBottomSprite, self.animSetBottom.blasting) | |
self:PlayAnim(self.blasterTopSprite, self.animSetTop.blasting) | |
end) | |
elseif state == 'release' then | |
DestroyComponent(self, "emitter") | |
self:PlayAnim(self.blasterBottomSprite, self.animSetBottom.blastStop) | |
self:PlayAnim(self.blasterTopSprite, self.animSetTop.blastStop, self.machine, function() | |
self:PlayAnim(self.blasterBottomSprite, self.animSetBottom.blastStop) | |
self:PlayAnim(self.blasterTopSprite, self.animSetTop.blastStop, self.machine, function() sync:Remove(self.blasterTopSprite) end) | |
end) | |
elseif state == 'finish' then | |
laser:Destroy() | |
self.armed = false | |
self:PlayAnim(self.blasterBottomSprite, self.animSetBottom.disarmed) | |
self:PlayAnim(self.blasterTopSprite, self.animSetTop.disarmed) | |
FadeOutDestroyComponent(self, "fireAc", 0.15) | |
sync:Sync(finishFunc) | |
end | |
end) | |
end | |
function CrabAttachment_BeamBlaster:Blast(finishFunc) | |
self:DoBlast(finishFunc) | |
end | |
function CrabAttachment_BeamBlaster:Active_FireState(finishFunc) | |
if not self.armed then | |
self:Arm(finishFunc) | |
else | |
self:Blast(finishFunc) | |
end | |
end | |
function CrabAttachment_BeamBlaster:CreateLaser(beamInfo) | |
local layer = self.defLayer | |
local laser = Laser{ | |
world = self.world, | |
width = beamInfo.beamSet.width, | |
segmentAnims = beamInfo.beamSet.animSet, | |
segmentLength = 16, | |
centralBlockMask = self.world.physWorld:Filter("enemy", "obstruction"), | |
blockMask = 0, | |
hitMask = COLLISION_MASK_ENEMY_BULLET, | |
minLength = 512, | |
maxLength = 512, | |
numTraces = beamInfo.beamSet.numTraces, | |
speed = 640, | |
pos = self.phys.pos * 32 + beamInfo.laserOffset, | |
dir = Vec2(0, -1), | |
layer = self.world.layers:Get(self.defLayer), | |
depth = self.depth + 1, | |
cap = beamInfo.beamSet.cap, | |
capBlocked = beamInfo.beamSet.capBlocked, | |
palette = "Pink", | |
blockFunc = function(hitShape) return false end, | |
hitFunc = function(hitShape) | |
local ud = hitShape.userdata | |
local mt = getmetatable(ud) | |
if ud and IsChildOf(mt, PlayerShip) and not ud.__destroyed and not ud.invincible and hitShape ~= ud.shape then | |
ud:Die(self) | |
end | |
end, | |
} | |
return laser | |
end | |
function CrabAttachment_BeamBlaster:InterpLaser(laser, maxScale, attackDur, sustainDur, releaseDur, stateFunc) | |
assert(stateFunc) | |
local function InterpLaserOut(t) | |
local scale = self:Ease(t, 0.01, maxScale, "outQuad") | |
laser.scale = Vec2(scale, 1) | |
end | |
local function InterpLaserIn(t) | |
local scale = self:Ease(t, maxScale, 0.01, "inExpo") | |
laser.scale = Vec2(scale, 1) | |
end | |
stateFunc('attack') | |
self:Interp(attackDur, self.activeMachine, InterpLaserOut, function() | |
stateFunc('sustain') | |
self:DelayCall(sustainDur, self.activeMachine, function() | |
stateFunc('release') | |
self:Interp(releaseDur, self.activeMachine, InterpLaserIn, function() stateFunc('finish') end) | |
end) | |
end) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment