dopaminejs 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dopamine.js +62 -46
- package/dist/dopamine.umd.cjs +1 -1
- package/package.json +1 -1
- package/src/core/DopamineKernel.js +8 -1
- package/src/core/Game.js +1 -0
- package/src/core/GameObject.js +17 -1
- package/src/core/PluginRegistry.js +2 -2
- package/src/core/Scene.js +15 -18
- package/src/dopamine/effects/WebGLParticleSystem.js +0 -3
- package/src/dopamine/index.js +0 -1
- package/src/renderer/Renderer.js +17 -9
package/dist/dopamine.js
CHANGED
|
@@ -280,7 +280,7 @@ class P {
|
|
|
280
280
|
this.storage.removeItem(this.prefix + t);
|
|
281
281
|
}
|
|
282
282
|
}
|
|
283
|
-
class
|
|
283
|
+
class C {
|
|
284
284
|
constructor(t) {
|
|
285
285
|
this.particleSystem = t, this.container = null, this.xpBar = null, this.levelDisplay = null, this.streakDisplay = null, this.init();
|
|
286
286
|
}
|
|
@@ -430,7 +430,7 @@ class T {
|
|
|
430
430
|
`, document.body.appendChild(e);
|
|
431
431
|
}
|
|
432
432
|
}
|
|
433
|
-
class
|
|
433
|
+
class T {
|
|
434
434
|
constructor(t = {}) {
|
|
435
435
|
this.container = t.container ? typeof t.container == "string" ? document.querySelector(t.container) : t.container : document.body, this.canvasId = t.canvasId || "dopamine-particle-canvas", this.canvas = document.getElementById(this.canvasId), this.canvas || (this.canvas = document.createElement("canvas"), this.canvas.id = this.canvasId, this.canvas.style.pointerEvents = "none", this.canvas.style.zIndex = t.zIndex || "9999", this.container === document.body ? (this.canvas.style.position = "fixed", this.canvas.style.top = "0", this.canvas.style.left = "0") : (this.canvas.style.position = "absolute", this.canvas.style.top = "0", this.canvas.style.left = "0", window.getComputedStyle(this.container).position === "static" && (this.container.style.position = "relative")), this.container.appendChild(this.canvas)), this.ctx = this.canvas.getContext("2d"), this.particles = [], this.pool = [], this.sprites = /* @__PURE__ */ new Map(), this.customEffects = /* @__PURE__ */ new Map(), this.isAnimating = !1, this._resize(), window.ResizeObserver && this.container !== document.body ? new ResizeObserver(() => this._resize()).observe(this.container) : window.addEventListener("resize", () => this._resize());
|
|
436
436
|
}
|
|
@@ -481,8 +481,8 @@ class C {
|
|
|
481
481
|
size: f = 5
|
|
482
482
|
} = t;
|
|
483
483
|
for (let v = 0; v < i; v++) {
|
|
484
|
-
const l = this._getParticle(),
|
|
485
|
-
l.x = e, l.y = s, l.vx = Math.cos(
|
|
484
|
+
const l = this._getParticle(), w = m + (Math.random() - 0.5) * u, x = Math.random() * r;
|
|
485
|
+
l.x = e, l.y = s, l.vx = Math.cos(w) * x, l.vy = Math.sin(w) * x, l.life = h, l.decay = o * (0.8 + Math.random() * 0.4), l.gravity = n, l.color = Array.isArray(c) ? c[Math.floor(Math.random() * c.length)] : c, l.size = f * (0.8 + Math.random() * 0.4), l.sprite = d, l.rotation = Math.random() * Math.PI * 2, l.rotationSpeed = (Math.random() - 0.5) * 0.2, this.particles.push(l);
|
|
486
486
|
}
|
|
487
487
|
this._startAnimation();
|
|
488
488
|
}
|
|
@@ -701,12 +701,12 @@ class I {
|
|
|
701
701
|
this.playTone(200, 0.2, "sawtooth", 0.3);
|
|
702
702
|
}
|
|
703
703
|
}
|
|
704
|
-
class
|
|
704
|
+
class B {
|
|
705
705
|
constructor(t = {}) {
|
|
706
|
-
this.config = t, this.dataService = new P(t.data || {}), this.rewardSystem = new E(this.dataService, t.rewards || {}), this.soundManager = new I(t.sound || {}), this.particleSystem = new
|
|
706
|
+
this.config = t, this.dataService = new P(t.data || {}), this.rewardSystem = new E(this.dataService, t.rewards || {}), this.soundManager = new I(t.sound || {}), this.particleSystem = new T(t.particles || {}), this.gameUI = new C(this.particleSystem), this._bindEvents();
|
|
707
707
|
}
|
|
708
708
|
async init() {
|
|
709
|
-
return await this.rewardSystem.init(),
|
|
709
|
+
return await this.rewardSystem.init(), {
|
|
710
710
|
rewardSystem: this.rewardSystem,
|
|
711
711
|
gameUI: this.gameUI,
|
|
712
712
|
particleSystem: this.particleSystem,
|
|
@@ -979,7 +979,7 @@ class A {
|
|
|
979
979
|
t.init(this.kernel), this.kernel.events.emit("plugin_loaded", {
|
|
980
980
|
name: t.name,
|
|
981
981
|
version: t.version
|
|
982
|
-
})
|
|
982
|
+
});
|
|
983
983
|
} catch (e) {
|
|
984
984
|
throw console.error(`[PluginRegistry] Failed to initialize plugin "${t.name}":`, e), this._plugins.delete(t.name), this._loadOrder.pop(), e;
|
|
985
985
|
}
|
|
@@ -1004,7 +1004,7 @@ class A {
|
|
|
1004
1004
|
await t.init(this.kernel), this.kernel.events.emit("plugin_loaded", {
|
|
1005
1005
|
name: t.name,
|
|
1006
1006
|
version: t.version
|
|
1007
|
-
})
|
|
1007
|
+
});
|
|
1008
1008
|
} catch (e) {
|
|
1009
1009
|
throw console.error(`[PluginRegistry] Failed to initialize plugin "${t.name}":`, e), this._plugins.delete(t.name), this._loadOrder.pop(), e;
|
|
1010
1010
|
}
|
|
@@ -1069,7 +1069,7 @@ class A {
|
|
|
1069
1069
|
}
|
|
1070
1070
|
class D {
|
|
1071
1071
|
constructor(t = {}) {
|
|
1072
|
-
this.width = t.width || 800, this.height = t.height || 600, this.backgroundColor = t.backgroundColor || "#000000", this.canvas =
|
|
1072
|
+
this.width = t.width || 800, this.height = t.height || 600, this.backgroundColor = t.backgroundColor || "#000000", t.canvas ? (this.canvas = t.canvas, this.canvas.width = this.width, this.canvas.height = this.height) : (this.canvas = document.createElement("canvas"), this.canvas.width = this.width, this.canvas.height = this.height, (t.parent ? typeof t.parent == "string" ? document.querySelector(t.parent) : t.parent : document.body).appendChild(this.canvas)), this.ctx = this.canvas.getContext("2d");
|
|
1073
1073
|
}
|
|
1074
1074
|
/**
|
|
1075
1075
|
* Clear the canvas.
|
|
@@ -1153,7 +1153,7 @@ class y {
|
|
|
1153
1153
|
render(t) {
|
|
1154
1154
|
}
|
|
1155
1155
|
}
|
|
1156
|
-
class
|
|
1156
|
+
class G extends y {
|
|
1157
1157
|
constructor(t = "box", e = 50, s = 50, i = 25) {
|
|
1158
1158
|
super(), this.type = t, this.width = e, this.height = s, this.radius = i, this.tag = null;
|
|
1159
1159
|
}
|
|
@@ -1264,7 +1264,7 @@ class _ {
|
|
|
1264
1264
|
setGravity(t, e) {
|
|
1265
1265
|
}
|
|
1266
1266
|
}
|
|
1267
|
-
const
|
|
1267
|
+
const $ = new _();
|
|
1268
1268
|
console.warn("[DopamineJS] GlobalPhysics is deprecated. Use kernel.physics instead.");
|
|
1269
1269
|
class k {
|
|
1270
1270
|
constructor() {
|
|
@@ -1348,7 +1348,15 @@ class U {
|
|
|
1348
1348
|
_registerCoreSystems(t) {
|
|
1349
1349
|
this.systems.register("ticker", new L(), {
|
|
1350
1350
|
priority: 100
|
|
1351
|
-
})
|
|
1351
|
+
});
|
|
1352
|
+
const e = {
|
|
1353
|
+
width: t.width,
|
|
1354
|
+
height: t.height,
|
|
1355
|
+
backgroundColor: t.backgroundColor,
|
|
1356
|
+
canvas: t.canvas,
|
|
1357
|
+
...t.renderer
|
|
1358
|
+
};
|
|
1359
|
+
this.systems.register("renderer", new D(e), {
|
|
1352
1360
|
priority: 90
|
|
1353
1361
|
}), this.systems.register("input", new k(), {
|
|
1354
1362
|
priority: 80
|
|
@@ -1587,36 +1595,26 @@ const X = {
|
|
|
1587
1595
|
starBurst(a, t, e) {
|
|
1588
1596
|
}
|
|
1589
1597
|
};
|
|
1590
|
-
class
|
|
1598
|
+
class W {
|
|
1591
1599
|
constructor() {
|
|
1592
|
-
this.
|
|
1600
|
+
this.gameObjects = [], this.kernel = null;
|
|
1593
1601
|
}
|
|
1594
1602
|
/**
|
|
1595
1603
|
* Called when the scene is added to the Game.
|
|
1596
1604
|
*/
|
|
1597
1605
|
onEnter() {
|
|
1598
1606
|
}
|
|
1599
|
-
onExit() {
|
|
1600
|
-
}
|
|
1601
1607
|
/**
|
|
1602
|
-
*
|
|
1603
|
-
* @param {number} dt
|
|
1608
|
+
* Called when the scene is removed from the Game.
|
|
1604
1609
|
*/
|
|
1605
|
-
|
|
1606
|
-
for (const e of this.children)
|
|
1607
|
-
e.update && e.update(t);
|
|
1610
|
+
onExit() {
|
|
1608
1611
|
}
|
|
1609
1612
|
/**
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
/**
|
|
1615
|
-
* Add a GameObject to the scene.
|
|
1616
|
-
* @param {GameObject} gameObject
|
|
1617
|
-
*/
|
|
1613
|
+
* Add a GameObject to the scene.
|
|
1614
|
+
* @param {GameObject} gameObject
|
|
1615
|
+
*/
|
|
1618
1616
|
add(t) {
|
|
1619
|
-
return t.kernel = this.kernel, this.gameObjects.push(t), t;
|
|
1617
|
+
return this.kernel && (t.kernel = this.kernel), this.gameObjects.push(t), t;
|
|
1620
1618
|
}
|
|
1621
1619
|
/**
|
|
1622
1620
|
* Remove a GameObject from the scene.
|
|
@@ -1626,10 +1624,18 @@ class J {
|
|
|
1626
1624
|
const e = this.gameObjects.indexOf(t);
|
|
1627
1625
|
e > -1 && this.gameObjects.splice(e, 1);
|
|
1628
1626
|
}
|
|
1627
|
+
/**
|
|
1628
|
+
* Update loop for the scene.
|
|
1629
|
+
* @param {number} dt
|
|
1630
|
+
*/
|
|
1629
1631
|
update(t) {
|
|
1630
1632
|
for (const e of this.gameObjects)
|
|
1631
1633
|
e.update(t);
|
|
1632
1634
|
}
|
|
1635
|
+
/**
|
|
1636
|
+
* Render loop for the scene.
|
|
1637
|
+
* @param {CanvasRenderingContext2D} ctx
|
|
1638
|
+
*/
|
|
1633
1639
|
render(t) {
|
|
1634
1640
|
for (const e of this.gameObjects)
|
|
1635
1641
|
e.render(t);
|
|
@@ -1647,9 +1653,9 @@ class R {
|
|
|
1647
1653
|
this.currentScene && this.currentScene.onExit(), this.currentScene = t, this.currentScene.game = this.game, this.game.scene = t, t.onEnter();
|
|
1648
1654
|
}
|
|
1649
1655
|
}
|
|
1650
|
-
class
|
|
1656
|
+
class J {
|
|
1651
1657
|
constructor(t = {}) {
|
|
1652
|
-
this.config = t, this.kernel = new U(t), this.director = new R(this), this.kernel.events.on(p.Events.TICK, this._update.bind(this), 10), this.kernel.events.on(p.Events.RENDER, this._render.bind(this), 10);
|
|
1658
|
+
this.config = t, this.kernel = new U(t), this.director = new R(this), this.kernel.systems.register("director", this.director), this.kernel.events.on(p.Events.TICK, this._update.bind(this), 10), this.kernel.events.on(p.Events.RENDER, this._render.bind(this), 10);
|
|
1653
1659
|
}
|
|
1654
1660
|
/**
|
|
1655
1661
|
* Backward compatibility accessors
|
|
@@ -1700,7 +1706,17 @@ class W {
|
|
|
1700
1706
|
}
|
|
1701
1707
|
class Y {
|
|
1702
1708
|
constructor(t = 0, e = 0) {
|
|
1703
|
-
this.x = t, this.y = e, this.rotation = 0, this.scale = { x: 1, y: 1 }, this.components = [], this.children = [], this.parent = null, this.
|
|
1709
|
+
this.x = t, this.y = e, this.rotation = 0, this.scale = { x: 1, y: 1 }, this.components = [], this.children = [], this.parent = null, this._kernel = null;
|
|
1710
|
+
}
|
|
1711
|
+
get kernel() {
|
|
1712
|
+
return this._kernel;
|
|
1713
|
+
}
|
|
1714
|
+
set kernel(t) {
|
|
1715
|
+
this._kernel = t;
|
|
1716
|
+
for (const e of this.components)
|
|
1717
|
+
e.kernel = t;
|
|
1718
|
+
for (const e of this.children)
|
|
1719
|
+
e.kernel = t;
|
|
1704
1720
|
}
|
|
1705
1721
|
/**
|
|
1706
1722
|
* Add a child object.
|
|
@@ -1766,7 +1782,7 @@ class b {
|
|
|
1766
1782
|
return Math.sqrt(Math.pow(e.x - t.x, 2) + Math.pow(e.y - t.y, 2));
|
|
1767
1783
|
}
|
|
1768
1784
|
}
|
|
1769
|
-
class
|
|
1785
|
+
class j extends y {
|
|
1770
1786
|
constructor(t) {
|
|
1771
1787
|
super(), this.image = t, this.anchor = { x: 0.5, y: 0.5 }, this.width = t ? t.width : 0, this.height = t ? t.height : 0, this.frame = { x: 0, y: 0, w: this.width, h: this.height };
|
|
1772
1788
|
}
|
|
@@ -1799,7 +1815,7 @@ class V extends y {
|
|
|
1799
1815
|
super(), this.animations = {}, this.currentAnim = null, this.timer = 0, this.currentFrameIndex = 0, this.sprite = null;
|
|
1800
1816
|
}
|
|
1801
1817
|
onAttach() {
|
|
1802
|
-
this.sprite = this.gameObject.getComponent(
|
|
1818
|
+
this.sprite = this.gameObject.getComponent(j), this.sprite || console.warn("Animator attached to GameObject without a Sprite component.");
|
|
1803
1819
|
}
|
|
1804
1820
|
addAnimation(t, e, s = 10, i = !0) {
|
|
1805
1821
|
this.animations[t] = { frames: e, fps: s, loop: i };
|
|
@@ -1842,12 +1858,12 @@ class Q {
|
|
|
1842
1858
|
const n = r.getContext("2d");
|
|
1843
1859
|
for (let o = 0; o < 4; o++) {
|
|
1844
1860
|
const h = o * 64, c = 0, d = h + 64 / 2, u = c + 64 / 2, m = o % 2 === 0 ? 0 : -2, f = o === 1 ? 5 : o === 3 ? -5 : 0;
|
|
1845
|
-
n.fillStyle = t, n.beginPath(), n.arc(d, u + m, 20, 0, Math.PI * 2), n.fill(), n.fillStyle = e, n.beginPath(), n.arc(d - 15, u + m + f, 8, 0, Math.PI * 2), n.arc(d + 15, u + m - f, 8, 0, Math.PI * 2), n.fill(), n.fillStyle =
|
|
1861
|
+
n.fillStyle = t, n.beginPath(), n.arc(d, u + m, 20, 0, Math.PI * 2), n.fill(), n.fillStyle = e, n.beginPath(), n.arc(d - 15, u + m + f, 8, 0, Math.PI * 2), n.arc(d + 15, u + m - f, 8, 0, Math.PI * 2), n.fill(), n.fillStyle = z(t), n.beginPath(), n.arc(d, u + m, 15, 0, Math.PI * 2), n.fill(), e === "#333" && (n.fillStyle = "#000", n.fillRect(d + 10, u + m - 5, 25, 6));
|
|
1846
1862
|
}
|
|
1847
1863
|
return r;
|
|
1848
1864
|
}
|
|
1849
1865
|
}
|
|
1850
|
-
function
|
|
1866
|
+
function z(a, t) {
|
|
1851
1867
|
return a;
|
|
1852
1868
|
}
|
|
1853
1869
|
class Z extends y {
|
|
@@ -1910,18 +1926,18 @@ class tt extends y {
|
|
|
1910
1926
|
}
|
|
1911
1927
|
export {
|
|
1912
1928
|
V as Animator,
|
|
1913
|
-
|
|
1929
|
+
G as Collider,
|
|
1914
1930
|
y as Component,
|
|
1915
1931
|
P as DataService,
|
|
1916
1932
|
R as Director,
|
|
1917
1933
|
U as DopamineKernel,
|
|
1918
1934
|
p as EventBus,
|
|
1919
|
-
|
|
1935
|
+
J as Game,
|
|
1920
1936
|
Y as GameObject,
|
|
1921
|
-
|
|
1937
|
+
C as GameUI,
|
|
1922
1938
|
F as GlobalInput,
|
|
1923
1939
|
N as GlobalLoader,
|
|
1924
|
-
|
|
1940
|
+
$ as GlobalPhysics,
|
|
1925
1941
|
H as IAudioSystem,
|
|
1926
1942
|
q as IParticleSystem,
|
|
1927
1943
|
X as IPhysicsSystem,
|
|
@@ -1929,19 +1945,19 @@ export {
|
|
|
1929
1945
|
k as Input,
|
|
1930
1946
|
S as Loader,
|
|
1931
1947
|
Z as ParticleEmitter,
|
|
1932
|
-
|
|
1948
|
+
T as ParticleSystem,
|
|
1933
1949
|
_ as Physics,
|
|
1934
1950
|
A as PluginRegistry,
|
|
1935
1951
|
D as Renderer,
|
|
1936
1952
|
E as RewardSystem,
|
|
1937
|
-
|
|
1953
|
+
W as Scene,
|
|
1938
1954
|
tt as ScreenShake,
|
|
1939
1955
|
I as SoundManager,
|
|
1940
|
-
|
|
1956
|
+
j as Sprite,
|
|
1941
1957
|
K as System,
|
|
1942
1958
|
O as SystemRegistry,
|
|
1943
1959
|
Q as TextureGenerator,
|
|
1944
1960
|
L as Ticker,
|
|
1945
1961
|
b as Vector2,
|
|
1946
|
-
|
|
1962
|
+
B as default
|
|
1947
1963
|
};
|
package/dist/dopamine.umd.cjs
CHANGED
|
@@ -42,4 +42,4 @@
|
|
|
42
42
|
</div>
|
|
43
43
|
<button class="btn" onclick="location.reload()">Play Again</button>
|
|
44
44
|
<button class="btn" onclick="window.location.href='index.html'" style="margin-top: 10px; background: #543847;">Exit</button>
|
|
45
|
-
`,document.body.appendChild(t)}}class E{constructor(e={}){this.container=e.container?typeof e.container=="string"?document.querySelector(e.container):e.container:document.body,this.canvasId=e.canvasId||"dopamine-particle-canvas",this.canvas=document.getElementById(this.canvasId),this.canvas||(this.canvas=document.createElement("canvas"),this.canvas.id=this.canvasId,this.canvas.style.pointerEvents="none",this.canvas.style.zIndex=e.zIndex||"9999",this.container===document.body?(this.canvas.style.position="fixed",this.canvas.style.top="0",this.canvas.style.left="0"):(this.canvas.style.position="absolute",this.canvas.style.top="0",this.canvas.style.left="0",window.getComputedStyle(this.container).position==="static"&&(this.container.style.position="relative")),this.container.appendChild(this.canvas)),this.ctx=this.canvas.getContext("2d"),this.particles=[],this.pool=[],this.sprites=new Map,this.customEffects=new Map,this.isAnimating=!1,this._resize(),window.ResizeObserver&&this.container!==document.body?new ResizeObserver(()=>this._resize()).observe(this.container):window.addEventListener("resize",()=>this._resize())}_resize(){this.container===document.body?(this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight):(this.canvas.width=this.container.clientWidth,this.canvas.height=this.container.clientHeight)}registerSprite(e,t){const s=new Image;s.src=t,this.sprites.set(e,s)}registerEffect(e,t){this.customEffects.set(e,t)}play(e,t,s,...i){const n=this.customEffects.get(e);n?n(t,s,...i):console.warn(`[DopamineJS] Effect '${e}' not found.`)}emit(e){const{x:t,y:s,count:i=10,speed:n=5,gravity:r=.1,decay:h=.02,life:c=1,color:l="#ffd700",sprite:u=null,spread:y=Math.PI*2,angle:p=0,size:w=5}=e;for(let R=0;R<i;R++){const d=this._getParticle(),j=p+(Math.random()-.5)*y,z=Math.random()*n;d.x=t,d.y=s,d.vx=Math.cos(j)*z,d.vy=Math.sin(j)*z,d.life=c,d.decay=h*(.8+Math.random()*.4),d.gravity=r,d.color=Array.isArray(l)?l[Math.floor(Math.random()*l.length)]:l,d.size=w*(.8+Math.random()*.4),d.sprite=u,d.rotation=Math.random()*Math.PI*2,d.rotationSpeed=(Math.random()-.5)*.2,this.particles.push(d)}this._startAnimation()}_getParticle(){return this.pool.length>0?this.pool.pop():{}}_recycleParticle(e){this.pool.push(e)}confetti(e,t,s=50){const i=["#ff6b6b","#4ecdc4","#45b7d1","#f7dc6f","#c06c84","#6c5ce7"];this.emit({x:e,y:t,count:s,color:i,speed:10,gravity:.3,decay:.015,size:8,spread:Math.PI*2})}coinShower(e,t,s=10){this.emit({x:e,y:t,count:s,color:"#ffd700",speed:4,gravity:.4,decay:.012,size:12,angle:-Math.PI/2,spread:Math.PI/2})}sparkle(e,t,s=20,i="#ffd700"){this.emit({x:e,y:t,count:s,color:i,speed:3,gravity:-.05,decay:.03,size:3})}fire(e,t,s=15){const i=["#ff6b00","#ff8800","#ffaa00","#ff4400"];this.emit({x:e,y:t,count:s,color:i,speed:3,gravity:-.2,decay:.04,size:5,angle:-Math.PI/2,spread:Math.PI/4})}starBurst(e,t,s=8){for(let i=0;i<s;i++){const n=this._getParticle(),r=Math.PI*2/s*i,h=4;n.x=e,n.y=t,n.vx=Math.cos(r)*h,n.vy=Math.sin(r)*h,n.life=1,n.decay=.03,n.gravity=0,n.color="#ffffff",n.size=15,n.sprite=null,n.type="star",n.rotation=r,n.rotationSpeed=0,this.particles.push(n)}this._startAnimation()}_startAnimation(){this.isAnimating||(this.isAnimating=!0,this._animate())}_animate(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);for(let e=this.particles.length-1;e>=0;e--){const t=this.particles[e];if(t.vy+=t.gravity,t.x+=t.vx,t.y+=t.vy,t.life-=t.decay,t.rotationSpeed&&(t.rotation+=t.rotationSpeed),t.life<=0){this._recycleParticle(t),this.particles.splice(e,1);continue}if(this.ctx.save(),this.ctx.globalAlpha=t.life,this.ctx.translate(t.x,t.y),this.ctx.rotate(t.rotation),t.sprite&&this.sprites.has(t.sprite)){const s=this.sprites.get(t.sprite);s.complete&&this.ctx.drawImage(s,-t.size/2,-t.size/2,t.size,t.size)}else t.type==="star"?(this.ctx.fillStyle=t.color,this._drawStarPath(0,0,5,t.size,t.size/2),this.ctx.fill()):(this.ctx.fillStyle=t.color,this.ctx.beginPath(),this.ctx.arc(0,0,t.size,0,Math.PI*2),this.ctx.fill());this.ctx.restore()}this.particles.length>0?requestAnimationFrame(()=>this._animate()):this.isAnimating=!1}_drawStarPath(e,t,s,i,n){let r=Math.PI/2*3,h=e,c=t;const l=Math.PI/s;this.ctx.beginPath(),this.ctx.moveTo(e,t-i);for(let u=0;u<s;u++)h=e+Math.cos(r)*i,c=t+Math.sin(r)*i,this.ctx.lineTo(h,c),r+=l,h=e+Math.cos(r)*n,c=t+Math.sin(r)*n,this.ctx.lineTo(h,c),r+=l;this.ctx.lineTo(e,t-i),this.ctx.closePath()}clear(){this.particles.forEach(e=>this._recycleParticle(e)),this.particles=[],this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}}class T{constructor(e={}){this.audioContext=null,this.storageKey=e.storageKey||"dopamineSoundsMuted",this.muted=localStorage.getItem(this.storageKey)==="true",this.assets=new Map,this.customSounds=e.customSounds||{},Object.keys(this.customSounds).length>0&&this.preloadSounds(this.customSounds)}initAudio(){if(!this.audioContext){const e=window.AudioContext||window.webkitAudioContext;this.audioContext=new e}this.audioContext.state==="suspended"&&this.audioContext.resume()}toggleMute(){return this.muted=!this.muted,localStorage.setItem(this.storageKey,this.muted),this.muted}registerSound(e,t){this.customSounds[e]=t,this.audioContext&&this.loadSound(e,t)}async preloadSounds(e){const t=Object.entries(e).map(([s,i])=>this.loadSound(s,i));await Promise.allSettled(t)}async loadSound(e,t){try{if(!this.audioContext)return;const i=await(await fetch(t)).arrayBuffer(),n=await this.audioContext.decodeAudioData(i);this.assets.set(e,n)}catch(s){console.warn(`[DopamineJS] Failed to load sound '${e}':`,s)}}async play(e){if(this.muted)return;if(this.initAudio(),this.assets.has(e)){this._playBuffer(this.assets.get(e));return}if(this.customSounds[e]&&!this.assets.has(e)&&(await this.loadSound(e,this.customSounds[e]),this.assets.has(e))){this._playBuffer(this.assets.get(e));return}const t={jump:()=>this.playJump(!0),score:()=>this.playScore(!0),success:()=>this.playSuccess(!0),click:()=>this.playClick(!0),error:()=>this.playError(!0),gameover:()=>this.playGameOver(!0)};t[e]&&t[e]()}_playBuffer(e){const t=this.audioContext.createBufferSource();t.buffer=e,t.connect(this.audioContext.destination),t.start(0)}playTone(e,t,s="sine",i=.3){if(this.muted)return;this.initAudio();const n=this.audioContext.createOscillator(),r=this.audioContext.createGain();n.connect(r),r.connect(this.audioContext.destination),n.frequency.value=e,n.type=s,r.gain.setValueAtTime(i,this.audioContext.currentTime),r.gain.exponentialRampToValueAtTime(.01,this.audioContext.currentTime+t),n.start(this.audioContext.currentTime),n.stop(this.audioContext.currentTime+t)}playJump(e=!1){if(!e&&this.assets.has("jump"))return this.play("jump");this.playTone(400,.1,"square",.2)}playScore(e=!1){if(!e&&this.assets.has("score"))return this.play("score");this.playTone(800,.15,"sine",.25),setTimeout(()=>this.playTone(1e3,.15,"sine",.25),50)}playGameOver(e=!1){if(!e&&this.assets.has("gameover"))return this.play("gameover");this.playTone(300,.2,"sawtooth",.3),setTimeout(()=>this.playTone(200,.2,"sawtooth",.3),100),setTimeout(()=>this.playTone(150,.3,"sawtooth",.3),200)}playClick(e=!1){if(!e&&this.assets.has("click"))return this.play("click");this.playTone(600,.05,"sine",.1)}playSuccess(e=!1){if(!e&&this.assets.has("success"))return this.play("success");this.playTone(600,.1,"sine",.2),setTimeout(()=>this.playTone(800,.2,"sine",.2),100)}playError(e=!1){if(!e&&this.assets.has("error"))return this.play("error");this.playTone(200,.2,"sawtooth",.3)}}class G{constructor(e={}){this.config=e,this.dataService=new M(e.data||{}),this.rewardSystem=new b(this.dataService,e.rewards||{}),this.soundManager=new T(e.sound||{}),this.particleSystem=new E(e.particles||{}),this.gameUI=new P(this.particleSystem),this._bindEvents()}async init(){return await this.rewardSystem.init(),console.log("DopamineJS Initialized 🚀"),{rewardSystem:this.rewardSystem,gameUI:this.gameUI,particleSystem:this.particleSystem,soundManager:this.soundManager}}_bindEvents(){this.rewardSystem.on("xp_gained",e=>{const{total:t,needed:s}=this.rewardSystem.getXPForNextLevel();this.gameUI.updateXP(this.rewardSystem.player.xp,s,t),e.xpGained>0}),this.rewardSystem.on("level_up",e=>{this.gameUI.updateLevel(e.newLevel),this.gameUI.showLevelUp(e.oldLevel,e.newLevel)}),this.rewardSystem.on("achievement_unlocked",e=>{this.gameUI.showAchievement(e)}),this.rewardSystem.on("new_high_score",e=>{this.gameUI.showNotification(`New High Score: ${e.score}!`,"legendary"),this.soundManager.playSuccess()})}}class m{constructor(){this._listeners=new Map,this._onceListeners=new Map,this._sortedCache=new Map}on(e,t,s=0){return this._listeners.has(e)||this._listeners.set(e,new Set),this._listeners.get(e).add({callback:t,priority:s}),this._sortedCache.delete(e),this}once(e,t){return this._onceListeners.has(e)||this._onceListeners.set(e,new Set),this._onceListeners.get(e).add(t),this}off(e,t){const s=this._listeners.get(e);if(s){for(const n of s)if(n.callback===t){s.delete(n),this._sortedCache.delete(e);break}}const i=this._onceListeners.get(e);return i&&i.delete(t),this}emit(e,t){const s=this._getSortedListeners(e);for(let n=0;n<s.length;n++)s[n].callback(t);const i=this._onceListeners.get(e);if(i&&i.size>0){for(const n of i)n(t);i.clear()}}_getSortedListeners(e){if(this._sortedCache.has(e))return this._sortedCache.get(e);const t=this._listeners.get(e);if(!t||t.size===0)return[];const s=Array.from(t).sort((i,n)=>n.priority-i.priority);return this._sortedCache.set(e,s),s}clear(e){e?(this._listeners.delete(e),this._onceListeners.delete(e),this._sortedCache.delete(e)):(this._listeners.clear(),this._onceListeners.clear(),this._sortedCache.clear())}hasListeners(e){const t=this._listeners.get(e),s=this._onceListeners.get(e);return t&&t.size>0||s&&s.size>0}}m.Events={TICK:"tick",FIXED_UPDATE:"fixed_update",RENDER:"render",COLLISION_ENTER:"collision_enter",COLLISION_EXIT:"collision_exit",XP_GAINED:"xp_gained",LEVEL_UP:"level_up",ACHIEVEMENT_UNLOCKED:"achievement_unlocked",NEW_HIGH_SCORE:"new_high_score",STREAK_UPDATED:"streak_updated",SYSTEM_REGISTERED:"system_registered",SYSTEM_UNREGISTERED:"system_unregistered",PLUGIN_LOADED:"plugin_loaded",PLUGIN_UNLOADED:"plugin_unloaded"};class I{constructor(e){this.kernel=e,this._systems=new Map,this._updateOrder=[],this._fixedUpdateOrder=[],this._needsRecompute=!1}register(e,t,{priority:s=0,dependencies:i=[]}={}){this._systems.has(e)&&(console.warn(`[SystemRegistry] System "${e}" already registered. Replacing.`),this.unregister(e));for(const n of i)this._systems.has(n)||console.warn(`[SystemRegistry] Dependency "${n}" not found for system "${e}"`);return this._systems.set(e,{system:t,priority:s,dependencies:i}),t.init&&t.init(this.kernel),this._needsRecompute=!0,this.kernel.events.emit("system_registered",{name:e,system:t}),this}get(e){const t=this._systems.get(e);return t?t.system:void 0}has(e){return this._systems.has(e)}unregister(e){const t=this._systems.get(e);return t?(t.system.destroy&&t.system.destroy(),this._systems.delete(e),this._needsRecompute=!0,this.kernel.events.emit("system_unregistered",{name:e}),!0):!1}update(e){this._needsRecompute&&this._recomputeUpdateOrder();for(let t=0;t<this._updateOrder.length;t++){const s=this._updateOrder[t];s.update&&s.update(e)}}fixedUpdate(e){this._needsRecompute&&this._recomputeUpdateOrder();for(let t=0;t<this._fixedUpdateOrder.length;t++){const s=this._fixedUpdateOrder[t];s.fixedUpdate&&s.fixedUpdate(e)}}_recomputeUpdateOrder(){const e=Array.from(this._systems.entries()),t=new Map,s=new Map;for(const[r,h]of e)t.set(r,h.dependencies),s.set(r,0);for(const[r,h]of t)for(const c of h)s.has(c)&&s.set(r,s.get(r)+1);const i=[],n=[];for(const[r,h]of s)h===0&&i.push(r);for(;i.length>0;){i.sort((h,c)=>{const l=this._systems.get(h).priority;return this._systems.get(c).priority-l});const r=i.shift();n.push(r);for(const[h,c]of t)if(c.includes(r)){const l=s.get(h)-1;s.set(h,l),l===0&&i.push(h)}}n.length!==e.length&&(console.error("[SystemRegistry] Circular dependency detected in systems!"),n.length=0,n.push(...e.map(([r])=>r).sort((r,h)=>this._systems.get(h).priority-this._systems.get(r).priority))),this._updateOrder=n.map(r=>this._systems.get(r).system).filter(r=>r.update),this._fixedUpdateOrder=n.map(r=>this._systems.get(r).system).filter(r=>r.fixedUpdate),this._needsRecompute=!1}getSystemNames(){return Array.from(this._systems.keys())}clear(){for(const e of this._systems.keys())this.unregister(e)}}class C{constructor(e){this.kernel=e,this._plugins=new Map,this._loadOrder=[]}use(e){if(!e.name)throw new Error("[PluginRegistry] Plugin must have a name");if(this._plugins.has(e.name))return console.warn(`[PluginRegistry] Plugin "${e.name}" already registered. Skipping.`),this;if(!e.init||typeof e.init!="function")throw new Error(`[PluginRegistry] Plugin "${e.name}" must have an init() method`);this._plugins.set(e.name,e),this._loadOrder.push(e.name);try{e.init(this.kernel),this.kernel.events.emit("plugin_loaded",{name:e.name,version:e.version}),console.log(`[PluginRegistry] Loaded plugin: ${e.name}${e.version?` v${e.version}`:""}`)}catch(t){throw console.error(`[PluginRegistry] Failed to initialize plugin "${e.name}":`,t),this._plugins.delete(e.name),this._loadOrder.pop(),t}return this}async useAsync(e){if(!e.name)throw new Error("[PluginRegistry] Plugin must have a name");if(this._plugins.has(e.name))return console.warn(`[PluginRegistry] Plugin "${e.name}" already registered. Skipping.`),this;if(!e.init||typeof e.init!="function")throw new Error(`[PluginRegistry] Plugin "${e.name}" must have an init() method`);this._plugins.set(e.name,e),this._loadOrder.push(e.name);try{await e.init(this.kernel),this.kernel.events.emit("plugin_loaded",{name:e.name,version:e.version}),console.log(`[PluginRegistry] Loaded plugin: ${e.name}${e.version?` v${e.version}`:""}`)}catch(t){throw console.error(`[PluginRegistry] Failed to initialize plugin "${e.name}":`,t),this._plugins.delete(e.name),this._loadOrder.pop(),t}return this}remove(e){const t=this._plugins.get(e);if(!t)return!1;if(t.destroy)try{t.destroy()}catch(i){console.error(`[PluginRegistry] Error destroying plugin "${e}":`,i)}this._plugins.delete(e);const s=this._loadOrder.indexOf(e);return s>-1&&this._loadOrder.splice(s,1),this.kernel.events.emit("plugin_unloaded",{name:e}),!0}get(e){return this._plugins.get(e)}has(e){return this._plugins.has(e)}getPluginNames(){return Array.from(this._plugins.keys())}getLoadOrder(){return[...this._loadOrder]}clear(){for(let e=this._loadOrder.length-1;e>=0;e--)this.remove(this._loadOrder[e])}}class O{constructor(e={}){this.width=e.width||800,this.height=e.height||600,this.backgroundColor=e.backgroundColor||"#000000",this.canvas=document.createElement("canvas"),this.canvas.width=this.width,this.canvas.height=this.height,this.ctx=this.canvas.getContext("2d"),(e.parent?typeof e.parent=="string"?document.querySelector(e.parent):e.parent:document.body).appendChild(this.canvas)}clear(){this.ctx.fillStyle=this.backgroundColor,this.ctx.fillRect(0,0,this.width,this.height)}resize(e,t){this.width=e,this.height=t,this.canvas.width=e,this.canvas.height=t}}class A{constructor(){this.running=!1,this.lastTime=0,this.callbacks=new Set,this._tick=this._tick.bind(this)}add(e){this.callbacks.add(e)}remove(e){this.callbacks.delete(e)}start(){this.running||(this.running=!0,this.lastTime=performance.now(),requestAnimationFrame(this._tick))}stop(){this.running=!1}_tick(e){if(!this.running)return;const t=(e-this.lastTime)/1e3;this.lastTime=e;const s=Math.min(t,.1);for(const i of this.callbacks)i(s);requestAnimationFrame(this._tick)}}class f{constructor(){this.gameObject=null,this.kernel=null}get physics(){var e;return(e=this.kernel)==null?void 0:e.systems.get("physics")}get input(){var e;return(e=this.kernel)==null?void 0:e.systems.get("input")}get loader(){var e;return(e=this.kernel)==null?void 0:e.systems.get("loader")}get events(){var e;return(e=this.kernel)==null?void 0:e.events}onAttach(){}onDetach(){}update(e){}render(e){}}class $ extends f{constructor(e="box",t=50,s=50,i=25){super(),this.type=e,this.width=t,this.height=s,this.radius=i,this.tag=null}onAttach(){super.onAttach(),this.physics&&this.physics.add(this)}onDetach(){super.onDetach(),this.physics&&this.physics.remove(this)}getBounds(){const e=this.gameObject;if(this.type==="box")return{left:e.x-this.width/2,right:e.x+this.width/2,top:e.y-this.height/2,bottom:e.y+this.height/2};if(this.type==="circle")return{x:e.x,y:e.y,radius:this.radius}}}class _{constructor(){this.colliders=[],this.kernel=null}init(e){this.kernel=e}fixedUpdate(e){this.step()}destroy(){this.colliders=[]}add(e){this.colliders.push(e)}remove(e){const t=this.colliders.indexOf(e);t>-1&&this.colliders.splice(t,1)}step(){for(let e=0;e<this.colliders.length;e++)for(let t=e+1;t<this.colliders.length;t++){const s=this.colliders[e],i=this.colliders[t];this._intersects(s,s.getBounds(),i,i.getBounds())&&(this._notifyCollision(s.gameObject,i.gameObject),this._notifyCollision(i.gameObject,s.gameObject))}}_notifyCollision(e,t){!e||!e.components||e.components.forEach(s=>{s.onCollisionEnter&&s.onCollisionEnter(t)})}checkOverlap(e,t){const s=[],i=e.getBounds();for(const n of this.colliders){if(n===e||t&&n.tag!==t)continue;const r=n.getBounds();this._intersects(e,i,n,r)&&s.push(n)}return s}_intersects(e,t,s,i){if(e.type==="box"&&s.type==="box")return t.left<i.right&&t.right>i.left&&t.top<i.bottom&&t.bottom>i.top;if(e.type==="circle"&&s.type==="circle"){const n=t.x-i.x,r=t.y-i.y;return Math.sqrt(n*n+r*r)<t.radius+i.radius}return!1}addBody(e){this.add(e)}removeBody(e){this.remove(e)}checkCollision(e,t){return this._intersects(e,e.getBounds(),t,t.getBounds())}raycast(e,t,s){return null}setGravity(e,t){}}const B=new _;console.warn("[DopamineJS] GlobalPhysics is deprecated. Use kernel.physics instead.");class x{constructor(){this.keys=new Map,this.mouse={x:0,y:0,buttons:new Map},this.kernel=null,this._onKeyDown=this._onKeyDown.bind(this),this._onKeyUp=this._onKeyUp.bind(this),this._onMouseMove=this._onMouseMove.bind(this),this._onMouseDown=this._onMouseDown.bind(this),this._onMouseUp=this._onMouseUp.bind(this)}init(e){this.kernel=e,window.addEventListener("keydown",this._onKeyDown),window.addEventListener("keyup",this._onKeyUp),window.addEventListener("mousemove",this._onMouseMove),window.addEventListener("mousedown",this._onMouseDown),window.addEventListener("mouseup",this._onMouseUp)}destroy(){window.removeEventListener("keydown",this._onKeyDown),window.removeEventListener("keyup",this._onKeyUp),window.removeEventListener("mousemove",this._onMouseMove),window.removeEventListener("mousedown",this._onMouseDown),window.removeEventListener("mouseup",this._onMouseUp)}_onKeyDown(e){this.keys.set(e.key,!0)}_onKeyUp(e){this.keys.set(e.key,!1)}_onMouseMove(e){this.mouse.x=e.clientX,this.mouse.y=e.clientY}_onMouseDown(e){this.mouse.buttons.set(e.button,!0)}_onMouseUp(e){this.mouse.buttons.set(e.button,!1)}isKeyDown(e){return this.keys.get(e)||!1}isMouseButtonDown(e=0){return this.mouse.buttons.get(e)||!1}}const F=new x;console.warn("[DopamineJS] GlobalInput is deprecated. Use kernel.input instead.");class S{constructor(){this.assets=new Map,this.kernel=null}init(e){this.kernel=e}destroy(){this.assets.clear()}async loadImage(e,t){return new Promise((s,i)=>{const n=new Image;n.onload=()=>{this.assets.set(e,n),s(n)},n.onerror=i,n.src=t})}get(e){return this.assets.get(e)}}const N=new S;console.warn("[DopamineJS] GlobalLoader is deprecated. Use kernel.loader instead.");class D{constructor(e={}){this.config=e,this.events=new m,this.systems=new I(this),this.plugins=new C(this),this._registerCoreSystems(e),this.fixedTimestep=e.fixedTimestep||1/60,this._accumulator=0,this._maxAccumulator=this.fixedTimestep*5}_registerCoreSystems(e){this.systems.register("ticker",new A,{priority:100}),this.systems.register("renderer",new O(e.renderer||{}),{priority:90}),this.systems.register("input",new x,{priority:80}),this.systems.register("loader",new S,{priority:70}),this.systems.register("physics",new _,{priority:60})}start(){const e=this.systems.get("ticker");e&&(e.add(this._update.bind(this)),e.start()),this.events.emit("kernel_started")}stop(){const e=this.systems.get("ticker");e&&e.stop(),this.events.emit("kernel_stopped")}_update(e){for(this.events.emit(m.Events.TICK,{dt:e}),this._accumulator+=e,this._accumulator>this._maxAccumulator&&(this._accumulator=this._maxAccumulator);this._accumulator>=this.fixedTimestep;)this.events.emit(m.Events.FIXED_UPDATE,{dt:this.fixedTimestep}),this.systems.fixedUpdate(this.fixedTimestep),this._accumulator-=this.fixedTimestep;this.systems.update(e),this.events.emit(m.Events.RENDER,{dt:e})}get physics(){return this.systems.get("physics")}get input(){return this.systems.get("input")}get loader(){return this.systems.get("loader")}get renderer(){return this.systems.get("renderer")}get ticker(){return this.systems.get("ticker")}destroy(){this.stop(),this.plugins.clear(),this.systems.clear(),this.events.clear()}}const v={init(a){},update(a){},fixedUpdate(a){},destroy(){}};class K{constructor(){this.kernel=null}init(e){this.kernel=e}update(e){}fixedUpdate(e){}destroy(){}}const X={...v,addBody(a){},removeBody(a){},checkCollision(a,e){},raycast(a,e,t){},setGravity(a,e){},step(a){}},H={...v,registerSound(a,e){},preloadSounds(a){},play(a,e){},playTone(a,e,t,s){},stop(a){},toggleMute(){},setVolume(a){}},q={...v,registerSprite(a,e){},registerEffect(a,e){},play(a,e,t,...s){},emit(a){},clear(){},confetti(a,e,t){},coinShower(a,e,t){},sparkle(a,e,t,s){},fire(a,e,t){},starBurst(a,e,t){}};class J{constructor(){this.children=[],this.game=null}onEnter(){}onExit(){}update(e){for(const t of this.children)t.update&&t.update(e)}add(e){return e.kernel=this.kernel,this.gameObjects.push(e),e}remove(e){const t=this.gameObjects.indexOf(e);t>-1&&this.gameObjects.splice(t,1)}update(e){for(const t of this.gameObjects)t.update(e)}render(e){for(const t of this.gameObjects)t.render(e)}}class L{constructor(e){this.game=e,this.currentScene=null}run(e){this.currentScene&&this.currentScene.onExit(),this.currentScene=e,this.currentScene.game=this.game,this.game.scene=e,e.onEnter()}}class W{constructor(e={}){this.config=e,this.kernel=new D(e),this.director=new L(this),this.kernel.events.on(m.Events.TICK,this._update.bind(this),10),this.kernel.events.on(m.Events.RENDER,this._render.bind(this),10)}get renderer(){return this.kernel.renderer}get ticker(){return this.kernel.ticker}get physics(){return this.kernel.physics}get input(){return this.kernel.input}start(){this.kernel.start()}stop(){this.kernel.stop()}setScene(e){e.kernel=this.kernel,this.director.run(e)}_update({dt:e}){this.director.currentScene&&this.director.currentScene.update(e)}_render({dt:e}){this.renderer.clear(),this.director.currentScene&&this.director.currentScene.render(this.renderer.ctx)}destroy(){this.kernel.destroy()}}class Y{constructor(e=0,t=0){this.x=e,this.y=t,this.rotation=0,this.scale={x:1,y:1},this.components=[],this.children=[],this.parent=null,this.kernel=null}addChild(e){return e.parent=this,e.kernel=this.kernel,this.children.push(e),e}addComponent(e){return e.gameObject=this,e.kernel=this.kernel,this.components.push(e),e.onAttach(),e}getComponent(e){return this.components.find(t=>t instanceof e)}update(e){for(const t of this.components)t.update&&t.update(e);for(const t of this.children)t.update(e)}render(e){e.save(),e.translate(this.x,this.y),e.rotate(this.rotation),e.scale(this.scale.x,this.scale.y);for(const t of this.components)t.render&&t.render(e);for(const t of this.children)t.render(e);e.restore()}}class k{constructor(e=0,t=0){this.x=e,this.y=t}add(e){return this.x+=e.x,this.y+=e.y,this}sub(e){return this.x-=e.x,this.y-=e.y,this}scale(e){return this.x*=e,this.y*=e,this}distance(e){const t=this.x-e.x,s=this.y-e.y;return Math.sqrt(t*t+s*s)}normalize(){const e=Math.sqrt(this.x*this.x+this.y*this.y);return e>0&&(this.x/=e,this.y/=e),this}clone(){return new k(this.x,this.y)}static distance(e,t){return Math.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2))}}class U extends f{constructor(e){super(),this.image=e,this.anchor={x:.5,y:.5},this.width=e?e.width:0,this.height=e?e.height:0,this.frame={x:0,y:0,w:this.width,h:this.height}}setFrame(e,t,s,i){this.frame={x:e,y:t,w:s,h:i},this.width=s,this.height=i}setTexture(e){this.image=e,e&&this.setFrame(0,0,e.width,e.height)}render(e){if(!this.image)return;const t=this.frame.w,s=this.frame.h,i=-t*this.anchor.x,n=-s*this.anchor.y;e.drawImage(this.image,this.frame.x,this.frame.y,t,s,i,n,t,s)}}class V extends f{constructor(){super(),this.animations={},this.currentAnim=null,this.timer=0,this.currentFrameIndex=0,this.sprite=null}onAttach(){this.sprite=this.gameObject.getComponent(U),this.sprite||console.warn("Animator attached to GameObject without a Sprite component.")}addAnimation(e,t,s=10,i=!0){this.animations[e]={frames:t,fps:s,loop:i}}play(e){this.currentAnim&&this.currentAnim.name===e||this.animations[e]&&(this.currentAnim={name:e,...this.animations[e]},this.currentFrameIndex=0,this.timer=0,this._updateFrame())}update(e){if(!this.currentAnim||!this.sprite)return;this.timer+=e;const t=1/this.currentAnim.fps;this.timer>=t&&(this.timer-=t,this.currentFrameIndex++,this.currentFrameIndex>=this.currentAnim.frames.length&&(this.currentAnim.loop?this.currentFrameIndex=0:this.currentFrameIndex=this.currentAnim.frames.length-1),this._updateFrame())}_updateFrame(){const e=this.currentAnim.frames[this.currentFrameIndex];this.sprite.setFrame(e.x,e.y,e.w,e.h)}}class Q{static createGround(e,t,s="#333"){const i=document.createElement("canvas");i.width=e,i.height=t;const n=i.getContext("2d");n.fillStyle=s,n.fillRect(0,0,e,t);for(let r=0;r<1e3;r++){n.fillStyle=Math.random()>.5?"#444":"#222";const h=Math.random()*4+2;n.fillRect(Math.random()*e,Math.random()*t,h,h)}n.strokeStyle="rgba(255,255,255,0.05)",n.lineWidth=2,n.beginPath();for(let r=0;r<=e;r+=64)n.moveTo(r,0),n.lineTo(r,t);for(let r=0;r<=t;r+=64)n.moveTo(0,r),n.lineTo(e,r);return n.stroke(),i}static createCharacterSheet(e,t){const n=document.createElement("canvas");n.width=64*4,n.height=64;const r=n.getContext("2d");for(let h=0;h<4;h++){const c=h*64,l=0,u=c+64/2,y=l+64/2,p=h%2===0?0:-2,w=h===1?5:h===3?-5:0;r.fillStyle=e,r.beginPath(),r.arc(u,y+p,20,0,Math.PI*2),r.fill(),r.fillStyle=t,r.beginPath(),r.arc(u-15,y+p+w,8,0,Math.PI*2),r.arc(u+15,y+p-w,8,0,Math.PI*2),r.fill(),r.fillStyle=Z(e),r.beginPath(),r.arc(u,y+p,15,0,Math.PI*2),r.fill(),t==="#333"&&(r.fillStyle="#000",r.fillRect(u+10,y+p-5,25,6))}return n}}function Z(a,e){return a}class ee extends f{constructor(e){super(),this.system=e}play(e,t={}){const s=this.gameObject.x,i=this.gameObject.y;switch(e){case"confetti":this.system.confetti(s,i,t.count);break;case"fire":this.system.fire(s,i,t.count);break;case"sparkle":this.system.sparkle(s,i,t.count,t.color);break;case"blood":this.system.emit({x:s,y:i,count:10,color:["#8a0303","#ff0000"],speed:4,gravity:.1,decay:.05});break;default:this.system.emit({x:s,y:i,...t})}}}class te extends f{constructor(){super(),this.intensity=0,this.duration=0,this.timer=0,this.originalPos={x:0,y:0},this.isShaking=!1}shake(e=5,t=.2){this.intensity=e,this.duration=t,this.timer=0,this.isShaking=!0,this.timer===0&&(this.originalPos.x=this.gameObject.x,this.originalPos.y=this.gameObject.y)}update(e){if(!this.isShaking)return;if(this.timer+=e,this.timer>=this.duration){this.isShaking=!1,this.gameObject.x=this.originalPos.x,this.gameObject.y=this.originalPos.y;return}const t=(Math.random()-.5)*2*this.intensity,s=(Math.random()-.5)*2*this.intensity;this.gameObject.x=this.originalPos.x+t,this.gameObject.y=this.originalPos.y+s}}o.Animator=V,o.Collider=$,o.Component=f,o.DataService=M,o.Director=L,o.DopamineKernel=D,o.EventBus=m,o.Game=W,o.GameObject=Y,o.GameUI=P,o.GlobalInput=F,o.GlobalLoader=N,o.GlobalPhysics=B,o.IAudioSystem=H,o.IParticleSystem=q,o.IPhysicsSystem=X,o.ISystem=v,o.Input=x,o.Loader=S,o.ParticleEmitter=ee,o.ParticleSystem=E,o.Physics=_,o.PluginRegistry=C,o.Renderer=O,o.RewardSystem=b,o.Scene=J,o.ScreenShake=te,o.SoundManager=T,o.Sprite=U,o.System=K,o.SystemRegistry=I,o.TextureGenerator=Q,o.Ticker=A,o.Vector2=k,o.default=G,Object.defineProperties(o,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
|
45
|
+
`,document.body.appendChild(t)}}class E{constructor(e={}){this.container=e.container?typeof e.container=="string"?document.querySelector(e.container):e.container:document.body,this.canvasId=e.canvasId||"dopamine-particle-canvas",this.canvas=document.getElementById(this.canvasId),this.canvas||(this.canvas=document.createElement("canvas"),this.canvas.id=this.canvasId,this.canvas.style.pointerEvents="none",this.canvas.style.zIndex=e.zIndex||"9999",this.container===document.body?(this.canvas.style.position="fixed",this.canvas.style.top="0",this.canvas.style.left="0"):(this.canvas.style.position="absolute",this.canvas.style.top="0",this.canvas.style.left="0",window.getComputedStyle(this.container).position==="static"&&(this.container.style.position="relative")),this.container.appendChild(this.canvas)),this.ctx=this.canvas.getContext("2d"),this.particles=[],this.pool=[],this.sprites=new Map,this.customEffects=new Map,this.isAnimating=!1,this._resize(),window.ResizeObserver&&this.container!==document.body?new ResizeObserver(()=>this._resize()).observe(this.container):window.addEventListener("resize",()=>this._resize())}_resize(){this.container===document.body?(this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight):(this.canvas.width=this.container.clientWidth,this.canvas.height=this.container.clientHeight)}registerSprite(e,t){const s=new Image;s.src=t,this.sprites.set(e,s)}registerEffect(e,t){this.customEffects.set(e,t)}play(e,t,s,...i){const n=this.customEffects.get(e);n?n(t,s,...i):console.warn(`[DopamineJS] Effect '${e}' not found.`)}emit(e){const{x:t,y:s,count:i=10,speed:n=5,gravity:r=.1,decay:h=.02,life:c=1,color:l="#ffd700",sprite:u=null,spread:y=Math.PI*2,angle:p=0,size:w=5}=e;for(let R=0;R<i;R++){const d=this._getParticle(),j=p+(Math.random()-.5)*y,z=Math.random()*n;d.x=t,d.y=s,d.vx=Math.cos(j)*z,d.vy=Math.sin(j)*z,d.life=c,d.decay=h*(.8+Math.random()*.4),d.gravity=r,d.color=Array.isArray(l)?l[Math.floor(Math.random()*l.length)]:l,d.size=w*(.8+Math.random()*.4),d.sprite=u,d.rotation=Math.random()*Math.PI*2,d.rotationSpeed=(Math.random()-.5)*.2,this.particles.push(d)}this._startAnimation()}_getParticle(){return this.pool.length>0?this.pool.pop():{}}_recycleParticle(e){this.pool.push(e)}confetti(e,t,s=50){const i=["#ff6b6b","#4ecdc4","#45b7d1","#f7dc6f","#c06c84","#6c5ce7"];this.emit({x:e,y:t,count:s,color:i,speed:10,gravity:.3,decay:.015,size:8,spread:Math.PI*2})}coinShower(e,t,s=10){this.emit({x:e,y:t,count:s,color:"#ffd700",speed:4,gravity:.4,decay:.012,size:12,angle:-Math.PI/2,spread:Math.PI/2})}sparkle(e,t,s=20,i="#ffd700"){this.emit({x:e,y:t,count:s,color:i,speed:3,gravity:-.05,decay:.03,size:3})}fire(e,t,s=15){const i=["#ff6b00","#ff8800","#ffaa00","#ff4400"];this.emit({x:e,y:t,count:s,color:i,speed:3,gravity:-.2,decay:.04,size:5,angle:-Math.PI/2,spread:Math.PI/4})}starBurst(e,t,s=8){for(let i=0;i<s;i++){const n=this._getParticle(),r=Math.PI*2/s*i,h=4;n.x=e,n.y=t,n.vx=Math.cos(r)*h,n.vy=Math.sin(r)*h,n.life=1,n.decay=.03,n.gravity=0,n.color="#ffffff",n.size=15,n.sprite=null,n.type="star",n.rotation=r,n.rotationSpeed=0,this.particles.push(n)}this._startAnimation()}_startAnimation(){this.isAnimating||(this.isAnimating=!0,this._animate())}_animate(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);for(let e=this.particles.length-1;e>=0;e--){const t=this.particles[e];if(t.vy+=t.gravity,t.x+=t.vx,t.y+=t.vy,t.life-=t.decay,t.rotationSpeed&&(t.rotation+=t.rotationSpeed),t.life<=0){this._recycleParticle(t),this.particles.splice(e,1);continue}if(this.ctx.save(),this.ctx.globalAlpha=t.life,this.ctx.translate(t.x,t.y),this.ctx.rotate(t.rotation),t.sprite&&this.sprites.has(t.sprite)){const s=this.sprites.get(t.sprite);s.complete&&this.ctx.drawImage(s,-t.size/2,-t.size/2,t.size,t.size)}else t.type==="star"?(this.ctx.fillStyle=t.color,this._drawStarPath(0,0,5,t.size,t.size/2),this.ctx.fill()):(this.ctx.fillStyle=t.color,this.ctx.beginPath(),this.ctx.arc(0,0,t.size,0,Math.PI*2),this.ctx.fill());this.ctx.restore()}this.particles.length>0?requestAnimationFrame(()=>this._animate()):this.isAnimating=!1}_drawStarPath(e,t,s,i,n){let r=Math.PI/2*3,h=e,c=t;const l=Math.PI/s;this.ctx.beginPath(),this.ctx.moveTo(e,t-i);for(let u=0;u<s;u++)h=e+Math.cos(r)*i,c=t+Math.sin(r)*i,this.ctx.lineTo(h,c),r+=l,h=e+Math.cos(r)*n,c=t+Math.sin(r)*n,this.ctx.lineTo(h,c),r+=l;this.ctx.lineTo(e,t-i),this.ctx.closePath()}clear(){this.particles.forEach(e=>this._recycleParticle(e)),this.particles=[],this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}}class T{constructor(e={}){this.audioContext=null,this.storageKey=e.storageKey||"dopamineSoundsMuted",this.muted=localStorage.getItem(this.storageKey)==="true",this.assets=new Map,this.customSounds=e.customSounds||{},Object.keys(this.customSounds).length>0&&this.preloadSounds(this.customSounds)}initAudio(){if(!this.audioContext){const e=window.AudioContext||window.webkitAudioContext;this.audioContext=new e}this.audioContext.state==="suspended"&&this.audioContext.resume()}toggleMute(){return this.muted=!this.muted,localStorage.setItem(this.storageKey,this.muted),this.muted}registerSound(e,t){this.customSounds[e]=t,this.audioContext&&this.loadSound(e,t)}async preloadSounds(e){const t=Object.entries(e).map(([s,i])=>this.loadSound(s,i));await Promise.allSettled(t)}async loadSound(e,t){try{if(!this.audioContext)return;const i=await(await fetch(t)).arrayBuffer(),n=await this.audioContext.decodeAudioData(i);this.assets.set(e,n)}catch(s){console.warn(`[DopamineJS] Failed to load sound '${e}':`,s)}}async play(e){if(this.muted)return;if(this.initAudio(),this.assets.has(e)){this._playBuffer(this.assets.get(e));return}if(this.customSounds[e]&&!this.assets.has(e)&&(await this.loadSound(e,this.customSounds[e]),this.assets.has(e))){this._playBuffer(this.assets.get(e));return}const t={jump:()=>this.playJump(!0),score:()=>this.playScore(!0),success:()=>this.playSuccess(!0),click:()=>this.playClick(!0),error:()=>this.playError(!0),gameover:()=>this.playGameOver(!0)};t[e]&&t[e]()}_playBuffer(e){const t=this.audioContext.createBufferSource();t.buffer=e,t.connect(this.audioContext.destination),t.start(0)}playTone(e,t,s="sine",i=.3){if(this.muted)return;this.initAudio();const n=this.audioContext.createOscillator(),r=this.audioContext.createGain();n.connect(r),r.connect(this.audioContext.destination),n.frequency.value=e,n.type=s,r.gain.setValueAtTime(i,this.audioContext.currentTime),r.gain.exponentialRampToValueAtTime(.01,this.audioContext.currentTime+t),n.start(this.audioContext.currentTime),n.stop(this.audioContext.currentTime+t)}playJump(e=!1){if(!e&&this.assets.has("jump"))return this.play("jump");this.playTone(400,.1,"square",.2)}playScore(e=!1){if(!e&&this.assets.has("score"))return this.play("score");this.playTone(800,.15,"sine",.25),setTimeout(()=>this.playTone(1e3,.15,"sine",.25),50)}playGameOver(e=!1){if(!e&&this.assets.has("gameover"))return this.play("gameover");this.playTone(300,.2,"sawtooth",.3),setTimeout(()=>this.playTone(200,.2,"sawtooth",.3),100),setTimeout(()=>this.playTone(150,.3,"sawtooth",.3),200)}playClick(e=!1){if(!e&&this.assets.has("click"))return this.play("click");this.playTone(600,.05,"sine",.1)}playSuccess(e=!1){if(!e&&this.assets.has("success"))return this.play("success");this.playTone(600,.1,"sine",.2),setTimeout(()=>this.playTone(800,.2,"sine",.2),100)}playError(e=!1){if(!e&&this.assets.has("error"))return this.play("error");this.playTone(200,.2,"sawtooth",.3)}}class G{constructor(e={}){this.config=e,this.dataService=new M(e.data||{}),this.rewardSystem=new b(this.dataService,e.rewards||{}),this.soundManager=new T(e.sound||{}),this.particleSystem=new E(e.particles||{}),this.gameUI=new P(this.particleSystem),this._bindEvents()}async init(){return await this.rewardSystem.init(),{rewardSystem:this.rewardSystem,gameUI:this.gameUI,particleSystem:this.particleSystem,soundManager:this.soundManager}}_bindEvents(){this.rewardSystem.on("xp_gained",e=>{const{total:t,needed:s}=this.rewardSystem.getXPForNextLevel();this.gameUI.updateXP(this.rewardSystem.player.xp,s,t),e.xpGained>0}),this.rewardSystem.on("level_up",e=>{this.gameUI.updateLevel(e.newLevel),this.gameUI.showLevelUp(e.oldLevel,e.newLevel)}),this.rewardSystem.on("achievement_unlocked",e=>{this.gameUI.showAchievement(e)}),this.rewardSystem.on("new_high_score",e=>{this.gameUI.showNotification(`New High Score: ${e.score}!`,"legendary"),this.soundManager.playSuccess()})}}class m{constructor(){this._listeners=new Map,this._onceListeners=new Map,this._sortedCache=new Map}on(e,t,s=0){return this._listeners.has(e)||this._listeners.set(e,new Set),this._listeners.get(e).add({callback:t,priority:s}),this._sortedCache.delete(e),this}once(e,t){return this._onceListeners.has(e)||this._onceListeners.set(e,new Set),this._onceListeners.get(e).add(t),this}off(e,t){const s=this._listeners.get(e);if(s){for(const n of s)if(n.callback===t){s.delete(n),this._sortedCache.delete(e);break}}const i=this._onceListeners.get(e);return i&&i.delete(t),this}emit(e,t){const s=this._getSortedListeners(e);for(let n=0;n<s.length;n++)s[n].callback(t);const i=this._onceListeners.get(e);if(i&&i.size>0){for(const n of i)n(t);i.clear()}}_getSortedListeners(e){if(this._sortedCache.has(e))return this._sortedCache.get(e);const t=this._listeners.get(e);if(!t||t.size===0)return[];const s=Array.from(t).sort((i,n)=>n.priority-i.priority);return this._sortedCache.set(e,s),s}clear(e){e?(this._listeners.delete(e),this._onceListeners.delete(e),this._sortedCache.delete(e)):(this._listeners.clear(),this._onceListeners.clear(),this._sortedCache.clear())}hasListeners(e){const t=this._listeners.get(e),s=this._onceListeners.get(e);return t&&t.size>0||s&&s.size>0}}m.Events={TICK:"tick",FIXED_UPDATE:"fixed_update",RENDER:"render",COLLISION_ENTER:"collision_enter",COLLISION_EXIT:"collision_exit",XP_GAINED:"xp_gained",LEVEL_UP:"level_up",ACHIEVEMENT_UNLOCKED:"achievement_unlocked",NEW_HIGH_SCORE:"new_high_score",STREAK_UPDATED:"streak_updated",SYSTEM_REGISTERED:"system_registered",SYSTEM_UNREGISTERED:"system_unregistered",PLUGIN_LOADED:"plugin_loaded",PLUGIN_UNLOADED:"plugin_unloaded"};class I{constructor(e){this.kernel=e,this._systems=new Map,this._updateOrder=[],this._fixedUpdateOrder=[],this._needsRecompute=!1}register(e,t,{priority:s=0,dependencies:i=[]}={}){this._systems.has(e)&&(console.warn(`[SystemRegistry] System "${e}" already registered. Replacing.`),this.unregister(e));for(const n of i)this._systems.has(n)||console.warn(`[SystemRegistry] Dependency "${n}" not found for system "${e}"`);return this._systems.set(e,{system:t,priority:s,dependencies:i}),t.init&&t.init(this.kernel),this._needsRecompute=!0,this.kernel.events.emit("system_registered",{name:e,system:t}),this}get(e){const t=this._systems.get(e);return t?t.system:void 0}has(e){return this._systems.has(e)}unregister(e){const t=this._systems.get(e);return t?(t.system.destroy&&t.system.destroy(),this._systems.delete(e),this._needsRecompute=!0,this.kernel.events.emit("system_unregistered",{name:e}),!0):!1}update(e){this._needsRecompute&&this._recomputeUpdateOrder();for(let t=0;t<this._updateOrder.length;t++){const s=this._updateOrder[t];s.update&&s.update(e)}}fixedUpdate(e){this._needsRecompute&&this._recomputeUpdateOrder();for(let t=0;t<this._fixedUpdateOrder.length;t++){const s=this._fixedUpdateOrder[t];s.fixedUpdate&&s.fixedUpdate(e)}}_recomputeUpdateOrder(){const e=Array.from(this._systems.entries()),t=new Map,s=new Map;for(const[r,h]of e)t.set(r,h.dependencies),s.set(r,0);for(const[r,h]of t)for(const c of h)s.has(c)&&s.set(r,s.get(r)+1);const i=[],n=[];for(const[r,h]of s)h===0&&i.push(r);for(;i.length>0;){i.sort((h,c)=>{const l=this._systems.get(h).priority;return this._systems.get(c).priority-l});const r=i.shift();n.push(r);for(const[h,c]of t)if(c.includes(r)){const l=s.get(h)-1;s.set(h,l),l===0&&i.push(h)}}n.length!==e.length&&(console.error("[SystemRegistry] Circular dependency detected in systems!"),n.length=0,n.push(...e.map(([r])=>r).sort((r,h)=>this._systems.get(h).priority-this._systems.get(r).priority))),this._updateOrder=n.map(r=>this._systems.get(r).system).filter(r=>r.update),this._fixedUpdateOrder=n.map(r=>this._systems.get(r).system).filter(r=>r.fixedUpdate),this._needsRecompute=!1}getSystemNames(){return Array.from(this._systems.keys())}clear(){for(const e of this._systems.keys())this.unregister(e)}}class C{constructor(e){this.kernel=e,this._plugins=new Map,this._loadOrder=[]}use(e){if(!e.name)throw new Error("[PluginRegistry] Plugin must have a name");if(this._plugins.has(e.name))return console.warn(`[PluginRegistry] Plugin "${e.name}" already registered. Skipping.`),this;if(!e.init||typeof e.init!="function")throw new Error(`[PluginRegistry] Plugin "${e.name}" must have an init() method`);this._plugins.set(e.name,e),this._loadOrder.push(e.name);try{e.init(this.kernel),this.kernel.events.emit("plugin_loaded",{name:e.name,version:e.version})}catch(t){throw console.error(`[PluginRegistry] Failed to initialize plugin "${e.name}":`,t),this._plugins.delete(e.name),this._loadOrder.pop(),t}return this}async useAsync(e){if(!e.name)throw new Error("[PluginRegistry] Plugin must have a name");if(this._plugins.has(e.name))return console.warn(`[PluginRegistry] Plugin "${e.name}" already registered. Skipping.`),this;if(!e.init||typeof e.init!="function")throw new Error(`[PluginRegistry] Plugin "${e.name}" must have an init() method`);this._plugins.set(e.name,e),this._loadOrder.push(e.name);try{await e.init(this.kernel),this.kernel.events.emit("plugin_loaded",{name:e.name,version:e.version})}catch(t){throw console.error(`[PluginRegistry] Failed to initialize plugin "${e.name}":`,t),this._plugins.delete(e.name),this._loadOrder.pop(),t}return this}remove(e){const t=this._plugins.get(e);if(!t)return!1;if(t.destroy)try{t.destroy()}catch(i){console.error(`[PluginRegistry] Error destroying plugin "${e}":`,i)}this._plugins.delete(e);const s=this._loadOrder.indexOf(e);return s>-1&&this._loadOrder.splice(s,1),this.kernel.events.emit("plugin_unloaded",{name:e}),!0}get(e){return this._plugins.get(e)}has(e){return this._plugins.has(e)}getPluginNames(){return Array.from(this._plugins.keys())}getLoadOrder(){return[...this._loadOrder]}clear(){for(let e=this._loadOrder.length-1;e>=0;e--)this.remove(this._loadOrder[e])}}class O{constructor(e={}){this.width=e.width||800,this.height=e.height||600,this.backgroundColor=e.backgroundColor||"#000000",e.canvas?(this.canvas=e.canvas,this.canvas.width=this.width,this.canvas.height=this.height):(this.canvas=document.createElement("canvas"),this.canvas.width=this.width,this.canvas.height=this.height,(e.parent?typeof e.parent=="string"?document.querySelector(e.parent):e.parent:document.body).appendChild(this.canvas)),this.ctx=this.canvas.getContext("2d")}clear(){this.ctx.fillStyle=this.backgroundColor,this.ctx.fillRect(0,0,this.width,this.height)}resize(e,t){this.width=e,this.height=t,this.canvas.width=e,this.canvas.height=t}}class A{constructor(){this.running=!1,this.lastTime=0,this.callbacks=new Set,this._tick=this._tick.bind(this)}add(e){this.callbacks.add(e)}remove(e){this.callbacks.delete(e)}start(){this.running||(this.running=!0,this.lastTime=performance.now(),requestAnimationFrame(this._tick))}stop(){this.running=!1}_tick(e){if(!this.running)return;const t=(e-this.lastTime)/1e3;this.lastTime=e;const s=Math.min(t,.1);for(const i of this.callbacks)i(s);requestAnimationFrame(this._tick)}}class f{constructor(){this.gameObject=null,this.kernel=null}get physics(){var e;return(e=this.kernel)==null?void 0:e.systems.get("physics")}get input(){var e;return(e=this.kernel)==null?void 0:e.systems.get("input")}get loader(){var e;return(e=this.kernel)==null?void 0:e.systems.get("loader")}get events(){var e;return(e=this.kernel)==null?void 0:e.events}onAttach(){}onDetach(){}update(e){}render(e){}}class B extends f{constructor(e="box",t=50,s=50,i=25){super(),this.type=e,this.width=t,this.height=s,this.radius=i,this.tag=null}onAttach(){super.onAttach(),this.physics&&this.physics.add(this)}onDetach(){super.onDetach(),this.physics&&this.physics.remove(this)}getBounds(){const e=this.gameObject;if(this.type==="box")return{left:e.x-this.width/2,right:e.x+this.width/2,top:e.y-this.height/2,bottom:e.y+this.height/2};if(this.type==="circle")return{x:e.x,y:e.y,radius:this.radius}}}class _{constructor(){this.colliders=[],this.kernel=null}init(e){this.kernel=e}fixedUpdate(e){this.step()}destroy(){this.colliders=[]}add(e){this.colliders.push(e)}remove(e){const t=this.colliders.indexOf(e);t>-1&&this.colliders.splice(t,1)}step(){for(let e=0;e<this.colliders.length;e++)for(let t=e+1;t<this.colliders.length;t++){const s=this.colliders[e],i=this.colliders[t];this._intersects(s,s.getBounds(),i,i.getBounds())&&(this._notifyCollision(s.gameObject,i.gameObject),this._notifyCollision(i.gameObject,s.gameObject))}}_notifyCollision(e,t){!e||!e.components||e.components.forEach(s=>{s.onCollisionEnter&&s.onCollisionEnter(t)})}checkOverlap(e,t){const s=[],i=e.getBounds();for(const n of this.colliders){if(n===e||t&&n.tag!==t)continue;const r=n.getBounds();this._intersects(e,i,n,r)&&s.push(n)}return s}_intersects(e,t,s,i){if(e.type==="box"&&s.type==="box")return t.left<i.right&&t.right>i.left&&t.top<i.bottom&&t.bottom>i.top;if(e.type==="circle"&&s.type==="circle"){const n=t.x-i.x,r=t.y-i.y;return Math.sqrt(n*n+r*r)<t.radius+i.radius}return!1}addBody(e){this.add(e)}removeBody(e){this.remove(e)}checkCollision(e,t){return this._intersects(e,e.getBounds(),t,t.getBounds())}raycast(e,t,s){return null}setGravity(e,t){}}const $=new _;console.warn("[DopamineJS] GlobalPhysics is deprecated. Use kernel.physics instead.");class x{constructor(){this.keys=new Map,this.mouse={x:0,y:0,buttons:new Map},this.kernel=null,this._onKeyDown=this._onKeyDown.bind(this),this._onKeyUp=this._onKeyUp.bind(this),this._onMouseMove=this._onMouseMove.bind(this),this._onMouseDown=this._onMouseDown.bind(this),this._onMouseUp=this._onMouseUp.bind(this)}init(e){this.kernel=e,window.addEventListener("keydown",this._onKeyDown),window.addEventListener("keyup",this._onKeyUp),window.addEventListener("mousemove",this._onMouseMove),window.addEventListener("mousedown",this._onMouseDown),window.addEventListener("mouseup",this._onMouseUp)}destroy(){window.removeEventListener("keydown",this._onKeyDown),window.removeEventListener("keyup",this._onKeyUp),window.removeEventListener("mousemove",this._onMouseMove),window.removeEventListener("mousedown",this._onMouseDown),window.removeEventListener("mouseup",this._onMouseUp)}_onKeyDown(e){this.keys.set(e.key,!0)}_onKeyUp(e){this.keys.set(e.key,!1)}_onMouseMove(e){this.mouse.x=e.clientX,this.mouse.y=e.clientY}_onMouseDown(e){this.mouse.buttons.set(e.button,!0)}_onMouseUp(e){this.mouse.buttons.set(e.button,!1)}isKeyDown(e){return this.keys.get(e)||!1}isMouseButtonDown(e=0){return this.mouse.buttons.get(e)||!1}}const F=new x;console.warn("[DopamineJS] GlobalInput is deprecated. Use kernel.input instead.");class S{constructor(){this.assets=new Map,this.kernel=null}init(e){this.kernel=e}destroy(){this.assets.clear()}async loadImage(e,t){return new Promise((s,i)=>{const n=new Image;n.onload=()=>{this.assets.set(e,n),s(n)},n.onerror=i,n.src=t})}get(e){return this.assets.get(e)}}const N=new S;console.warn("[DopamineJS] GlobalLoader is deprecated. Use kernel.loader instead.");class D{constructor(e={}){this.config=e,this.events=new m,this.systems=new I(this),this.plugins=new C(this),this._registerCoreSystems(e),this.fixedTimestep=e.fixedTimestep||1/60,this._accumulator=0,this._maxAccumulator=this.fixedTimestep*5}_registerCoreSystems(e){this.systems.register("ticker",new A,{priority:100});const t={width:e.width,height:e.height,backgroundColor:e.backgroundColor,canvas:e.canvas,...e.renderer};this.systems.register("renderer",new O(t),{priority:90}),this.systems.register("input",new x,{priority:80}),this.systems.register("loader",new S,{priority:70}),this.systems.register("physics",new _,{priority:60})}start(){const e=this.systems.get("ticker");e&&(e.add(this._update.bind(this)),e.start()),this.events.emit("kernel_started")}stop(){const e=this.systems.get("ticker");e&&e.stop(),this.events.emit("kernel_stopped")}_update(e){for(this.events.emit(m.Events.TICK,{dt:e}),this._accumulator+=e,this._accumulator>this._maxAccumulator&&(this._accumulator=this._maxAccumulator);this._accumulator>=this.fixedTimestep;)this.events.emit(m.Events.FIXED_UPDATE,{dt:this.fixedTimestep}),this.systems.fixedUpdate(this.fixedTimestep),this._accumulator-=this.fixedTimestep;this.systems.update(e),this.events.emit(m.Events.RENDER,{dt:e})}get physics(){return this.systems.get("physics")}get input(){return this.systems.get("input")}get loader(){return this.systems.get("loader")}get renderer(){return this.systems.get("renderer")}get ticker(){return this.systems.get("ticker")}destroy(){this.stop(),this.plugins.clear(),this.systems.clear(),this.events.clear()}}const v={init(a){},update(a){},fixedUpdate(a){},destroy(){}};class K{constructor(){this.kernel=null}init(e){this.kernel=e}update(e){}fixedUpdate(e){}destroy(){}}const X={...v,addBody(a){},removeBody(a){},checkCollision(a,e){},raycast(a,e,t){},setGravity(a,e){},step(a){}},H={...v,registerSound(a,e){},preloadSounds(a){},play(a,e){},playTone(a,e,t,s){},stop(a){},toggleMute(){},setVolume(a){}},q={...v,registerSprite(a,e){},registerEffect(a,e){},play(a,e,t,...s){},emit(a){},clear(){},confetti(a,e,t){},coinShower(a,e,t){},sparkle(a,e,t,s){},fire(a,e,t){},starBurst(a,e,t){}};class W{constructor(){this.gameObjects=[],this.kernel=null}onEnter(){}onExit(){}add(e){return this.kernel&&(e.kernel=this.kernel),this.gameObjects.push(e),e}remove(e){const t=this.gameObjects.indexOf(e);t>-1&&this.gameObjects.splice(t,1)}update(e){for(const t of this.gameObjects)t.update(e)}render(e){for(const t of this.gameObjects)t.render(e)}}class L{constructor(e){this.game=e,this.currentScene=null}run(e){this.currentScene&&this.currentScene.onExit(),this.currentScene=e,this.currentScene.game=this.game,this.game.scene=e,e.onEnter()}}class J{constructor(e={}){this.config=e,this.kernel=new D(e),this.director=new L(this),this.kernel.systems.register("director",this.director),this.kernel.events.on(m.Events.TICK,this._update.bind(this),10),this.kernel.events.on(m.Events.RENDER,this._render.bind(this),10)}get renderer(){return this.kernel.renderer}get ticker(){return this.kernel.ticker}get physics(){return this.kernel.physics}get input(){return this.kernel.input}start(){this.kernel.start()}stop(){this.kernel.stop()}setScene(e){e.kernel=this.kernel,this.director.run(e)}_update({dt:e}){this.director.currentScene&&this.director.currentScene.update(e)}_render({dt:e}){this.renderer.clear(),this.director.currentScene&&this.director.currentScene.render(this.renderer.ctx)}destroy(){this.kernel.destroy()}}class Y{constructor(e=0,t=0){this.x=e,this.y=t,this.rotation=0,this.scale={x:1,y:1},this.components=[],this.children=[],this.parent=null,this._kernel=null}get kernel(){return this._kernel}set kernel(e){this._kernel=e;for(const t of this.components)t.kernel=e;for(const t of this.children)t.kernel=e}addChild(e){return e.parent=this,e.kernel=this.kernel,this.children.push(e),e}addComponent(e){return e.gameObject=this,e.kernel=this.kernel,this.components.push(e),e.onAttach(),e}getComponent(e){return this.components.find(t=>t instanceof e)}update(e){for(const t of this.components)t.update&&t.update(e);for(const t of this.children)t.update(e)}render(e){e.save(),e.translate(this.x,this.y),e.rotate(this.rotation),e.scale(this.scale.x,this.scale.y);for(const t of this.components)t.render&&t.render(e);for(const t of this.children)t.render(e);e.restore()}}class k{constructor(e=0,t=0){this.x=e,this.y=t}add(e){return this.x+=e.x,this.y+=e.y,this}sub(e){return this.x-=e.x,this.y-=e.y,this}scale(e){return this.x*=e,this.y*=e,this}distance(e){const t=this.x-e.x,s=this.y-e.y;return Math.sqrt(t*t+s*s)}normalize(){const e=Math.sqrt(this.x*this.x+this.y*this.y);return e>0&&(this.x/=e,this.y/=e),this}clone(){return new k(this.x,this.y)}static distance(e,t){return Math.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2))}}class U extends f{constructor(e){super(),this.image=e,this.anchor={x:.5,y:.5},this.width=e?e.width:0,this.height=e?e.height:0,this.frame={x:0,y:0,w:this.width,h:this.height}}setFrame(e,t,s,i){this.frame={x:e,y:t,w:s,h:i},this.width=s,this.height=i}setTexture(e){this.image=e,e&&this.setFrame(0,0,e.width,e.height)}render(e){if(!this.image)return;const t=this.frame.w,s=this.frame.h,i=-t*this.anchor.x,n=-s*this.anchor.y;e.drawImage(this.image,this.frame.x,this.frame.y,t,s,i,n,t,s)}}class V extends f{constructor(){super(),this.animations={},this.currentAnim=null,this.timer=0,this.currentFrameIndex=0,this.sprite=null}onAttach(){this.sprite=this.gameObject.getComponent(U),this.sprite||console.warn("Animator attached to GameObject without a Sprite component.")}addAnimation(e,t,s=10,i=!0){this.animations[e]={frames:t,fps:s,loop:i}}play(e){this.currentAnim&&this.currentAnim.name===e||this.animations[e]&&(this.currentAnim={name:e,...this.animations[e]},this.currentFrameIndex=0,this.timer=0,this._updateFrame())}update(e){if(!this.currentAnim||!this.sprite)return;this.timer+=e;const t=1/this.currentAnim.fps;this.timer>=t&&(this.timer-=t,this.currentFrameIndex++,this.currentFrameIndex>=this.currentAnim.frames.length&&(this.currentAnim.loop?this.currentFrameIndex=0:this.currentFrameIndex=this.currentAnim.frames.length-1),this._updateFrame())}_updateFrame(){const e=this.currentAnim.frames[this.currentFrameIndex];this.sprite.setFrame(e.x,e.y,e.w,e.h)}}class Q{static createGround(e,t,s="#333"){const i=document.createElement("canvas");i.width=e,i.height=t;const n=i.getContext("2d");n.fillStyle=s,n.fillRect(0,0,e,t);for(let r=0;r<1e3;r++){n.fillStyle=Math.random()>.5?"#444":"#222";const h=Math.random()*4+2;n.fillRect(Math.random()*e,Math.random()*t,h,h)}n.strokeStyle="rgba(255,255,255,0.05)",n.lineWidth=2,n.beginPath();for(let r=0;r<=e;r+=64)n.moveTo(r,0),n.lineTo(r,t);for(let r=0;r<=t;r+=64)n.moveTo(0,r),n.lineTo(e,r);return n.stroke(),i}static createCharacterSheet(e,t){const n=document.createElement("canvas");n.width=64*4,n.height=64;const r=n.getContext("2d");for(let h=0;h<4;h++){const c=h*64,l=0,u=c+64/2,y=l+64/2,p=h%2===0?0:-2,w=h===1?5:h===3?-5:0;r.fillStyle=e,r.beginPath(),r.arc(u,y+p,20,0,Math.PI*2),r.fill(),r.fillStyle=t,r.beginPath(),r.arc(u-15,y+p+w,8,0,Math.PI*2),r.arc(u+15,y+p-w,8,0,Math.PI*2),r.fill(),r.fillStyle=Z(e),r.beginPath(),r.arc(u,y+p,15,0,Math.PI*2),r.fill(),t==="#333"&&(r.fillStyle="#000",r.fillRect(u+10,y+p-5,25,6))}return n}}function Z(a,e){return a}class ee extends f{constructor(e){super(),this.system=e}play(e,t={}){const s=this.gameObject.x,i=this.gameObject.y;switch(e){case"confetti":this.system.confetti(s,i,t.count);break;case"fire":this.system.fire(s,i,t.count);break;case"sparkle":this.system.sparkle(s,i,t.count,t.color);break;case"blood":this.system.emit({x:s,y:i,count:10,color:["#8a0303","#ff0000"],speed:4,gravity:.1,decay:.05});break;default:this.system.emit({x:s,y:i,...t})}}}class te extends f{constructor(){super(),this.intensity=0,this.duration=0,this.timer=0,this.originalPos={x:0,y:0},this.isShaking=!1}shake(e=5,t=.2){this.intensity=e,this.duration=t,this.timer=0,this.isShaking=!0,this.timer===0&&(this.originalPos.x=this.gameObject.x,this.originalPos.y=this.gameObject.y)}update(e){if(!this.isShaking)return;if(this.timer+=e,this.timer>=this.duration){this.isShaking=!1,this.gameObject.x=this.originalPos.x,this.gameObject.y=this.originalPos.y;return}const t=(Math.random()-.5)*2*this.intensity,s=(Math.random()-.5)*2*this.intensity;this.gameObject.x=this.originalPos.x+t,this.gameObject.y=this.originalPos.y+s}}o.Animator=V,o.Collider=B,o.Component=f,o.DataService=M,o.Director=L,o.DopamineKernel=D,o.EventBus=m,o.Game=J,o.GameObject=Y,o.GameUI=P,o.GlobalInput=F,o.GlobalLoader=N,o.GlobalPhysics=$,o.IAudioSystem=H,o.IParticleSystem=q,o.IPhysicsSystem=X,o.ISystem=v,o.Input=x,o.Loader=S,o.ParticleEmitter=ee,o.ParticleSystem=E,o.Physics=_,o.PluginRegistry=C,o.Renderer=O,o.RewardSystem=b,o.Scene=W,o.ScreenShake=te,o.SoundManager=T,o.Sprite=U,o.System=K,o.SystemRegistry=I,o.TextureGenerator=Q,o.Ticker=A,o.Vector2=k,o.default=G,Object.defineProperties(o,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
package/package.json
CHANGED
|
@@ -43,7 +43,14 @@ export class DopamineKernel {
|
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
// Renderer
|
|
46
|
-
|
|
46
|
+
const rendererOptions = {
|
|
47
|
+
width: config.width,
|
|
48
|
+
height: config.height,
|
|
49
|
+
backgroundColor: config.backgroundColor,
|
|
50
|
+
canvas: config.canvas,
|
|
51
|
+
...config.renderer
|
|
52
|
+
};
|
|
53
|
+
this.systems.register('renderer', new Renderer(rendererOptions), {
|
|
47
54
|
priority: 90
|
|
48
55
|
});
|
|
49
56
|
|
package/src/core/Game.js
CHANGED
|
@@ -16,6 +16,7 @@ export class Game {
|
|
|
16
16
|
|
|
17
17
|
// Initialize Director
|
|
18
18
|
this.director = new Director(this);
|
|
19
|
+
this.kernel.systems.register('director', this.director);
|
|
19
20
|
|
|
20
21
|
// Bind to kernel tick event for scene updates
|
|
21
22
|
this.kernel.events.on(EventBus.Events.TICK, this._update.bind(this), 10);
|
package/src/core/GameObject.js
CHANGED
|
@@ -14,7 +14,23 @@ export class GameObject {
|
|
|
14
14
|
this.components = [];
|
|
15
15
|
this.children = [];
|
|
16
16
|
this.parent = null;
|
|
17
|
-
this.
|
|
17
|
+
this._kernel = null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get kernel() {
|
|
21
|
+
return this._kernel;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
set kernel(value) {
|
|
25
|
+
this._kernel = value;
|
|
26
|
+
// Propagate to components
|
|
27
|
+
for (const comp of this.components) {
|
|
28
|
+
comp.kernel = value;
|
|
29
|
+
}
|
|
30
|
+
// Propagate to children
|
|
31
|
+
for (const child of this.children) {
|
|
32
|
+
child.kernel = value;
|
|
33
|
+
}
|
|
18
34
|
}
|
|
19
35
|
|
|
20
36
|
/**
|
|
@@ -60,7 +60,7 @@ export class PluginRegistry {
|
|
|
60
60
|
version: plugin.version
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
// Plugin loaded successfully
|
|
64
64
|
} catch (error) {
|
|
65
65
|
console.error(`[PluginRegistry] Failed to initialize plugin "${plugin.name}":`, error);
|
|
66
66
|
this._plugins.delete(plugin.name);
|
|
@@ -106,7 +106,7 @@ export class PluginRegistry {
|
|
|
106
106
|
version: plugin.version
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
// Plugin loaded successfully
|
|
110
110
|
} catch (error) {
|
|
111
111
|
console.error(`[PluginRegistry] Failed to initialize plugin "${plugin.name}":`, error);
|
|
112
112
|
this._plugins.delete(plugin.name);
|
package/src/core/Scene.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export class Scene {
|
|
5
5
|
constructor() {
|
|
6
|
-
this.
|
|
7
|
-
this.
|
|
6
|
+
this.gameObjects = [];
|
|
7
|
+
this.kernel = null; // Injected by Game
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -12,30 +12,19 @@ export class Scene {
|
|
|
12
12
|
*/
|
|
13
13
|
onEnter() { }
|
|
14
14
|
|
|
15
|
-
onExit() { }
|
|
16
|
-
|
|
17
15
|
/**
|
|
18
|
-
*
|
|
19
|
-
* @param {number} dt
|
|
16
|
+
* Called when the scene is removed from the Game.
|
|
20
17
|
*/
|
|
21
|
-
|
|
22
|
-
// Update all children (GameObjects)
|
|
23
|
-
for (const child of this.children) {
|
|
24
|
-
if (child.update) child.update(dt);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
this.gameObjects = [];
|
|
30
|
-
this.kernel = null; // Injected by Game
|
|
31
|
-
}
|
|
18
|
+
onExit() { }
|
|
32
19
|
|
|
33
20
|
/**
|
|
34
21
|
* Add a GameObject to the scene.
|
|
35
22
|
* @param {GameObject} gameObject
|
|
36
23
|
*/
|
|
37
24
|
add(gameObject) {
|
|
38
|
-
|
|
25
|
+
if (this.kernel) {
|
|
26
|
+
gameObject.kernel = this.kernel; // Inject kernel
|
|
27
|
+
}
|
|
39
28
|
this.gameObjects.push(gameObject);
|
|
40
29
|
return gameObject;
|
|
41
30
|
}
|
|
@@ -51,12 +40,20 @@ export class Scene {
|
|
|
51
40
|
}
|
|
52
41
|
}
|
|
53
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Update loop for the scene.
|
|
45
|
+
* @param {number} dt
|
|
46
|
+
*/
|
|
54
47
|
update(dt) {
|
|
55
48
|
for (const obj of this.gameObjects) {
|
|
56
49
|
obj.update(dt);
|
|
57
50
|
}
|
|
58
51
|
}
|
|
59
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Render loop for the scene.
|
|
55
|
+
* @param {CanvasRenderingContext2D} ctx
|
|
56
|
+
*/
|
|
60
57
|
render(ctx) {
|
|
61
58
|
for (const obj of this.gameObjects) {
|
|
62
59
|
obj.render(ctx);
|
|
@@ -28,14 +28,11 @@ export class WebGLParticleSystem {
|
|
|
28
28
|
this.registeredEffects = new Map();
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
// ISystem interface
|
|
32
31
|
init(kernel) {
|
|
33
32
|
this.kernel = kernel;
|
|
34
33
|
this._initWebGL();
|
|
35
34
|
this._createShaders();
|
|
36
35
|
this._createBuffers();
|
|
37
|
-
|
|
38
|
-
console.log('[WebGLParticles] Initialized with max particles:', this.maxParticles);
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
update(dt) {
|
package/src/dopamine/index.js
CHANGED
package/src/renderer/Renderer.js
CHANGED
|
@@ -7,17 +7,25 @@ export class Renderer {
|
|
|
7
7
|
this.height = options.height || 600;
|
|
8
8
|
this.backgroundColor = options.backgroundColor || '#000000';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
// Use existing canvas if provided, otherwise create new one
|
|
11
|
+
if (options.canvas) {
|
|
12
|
+
this.canvas = options.canvas;
|
|
13
|
+
this.canvas.width = this.width;
|
|
14
|
+
this.canvas.height = this.height;
|
|
15
|
+
} else {
|
|
16
|
+
this.canvas = document.createElement('canvas');
|
|
17
|
+
this.canvas.width = this.width;
|
|
18
|
+
this.canvas.height = this.height;
|
|
19
|
+
|
|
20
|
+
// Append to body or specified container
|
|
21
|
+
const parent = options.parent ?
|
|
22
|
+
(typeof options.parent === 'string' ? document.querySelector(options.parent) : options.parent)
|
|
23
|
+
: document.body;
|
|
14
24
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
(typeof options.parent === 'string' ? document.querySelector(options.parent) : options.parent)
|
|
18
|
-
: document.body;
|
|
25
|
+
parent.appendChild(this.canvas);
|
|
26
|
+
}
|
|
19
27
|
|
|
20
|
-
|
|
28
|
+
this.ctx = this.canvas.getContext('2d');
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
/**
|