diff --git a/Code/Entities/BubbleWrapBlock.cs b/Code/Entities/BubbleWrapBlock.cs index b8d4592..bb3c568 100644 --- a/Code/Entities/BubbleWrapBlock.cs +++ b/Code/Entities/BubbleWrapBlock.cs @@ -22,29 +22,36 @@ private enum States private readonly bool canDash; private readonly float respawnTime; + private readonly bool delayRespawn; private float timer; private float rectEffectInflate = 0f; private readonly SoundSource breakSfx; private readonly MTexture[,,] nineSlice; + private readonly MTexture debrisTexture; private Vector2 wobbleScale = Vector2.One; private readonly Wiggler wobble; public BubbleWrapBlock(EntityData data, Vector2 offset) - : this(data.Position + offset, data.Width, data.Height, data.Bool("canDash"), data.Float("respawnTime")) { } + : this(data.Position + offset, data.Width, data.Height, data.Bool("canDash"), data.Float("respawnTime"), data.Attr("texture", "objects/VortexHelper/bubbleWrapBlock"), data.Bool("delayRespawn", false)) { } public BubbleWrapBlock(Vector2 position, int width, int height, bool canDash, float respawnTime) + : this(position, width, height, canDash, respawnTime, "objects/VortexHelper/bubbleWrapBlock", false) { } + + public BubbleWrapBlock(Vector2 position, int width, int height, bool canDash, float respawnTime, string texture, bool delayed) : base(position, width, height, safe: true) { this.SurfaceSoundIndex = SurfaceIndex.Brick; this.canDash = canDash; this.respawnTime = respawnTime; + this.delayRespawn = delayed; - MTexture block = GFX.Game["objects/VortexHelper/bubbleWrapBlock/bubbleBlock"]; - MTexture outline = GFX.Game["objects/VortexHelper/bubbleWrapBlock/bubbleOutline"]; + MTexture block = GFX.Game[texture + "/bubbleBlock"]; + MTexture outline = GFX.Game[texture + "/bubbleOutline"]; + this.debrisTexture = GFX.Game.GetOrDefault(texture + "/debris", GFX.Game["debris/VortexHelper/bubbleWrapBlock"]); this.nineSlice = new MTexture[3, 3, 2]; for (int i = 0; i < 3; i++) @@ -142,7 +149,7 @@ public void Break() { Debris debris = new Debris().orig_Init(this.Position + new Vector2(4 + i * 8, 4 + j * 8), '1').BlastFrom(this.Center); var debrisData = new DynData(debris); - debrisData.Get("image").Texture = GFX.Game["debris/VortexHelper/BubbleWrapBlock"]; + debrisData.Get("image").Texture = this.debrisTexture; this.Scene.Add(debris); } } @@ -164,24 +171,45 @@ public override void Update() if (this.timer <= 0f) if (CheckEntitySafe()) - Respawn(); + StartRespawn(); if (this.state == States.Gone) this.rectEffectInflate = Calc.Approach(this.rectEffectInflate, 3, 20 * Engine.DeltaTime); } - private void Respawn() + private void StartRespawn() { if (this.Collidable) return; + this.Collidable = true; + + if (this.delayRespawn) + { + Audio.Play("event:/game/09_core/bounceblock_reappear", this.Center); + float duration = 0.35f; + for (int i = 0; i < this.Width / 8f; i++) + { + for (int j = 0; j < this.Height / 8f; j++) + { + Vector2 pos = this.Position + new Vector2(4 + i * 8, 4 + j * 8); + Scene.Add(Engine.Pooler.Create().Init(pos + (pos - Center).SafeNormalize() * 12f, pos, this.debrisTexture, duration)); + } + } + Alarm.Set(this, duration, Respawn, Alarm.AlarmMode.Oneshot); + } + else + Respawn(); + } + + private void Respawn() + { this.wobble.Start(); RespawnParticles(); this.rectEffectInflate = 0f; EnableStaticMovers(); this.breakSfx.Play(SFX.game_05_redbooster_reappear); - this.Collidable = true; this.state = States.Idle; } @@ -208,4 +236,47 @@ private bool CheckEntitySafe() LifeMax = 0.8f, DirectionRange = (float) Math.PI / 6f }; + + private class RespawnDebris : Entity + { + private float duration; + private Vector2 from; + private Vector2 to; + + private Image sprite; + private float percent; + + public BubbleWrapBlock.RespawnDebris Init(Vector2 from, Vector2 to, MTexture texture, float duration) + { + if (this.sprite == null) + { + Add(this.sprite = new Image(texture)); + this.sprite.CenterOrigin(); + } + else + { + this.sprite.Texture = texture; + } + this.sprite.Rotation = Calc.Random.NextAngle(); + + this.from = from; + this.Position = from; + this.percent = 0f; + this.to = to; + this.duration = duration; + return this; + } + + public override void Update() + { + if (this.percent > 1f) + { + RemoveSelf(); + return; + } + this.percent += Engine.DeltaTime / this.duration; + this.Position = Vector2.Lerp(this.from, this.to, Ease.CubeIn(this.percent)); + this.sprite.Color = Color.White * this.percent; + } + } } diff --git a/Loenn/entities/bubble_wrap_block.lua b/Loenn/entities/bubble_wrap_block.lua index 4a705b8..ee75b2f 100644 --- a/Loenn/entities/bubble_wrap_block.lua +++ b/Loenn/entities/bubble_wrap_block.lua @@ -19,12 +19,13 @@ bubbleWrapBlock.placements = { width = 16, height = 16, canDash = true, - respawnTime = 3.0 + respawnTime = 3.0, + texture = "objects/VortexHelper/bubbleWrapBlock", + delayRespawn = false, } } } -local frame = "objects/VortexHelper/bubbleWrapBlock/bubbleBlock" local nine_patch_options = { mode = "fill", borderMode = "repeat", @@ -35,7 +36,7 @@ function bubbleWrapBlock.sprite(room, entity) local x, y = entity.x or 0, entity.y or 0 local width, height = entity.width or 16, entity.height or 16 - local ninePatch = drawableNinePatch.fromTexture(frame, nine_patch_options, x, y, width, height) + local ninePatch = drawableNinePatch.fromTexture((entity.texture or "objects/VortexHelper/bubbleWrapBlock").."/bubbleBlock", nine_patch_options, x, y, width, height) return ninePatch:getDrawableSprite() end diff --git a/Loenn/lang/en_gb.lang b/Loenn/lang/en_gb.lang index cfc6e4f..09e4aab 100644 --- a/Loenn/lang/en_gb.lang +++ b/Loenn/lang/en_gb.lang @@ -25,7 +25,9 @@ entities.VortexHelper/BowlPuffer.attributes.description.explodeTimer=The time, i # Bubble Wrap Block entities.VortexHelper/BubbleWrapBlock.placements.name.bubble_wrap_block=Respawning Dash Block entities.VortexHelper/BubbleWrapBlock.attributes.description.canDash=Whether the player is able to break this block by dashing into it. -entities.VortexHelper/BubbleWrapBlock.attributes.description.respawnTime=The time in seconds that this block takes to respawn after breaking. +entities.VortexHelper/BubbleWrapBlock.attributes.description.respawnTime=The time in seconds that this block takes to respawn after breaking. +entities.VortexHelper/BubbleWrapBlock.attributes.description.texture=The folder containing the block textures.\nMust contain two 24x24 textures, named "bubbleBlock" and "bubbleOutline", and optionally a "debris" texture. +entities.VortexHelper/BubbleWrapBlock.attributes.description.delayRespawn=Whether the attached objects should respawn slightly later than the block's collision, similar to Core Blocks. # Color Switch entities.VortexHelper/ColorSwitch.placements.name.all_cycle=Color Switch (All, Cycle)