Skip to content

Instantly share code, notes, and snippets.

@lfarroco
Last active March 9, 2025 00:14
Show Gist options
  • Save lfarroco/10fcdf6b32ea487b268b3fde84673f2b to your computer and use it in GitHub Desktop.
Save lfarroco/10fcdf6b32ea487b268b3fde84673f2b to your computer and use it in GitHub Desktop.
// Phaser Energy Beam
// Created with the help of DeepSeek-R1
// https://phaser.io/sandbox/scUBZ1Kv
class EnergyBeam extends Phaser.GameObjects.Graphics {
constructor(scene, config) {
super(scene, config);
scene.add.existing(this);
this.setBlendMode(Phaser.BlendModes.ADD);
// Configuration
this.start = config.start;
this.end = config.end;
this.segments = config?.segments || 40;
this.amplitude = config?.amplitude || 15;
this.frequency = config?.frequency || 2;
this.speed = config?.speed || 0.05;
this.color = config?.color || 0xFFD700;
this.thickness = config?.thickness || 20;
// Internal state
this.phase = 0;
this.points = [];
}
updateBeam() {
this.clear();
// Calculate beam vector
const vec = new Phaser.Math.Vector2(
this.end.x - this.start.x,
this.end.y - this.start.y
);
// Normalize and get perpendicular vector
const normalized = vec.clone().normalize();
const normal = new Phaser.Math.Vector2(-normalized.y, normalized.x);
// Generate points along the beam with sine wave offset
this.points = [];
for (let i = 0; i <= this.segments; i++) {
const t = i / this.segments;
const wave = Math.sin(t * Math.PI * this.frequency + this.phase);
// Calculate position using original vector direction
const basePos = new Phaser.Math.Vector2(this.start.x, this.start.y)
.add(vec.clone().scale(t));
const offset = normal.clone().scale(wave * this.amplitude);
const pos = basePos.add(offset);
this.points.push(pos);
}
// Draw the beam
this.lineStyle(this.thickness, this.color, 0.8);
this.beginPath();
this.moveTo(this.points[0].x, this.points[0].y);
for (let i = 1; i < this.points.length; i++) {
this.lineTo(this.points[i].x, this.points[i].y);
}
this.strokePath();
// Update phase for animation
this.phase += this.speed;
}
}
class MainScene extends Phaser.Scene {
constructor() {
super({ key: "MainScene" });
}
preload() { }
create() {
this.beams = []
const simple = new EnergyBeam(this, {
start: { x: 100, y: 300 },
end: { x: 600, y: 300 },
segments: 12,
amplitude: 20,
frequency: 1,
thickness: 20,
color: 0xFFD700,
speed: 0.1,
})
const twist1 = new EnergyBeam(this, {
start: { x: 100, y: 500 },
end: { x: 600, y: 500 },
segments: 12,
amplitude: 20,
frequency: 1,
thickness: 15,
color: 0xFFD700,
speed: 0.1,
})
const twist2 = new EnergyBeam(this, {
start: { x: 100, y: 500 },
end: { x: 600, y: 500 },
segments: 11,
amplitude: 20,
frequency: 3,
thickness: 10,
color: 0xFFD700,
speed: 0.1,
})
twist2.phase = 1.5
const twist3 = new EnergyBeam(this, {
start: { x: 100, y: 500 },
end: { x: 600, y: 500 },
segments: 12,
amplitude: 20,
frequency: 1.5,
thickness: 5,
color: 0xFFD700,
speed: 0.1,
})
twist3.phase = 2.5
this.beams = [
simple, twist1, twist2, twist3
]
}
update(time) {
this.beams.forEach(beam => beam.updateBeam())
}
}
const game = new Phaser.Game({
type: Phaser.AUTO,
width: 800,
height: 800,
backgroundColor: '#111111',
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH
},
scene: [MainScene]
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment