| Server IP : 202.61.199.114 / Your IP : 216.73.217.139 Web Server : nginx/1.22.1 System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64 User : web20 ( 1018) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /proc/3951574/root/tmp/rrpkg/ |
Upload File : |
/* Reel Royale – ParticleEngine (Canvas, GPU-freundlich) */
export class ParticleEngine {
constructor(canvas) {
this.cv = canvas;
this.ctx = canvas.getContext('2d');
this.parts = [];
this.ambient = [];
this.mode = null;
this.accent = '#ffce53';
this.running = false;
this.dpr = Math.min(window.devicePixelRatio || 1, 2);
this._resize = this._resize.bind(this);
window.addEventListener('resize', this._resize);
this._resize();
}
_resize() {
this.w = this.cv.clientWidth || window.innerWidth;
this.h = this.cv.clientHeight || window.innerHeight;
this.cv.width = this.w * this.dpr;
this.cv.height = this.h * this.dpr;
this.ctx.setTransform(this.dpr, 0, 0, this.dpr, 0, 0);
}
setMode(mode, accent) {
this.mode = mode;
if (accent) this.accent = accent;
this.ambient = [];
const count = mode ? 46 : 0;
for (let i = 0; i < count; i++) this.ambient.push(this._spawnAmbient());
this.start();
}
clearMode() { this.mode = null; this.ambient = []; }
_spawnAmbient() {
const m = this.mode;
const base = { x: Math.random() * this.w, y: Math.random() * this.h, ttl: Infinity };
switch (m) {
case 'sand': return { ...base, vx: 0.3 + Math.random(), vy: -0.1 + Math.random() * 0.3, r: 1 + Math.random() * 1.5, c: 'rgba(255,210,120,', a: 0.3 + Math.random() * 0.3, kind: 'dot' };
case 'ember': return { ...base, y: this.h + Math.random() * 60, vx: -0.4 + Math.random() * 0.8, vy: -0.6 - Math.random() * 1.1, r: 1 + Math.random() * 2, c: 'rgba(255,140,60,', a: 0.4 + Math.random() * 0.4, kind: 'glow' };
case 'fire': return { ...base, y: this.h + Math.random() * 60, vx: -0.5 + Math.random(), vy: -0.9 - Math.random() * 1.5, r: 1.5 + Math.random() * 3, c: 'rgba(255,110,40,', a: 0.4 + Math.random() * 0.5, kind: 'glow' };
case 'bubble': return { ...base, y: this.h + Math.random() * 60, vx: -0.2 + Math.random() * 0.4, vy: -0.4 - Math.random() * 0.8, r: 2 + Math.random() * 4, c: 'rgba(150,225,255,', a: 0.2 + Math.random() * 0.3, kind: 'ring' };
case 'leaf': return { ...base, y: -20, vx: -0.4 + Math.random() * 0.8, vy: 0.4 + Math.random() * 0.7, r: 2 + Math.random() * 2, c: 'rgba(150,220,140,', a: 0.4 + Math.random() * 0.3, kind: 'dot', sway: Math.random() * 6 };
case 'spark': return { ...base, vx: -0.3 + Math.random() * 0.6, vy: -0.3 + Math.random() * 0.6, r: 1 + Math.random() * 1.5, c: 'rgba(255,200,110,', a: 0.3 + Math.random() * 0.4, kind: 'glow' };
default: return { ...base, vx: 0, vy: 0, r: 1, c: 'rgba(255,255,255,', a: 0.2, kind: 'dot' };
}
}
_stepAmbient(p) {
p.x += p.vx; p.y += p.vy;
if (p.sway) p.x += Math.sin(p.y / 30) * 0.4;
if (p.y < -30 || p.y > this.h + 40 || p.x < -30 || p.x > this.w + 30) Object.assign(p, this._spawnAmbient(), this.mode === 'leaf' ? { y: -20 } : {});
}
// ---- Effekte ----
burst(x, y, kind = 'gold', n = 24) {
const palette = {
gold: ['#ffce53', '#ffae2b', '#fff3c2'],
fire: ['#ff7a2c', '#ff3b3b', '#ffd166'],
water: ['#56d6ff', '#bdf0ff', '#3fb6d3'],
confetti: ['#ff5d6c', '#56d6ff', '#4ad991', '#ffce53', '#c77dff'],
spark: ['#ffe9a8', '#ffce53', '#fff'],
}[kind] || ['#ffce53'];
for (let i = 0; i < n; i++) {
const a = Math.random() * Math.PI * 2;
const sp = 1 + Math.random() * 6;
this.parts.push({
x, y, vx: Math.cos(a) * sp, vy: Math.sin(a) * sp - 2,
g: 0.12, r: 2 + Math.random() * 3, ttl: 50 + Math.random() * 30, life: 0,
color: palette[(Math.random() * palette.length) | 0],
shape: kind === 'confetti' ? 'rect' : 'dot', rot: Math.random() * 6,
});
}
this.start();
}
coinShower(n = 60) {
for (let i = 0; i < n; i++) {
this.parts.push({
x: Math.random() * this.w, y: -20 - Math.random() * 200,
vx: -0.5 + Math.random(), vy: 2 + Math.random() * 4, g: 0.08,
r: 5 + Math.random() * 5, ttl: 120, life: 0, color: '#ffce53', shape: 'coin', rot: Math.random() * 6,
});
}
this.start();
}
confetti(n = 90) {
for (let i = 0; i < n; i++) {
this.parts.push({
x: Math.random() * this.w, y: -20 - Math.random() * 100,
vx: -1 + Math.random() * 2, vy: 1.5 + Math.random() * 3, g: 0.05,
r: 3 + Math.random() * 4, ttl: 150, life: 0,
color: ['#ff5d6c', '#56d6ff', '#4ad991', '#ffce53', '#c77dff'][(Math.random() * 5) | 0],
shape: 'rect', rot: Math.random() * 6, vr: -0.2 + Math.random() * 0.4,
});
}
this.start();
}
/** Feuerwerk: mehrere zeitversetzte Explosionen oben im Bild (für besonders große Gewinne). */
fireworks(shots = 6) {
const kinds = ['gold', 'confetti', 'spark', 'fire', 'water'];
for (let i = 0; i < shots; i++) {
setTimeout(() => {
const x = this.w * (0.18 + Math.random() * 0.64);
const y = this.h * (0.12 + Math.random() * 0.4);
this.burst(x, y, kinds[(Math.random() * kinds.length) | 0], 28);
}, i * 360);
}
}
start() { if (!this.running) { this.running = true; requestAnimationFrame(() => this._loop()); } }
_loop() {
const ctx = this.ctx;
ctx.clearRect(0, 0, this.w, this.h);
// Ambient
for (const p of this.ambient) {
this._stepAmbient(p);
ctx.globalAlpha = p.a;
ctx.fillStyle = p.c + '1)';
if (p.kind === 'ring') { ctx.strokeStyle = p.c + '1)'; ctx.lineWidth = 1; ctx.beginPath(); ctx.arc(p.x, p.y, p.r, 0, 7); ctx.stroke(); }
else if (p.kind === 'glow') { ctx.shadowBlur = 8; ctx.shadowColor = p.c + '1)'; ctx.beginPath(); ctx.arc(p.x, p.y, p.r, 0, 7); ctx.fill(); ctx.shadowBlur = 0; }
else { ctx.beginPath(); ctx.arc(p.x, p.y, p.r, 0, 7); ctx.fill(); }
}
ctx.globalAlpha = 1;
// Effekt-Partikel
for (let i = this.parts.length - 1; i >= 0; i--) {
const p = this.parts[i];
p.life++; p.vy += p.g; p.x += p.vx; p.y += p.vy; p.rot += (p.vr || 0.05);
const fade = 1 - p.life / p.ttl;
if (fade <= 0 || p.y > this.h + 40) { this.parts.splice(i, 1); continue; }
ctx.globalAlpha = Math.max(0, fade);
ctx.fillStyle = p.color;
ctx.save(); ctx.translate(p.x, p.y); ctx.rotate(p.rot);
if (p.shape === 'rect') ctx.fillRect(-p.r, -p.r / 2, p.r * 2, p.r);
else if (p.shape === 'coin') {
ctx.shadowBlur = 8; ctx.shadowColor = '#ffce53';
ctx.beginPath(); ctx.ellipse(0, 0, p.r * Math.abs(Math.cos(p.rot)) + 1, p.r, 0, 0, 7); ctx.fill();
ctx.fillStyle = '#b9791a'; ctx.beginPath(); ctx.ellipse(0, 0, p.r * 0.4, p.r * 0.5, 0, 0, 7); ctx.fill();
} else { ctx.beginPath(); ctx.arc(0, 0, p.r, 0, 7); ctx.fill(); }
ctx.restore();
}
ctx.globalAlpha = 1; ctx.shadowBlur = 0;
if (this.parts.length || this.ambient.length) requestAnimationFrame(() => this._loop());
else this.running = false;
}
}