User prompt
increase the volume of the s shape
User prompt
make the bullets go in S shpae in wave 2
User prompt
the speeds of buullets vary for each wave
User prompt
make the bullets disappear immiedaitly after going outside of the arena
User prompt
add an ouutline to arenaBorderf
Code edit (1 edits merged)
Please save this source code
User prompt
Soul Dodge: Heart of Battle
Initial prompt
make a game like UNDERTALE
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Arena border (visual only)
var ArenaBorder = Container.expand(function () {
var self = Container.call(this);
var border = self.attachAsset('arenaBorder', {
anchorX: 0.5,
anchorY: 0.5
});
border.alpha = 0.7;
return self;
});
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
};
return self;
});
// Soul (player) class
var Soul = Container.expand(function () {
var self = Container.call(this);
var soulSprite = self.attachAsset('soul', {
anchorX: 0.5,
anchorY: 0.5
});
// For hit flash
self.flash = function () {
tween(self, {
alpha: 0.3
}, {
duration: 80,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: 120
});
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Arena dimensions (centered)
// Heart-shaped soul (red)
// Arena border (white rectangle, thin)
// Bullet (white circle)
// Enemy warning (yellow, for telegraphing)
var ARENA_W = 1200;
var ARENA_H = 900;
var ARENA_X = 2048 / 2 - ARENA_W / 2;
var ARENA_Y = 2732 / 2 - ARENA_H / 2;
// Add arena border
var arenaBorder = new ArenaBorder();
arenaBorder.x = 2048 / 2;
arenaBorder.y = 2732 / 2;
game.addChild(arenaBorder);
// Add soul (player)
var soul = new Soul();
soul.x = 2048 / 2;
soul.y = 2732 / 2;
game.addChild(soul);
// GUI: Timer (shows wave time left)
var timerTxt = new Text2('', {
size: 80,
fill: "#fff"
});
timerTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timerTxt);
// GUI: Wave counter
var waveTxt = new Text2('', {
size: 80,
fill: "#fff"
});
waveTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(waveTxt);
waveTxt.y = 90;
// Game state
var bullets = [];
var currentWave = 0;
var waveTime = 0;
var waveTimer = 0;
var waveActive = false;
var soulAlive = true;
var dragSoul = false;
var dragOffsetX = 0;
var dragOffsetY = 0;
// Arena bounds (for clamping soul)
function clampSoul(x, y) {
var hw = 50,
hh = 50; // soul half size
var minX = ARENA_X + hw;
var maxX = ARENA_X + ARENA_W - hw;
var minY = ARENA_Y + hh;
var maxY = ARENA_Y + ARENA_H - hh;
return {
x: Math.max(minX, Math.min(maxX, x)),
y: Math.max(minY, Math.min(maxY, y))
};
}
// Touch/drag controls
function handleSoulMove(x, y, obj) {
if (!dragSoul || !soulAlive) return;
var pos = clampSoul(x - dragOffsetX, y - dragOffsetY);
soul.x = pos.x;
soul.y = pos.y;
}
game.move = function (x, y, obj) {
handleSoulMove(x, y, obj);
};
game.down = function (x, y, obj) {
// Only start drag if inside soul
var dx = x - soul.x,
dy = y - soul.y;
if (dx * dx + dy * dy <= 60 * 60) {
dragSoul = true;
dragOffsetX = x - soul.x;
dragOffsetY = y - soul.y;
handleSoulMove(x, y, obj);
}
};
game.up = function (x, y, obj) {
dragSoul = false;
};
// Waves definition
// Each wave: {duration, spawnFunc(tick, bulletsArr)}
var waves = [
// Wave 1: Simple slow bullets from top
{
duration: 180,
// 3s
spawnFunc: function spawnFunc(tick, arr) {
if (tick % 30 === 0) {
// Wave 1: slow bullets
var speed = 6;
for (var i = 0; i < 4; ++i) {
var b = new Bullet();
b.x = ARENA_X + 200 + i * 250;
b.y = ARENA_Y + 30;
b.vx = 0;
b.vy = speed;
arr.push(b);
game.addChild(b);
}
}
}
},
// Wave 2: Bullets from left/right
{
duration: 210,
// 3.5s
spawnFunc: function spawnFunc(tick, arr) {
if (tick % 24 === 0) {
// S-shape: bullets from left and right, with vy oscillating as a sine wave
var speed = 10;
var amplitude = 60; // increased vertical amplitude of S
var freq = 0.12; // increased frequency of S
// Left to right
var b1 = new Bullet();
b1.x = ARENA_X + 30;
b1.y = ARENA_Y + 150 + tick % 2 * 400;
b1.vx = speed;
b1.vy = amplitude * Math.sin((tick + 0) * freq);
// Store phase for S motion
b1._sPhase = (tick + 0) * freq;
b1._sDir = 1;
// Override update for S shape
b1._baseY = b1.y;
b1._baseX = b1.x;
b1._t = 0;
b1.update = function () {
this.x += this.vx;
this._t += 1;
// S shape: y = baseY + amplitude * sin((x - baseX) * freq)
this.y = this._baseY + amplitude * Math.sin((this.x - this._baseX) * freq);
};
arr.push(b1);
game.addChild(b1);
// Right to left
var b2 = new Bullet();
b2.x = ARENA_X + ARENA_W - 30;
b2.y = ARENA_Y + 750 - tick % 2 * 400;
b2.vx = -speed;
b2.vy = amplitude * Math.sin((tick + 60) * freq);
b2._sPhase = (tick + 60) * freq;
b2._sDir = -1;
b2._baseY = b2.y;
b2._baseX = b2.x;
b2._t = 0;
b2.update = function () {
this.x += this.vx;
this._t += 1;
this.y = this._baseY + amplitude * Math.sin((this.x - this._baseX) * freq);
};
arr.push(b2);
game.addChild(b2);
}
}
},
// Wave 3: Diagonal bullets from corners
{
duration: 240,
// 4s
spawnFunc: function spawnFunc(tick, arr) {
if (tick % 36 === 0) {
// Wave 3: diagonal, medium speed
var speed = 7.5;
var diag = speed / Math.sqrt(2);
// Top-left
var b1 = new Bullet();
b1.x = ARENA_X + 40;
b1.y = ARENA_Y + 40;
b1.vx = diag;
b1.vy = diag;
arr.push(b1);
game.addChild(b1);
// Top-right
var b2 = new Bullet();
b2.x = ARENA_X + ARENA_W - 40;
b2.y = ARENA_Y + 40;
b2.vx = -diag;
b2.vy = diag;
arr.push(b2);
game.addChild(b2);
// Bottom-left
var b3 = new Bullet();
b3.x = ARENA_X + 40;
b3.y = ARENA_Y + ARENA_H - 40;
b3.vx = diag;
b3.vy = -diag;
arr.push(b3);
game.addChild(b3);
// Bottom-right
var b4 = new Bullet();
b4.x = ARENA_X + ARENA_W - 40;
b4.y = ARENA_Y + ARENA_H - 40;
b4.vx = -diag;
b4.vy = -diag;
arr.push(b4);
game.addChild(b4);
}
}
},
// Wave 4: Random rain
{
duration: 210,
// 3.5s
spawnFunc: function spawnFunc(tick, arr) {
if (tick % 10 === 0) {
// Wave 4: fast random rain
var minSpeed = 12,
maxSpeed = 16;
var b = new Bullet();
b.x = ARENA_X + 80 + Math.floor(Math.random() * (ARENA_W - 160));
b.y = ARENA_Y + 30;
b.vx = 0;
b.vy = minSpeed + Math.random() * (maxSpeed - minSpeed);
arr.push(b);
game.addChild(b);
}
}
},
// Wave 5: Spiral (center out)
{
duration: 270,
// 4.5s
spawnFunc: function spawnFunc(tick, arr) {
if (tick % 12 === 0) {
// Wave 5: spiral, moderate speed
var speed = 9;
var angle = tick / 12 * 0.5;
for (var i = 0; i < 4; ++i) {
var a = angle + i * Math.PI / 2;
var b = new Bullet();
b.x = 2048 / 2;
b.y = 2732 / 2;
b.vx = Math.cos(a) * speed;
b.vy = Math.sin(a) * speed;
arr.push(b);
game.addChild(b);
}
}
}
}];
// Start first wave
function startWave(idx) {
currentWave = idx;
waveTime = 0;
waveActive = true;
waveTimer = 0;
// Remove all bullets
for (var i = bullets.length - 1; i >= 0; --i) {
bullets[i].destroy();
bullets.splice(i, 1);
}
// Update GUI
waveTxt.setText("Wave " + (currentWave + 1) + "/" + waves.length);
}
startWave(0);
// Main update loop
game.update = function () {
if (!soulAlive) return;
// Wave logic
if (waveActive) {
var wave = waves[currentWave];
wave.spawnFunc(waveTime, bullets);
waveTime++;
// Update timer GUI
var tleft = Math.max(0, Math.ceil((wave.duration - waveTime) / 60));
timerTxt.setText("Time: " + tleft + "s");
// End wave?
if (waveTime >= wave.duration) {
waveActive = false;
// Remove all bullets after short delay
LK.setTimeout(function () {
for (var i = bullets.length - 1; i >= 0; --i) {
bullets[i].destroy();
bullets.splice(i, 1);
}
// Next wave or win
if (currentWave + 1 < waves.length) {
startWave(currentWave + 1);
} else {
// Win!
LK.showYouWin();
}
}, 600);
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; --i) {
var b = bullets[i];
b.update();
// Remove if out of arena (immediately on leaving the border)
if (b.x < ARENA_X || b.x > ARENA_X + ARENA_W || b.y < ARENA_Y || b.y > ARENA_Y + ARENA_H) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// Collision with soul
var dx = b.x - soul.x,
dy = b.y - soul.y;
if (dx * dx + dy * dy < 45 * 45) {
// Hit!
soul.flash();
soulAlive = false;
LK.effects.flashScreen(0xff0000, 800);
LK.setTimeout(function () {
LK.showGameOver();
}, 600);
break;
}
}
};
// Initial GUI text
timerTxt.setText("Time: ");
waveTxt.setText("Wave 1/" + waves.length); ===================================================================
--- original.js
+++ change.js
@@ -177,10 +177,10 @@
spawnFunc: function spawnFunc(tick, arr) {
if (tick % 24 === 0) {
// S-shape: bullets from left and right, with vy oscillating as a sine wave
var speed = 10;
- var amplitude = 6; // vertical amplitude of S
- var freq = 0.045; // frequency of S
+ var amplitude = 60; // increased vertical amplitude of S
+ var freq = 0.12; // increased frequency of S
// Left to right
var b1 = new Bullet();
b1.x = ARENA_X + 30;
b1.y = ARENA_Y + 150 + tick % 2 * 400;
@@ -196,9 +196,9 @@
b1.update = function () {
this.x += this.vx;
this._t += 1;
// S shape: y = baseY + amplitude * sin((x - baseX) * freq)
- this.y = this._baseY + amplitude * Math.sin((this.x - this._baseX) * 0.045);
+ this.y = this._baseY + amplitude * Math.sin((this.x - this._baseX) * freq);
};
arr.push(b1);
game.addChild(b1);
// Right to left
@@ -214,9 +214,9 @@
b2._t = 0;
b2.update = function () {
this.x += this.vx;
this._t += 1;
- this.y = this._baseY + amplitude * Math.sin((this.x - this._baseX) * 0.045);
+ this.y = this._baseY + amplitude * Math.sin((this.x - this._baseX) * freq);
};
arr.push(b2);
game.addChild(b2);
}