@energy8platform/game-engine 0.10.11 → 0.12.0
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/README.md +272 -74
- package/dist/index.cjs.js +1322 -296
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +369 -46
- package/dist/index.esm.js +1323 -298
- package/dist/index.esm.js.map +1 -1
- package/dist/lua.cjs.js +8 -18
- package/dist/lua.cjs.js.map +1 -1
- package/dist/lua.d.ts +0 -2
- package/dist/lua.esm.js +8 -18
- package/dist/lua.esm.js.map +1 -1
- package/dist/react.cjs.js +2848 -35
- package/dist/react.cjs.js.map +1 -1
- package/dist/react.d.ts +17 -6
- package/dist/react.esm.js +2848 -36
- package/dist/react.esm.js.map +1 -1
- package/dist/ui.cjs.js +1913 -592
- package/dist/ui.cjs.js.map +1 -1
- package/dist/ui.d.ts +528 -46
- package/dist/ui.esm.js +1911 -594
- package/dist/ui.esm.js.map +1 -1
- package/dist/vite.cjs.js +1 -11
- package/dist/vite.cjs.js.map +1 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vite.esm.js +1 -11
- package/dist/vite.esm.js.map +1 -1
- package/package.json +3 -18
- package/src/index.ts +3 -3
- package/src/lua/LuaEngine.ts +8 -18
- package/src/react/applyProps.ts +90 -2
- package/src/react/extendAll.ts +29 -6
- package/src/react/index.ts +1 -1
- package/src/react/jsx.d.ts +249 -0
- package/src/react/reconciler.ts +80 -7
- package/src/ui/BalanceDisplay.ts +31 -38
- package/src/ui/Button.ts +217 -53
- package/src/ui/FlexContainer.ts +529 -0
- package/src/ui/Label.ts +13 -0
- package/src/ui/Layout.ts +86 -87
- package/src/ui/Modal.ts +11 -1
- package/src/ui/Panel.ts +108 -36
- package/src/ui/ProgressBar.ts +85 -31
- package/src/ui/ScrollContainer.ts +397 -45
- package/src/ui/Slider.ts +241 -0
- package/src/ui/Toast.ts +47 -17
- package/src/ui/Toggle.ts +201 -0
- package/src/ui/WinDisplay.ts +51 -39
- package/src/ui/index.ts +9 -11
- package/src/ui/view.ts +28 -0
- package/src/vite/index.ts +1 -11
package/README.md
CHANGED
|
@@ -35,7 +35,6 @@ A casino game engine built on [PixiJS v8](https://pixijs.com/) and [@energy8plat
|
|
|
35
35
|
npm install pixi.js @energy8platform/game-sdk @energy8platform/game-engine
|
|
36
36
|
|
|
37
37
|
# Optional peer dependencies
|
|
38
|
-
npm install @pixi/ui @pixi/layout yoga-layout # UI components (Layout, Panel, ScrollContainer)
|
|
39
38
|
npm install @pixi/sound # Audio
|
|
40
39
|
npm install @esotericsoftware/spine-pixi-v8 # Spine animations
|
|
41
40
|
npm install react react-dom react-reconciler # React integration
|
|
@@ -88,9 +87,6 @@ bootstrap();
|
|
|
88
87
|
| --- | --- | --- |
|
|
89
88
|
| `pixi.js` | `^8.16.0` | Yes |
|
|
90
89
|
| `@energy8platform/game-sdk` | `^2.7.0` | Yes |
|
|
91
|
-
| `@pixi/ui` | `^2.3.0` | Optional — Button, ScrollContainer, ProgressBar |
|
|
92
|
-
| `@pixi/layout` | `^3.2.0` | Optional — Layout, Panel (Yoga flexbox) |
|
|
93
|
-
| `yoga-layout` | `^3.0.0` | Optional — peer dep of `@pixi/layout` |
|
|
94
90
|
| `@pixi/sound` | `^6.0.0` | Optional — audio |
|
|
95
91
|
| `@esotericsoftware/spine-pixi-v8` | `~4.2.0` | Optional — Spine animations |
|
|
96
92
|
| `react`, `react-dom` | `>=18.0.0` | Optional — ReactScene |
|
|
@@ -104,10 +100,10 @@ import { GameApplication } from '@energy8platform/game-engine'; // f
|
|
|
104
100
|
import { Scene, SceneManager } from '@energy8platform/game-engine/core';
|
|
105
101
|
import { AssetManager } from '@energy8platform/game-engine/assets';
|
|
106
102
|
import { AudioManager } from '@energy8platform/game-engine/audio';
|
|
107
|
-
import { Button, Label, Modal, Layout, ScrollContainer,
|
|
103
|
+
import { FlexContainer, Button, Label, Panel, Modal, Layout, ScrollContainer, Toast, ProgressBar, BalanceDisplay, WinDisplay, Slider, Toggle, resolveView } from '@energy8platform/game-engine/ui';
|
|
108
104
|
import { Tween, Timeline, Easing, SpriteAnimation } from '@energy8platform/game-engine/animation';
|
|
109
105
|
import { DevBridge, FPSOverlay } from '@energy8platform/game-engine/debug';
|
|
110
|
-
import { ReactScene,
|
|
106
|
+
import { ReactScene, extendPixiElements, extendUIElements, useSDK, useViewport } from '@energy8platform/game-engine/react';
|
|
111
107
|
import { defineGameConfig } from '@energy8platform/game-engine/vite';
|
|
112
108
|
import { LuaEngine, ActionRouter } from '@energy8platform/game-engine/lua';
|
|
113
109
|
```
|
|
@@ -396,17 +392,65 @@ SpineHelper.setSkin(spine, 'warrior');
|
|
|
396
392
|
|
|
397
393
|
## UI Components
|
|
398
394
|
|
|
399
|
-
>
|
|
400
|
-
>
|
|
401
|
-
> For components not wrapped by the engine (`Slider`, `CheckBox`, `Input`, `Select`, etc.), import directly from `@pixi/ui`.
|
|
395
|
+
> Built-in UI system with zero external dependencies. No `@pixi/ui`, `@pixi/layout`, or `yoga-layout` required. Import from `@energy8platform/game-engine/ui`.
|
|
402
396
|
|
|
403
|
-
###
|
|
397
|
+
### Asset Skinning (`ViewInput`)
|
|
398
|
+
|
|
399
|
+
Every visual component supports custom artwork via the `ViewInput` type:
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
type ViewInput = string | Texture | Container;
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
- `string` — texture name, resolved via `Sprite.from()` from the asset manager
|
|
406
|
+
- `Texture` — wrapped in a `Sprite`
|
|
407
|
+
- `Container` — used as-is (NineSliceSprite, AnimatedSprite, custom artwork, etc.)
|
|
408
|
+
|
|
409
|
+
If no custom view is provided, components fall back to Graphics-based rendering (colors, rounded rects). This means you can prototype with Graphics and later swap to production art with no API changes.
|
|
410
|
+
|
|
411
|
+
### FlexContainer
|
|
412
|
+
|
|
413
|
+
Lightweight flexbox-like layout container. Children added via `addChild()` automatically participate in flex layout.
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
const toolbar = new FlexContainer({
|
|
417
|
+
direction: 'row',
|
|
418
|
+
justifyContent: 'space-between',
|
|
419
|
+
alignItems: 'center',
|
|
420
|
+
gap: 16,
|
|
421
|
+
padding: 12,
|
|
422
|
+
});
|
|
423
|
+
toolbar.addChild(button1); // auto flex layout
|
|
424
|
+
toolbar.addChild(button2);
|
|
425
|
+
toolbar.addFlexChild(spacer, { flexGrow: 1 }); // with flex config
|
|
426
|
+
toolbar.resize(800, 60);
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**FlexItemConfig** — per-child options passed via `addFlexChild(child, config)` or JSX props:
|
|
404
430
|
|
|
405
|
-
|
|
431
|
+
| Property | Type | Default | Description |
|
|
432
|
+
| --- | --- | --- | --- |
|
|
433
|
+
| `flexGrow` | `number` | `0` | Flex grow factor |
|
|
434
|
+
| `flexShrink` | `number` | `1` | Flex shrink factor (`0` = don't shrink when content overflows) |
|
|
435
|
+
| `alignSelf` | `'auto' \| 'start' \| 'center' \| 'end' \| 'stretch'` | `'auto'` | Override parent's `alignItems` for this child |
|
|
436
|
+
| `flexExclude` | `boolean` | `false` | Exclude from flex layout (like `position: absolute`) |
|
|
437
|
+
| `layoutWidth` | `number` | — | Explicit width override for layout calculations |
|
|
438
|
+
| `layoutHeight` | `number` | — | Explicit height override for layout calculations |
|
|
406
439
|
|
|
407
440
|
```typescript
|
|
408
|
-
|
|
441
|
+
// Fixed item that won't shrink + centered override
|
|
442
|
+
toolbar.addFlexChild(logo, { flexShrink: 0 });
|
|
443
|
+
toolbar.addFlexChild(badge, { alignSelf: 'center' });
|
|
444
|
+
|
|
445
|
+
// Background excluded from layout flow
|
|
446
|
+
toolbar.addFlexChild(background, { flexExclude: true });
|
|
447
|
+
```
|
|
409
448
|
|
|
449
|
+
### Layout
|
|
450
|
+
|
|
451
|
+
Higher-level layout with direction presets (`horizontal`/`vertical`/`grid`/`wrap`), viewport anchoring, and responsive breakpoints. Wraps FlexContainer.
|
|
452
|
+
|
|
453
|
+
```typescript
|
|
410
454
|
const toolbar = new Layout({
|
|
411
455
|
direction: 'horizontal',
|
|
412
456
|
gap: 20,
|
|
@@ -422,9 +466,109 @@ toolbar.updateViewport(width, height);
|
|
|
422
466
|
|
|
423
467
|
**Anchors:** `top-left`, `top-center`, `top-right`, `center-left`, `center`, `center-right`, `bottom-left`, `bottom-center`, `bottom-right`
|
|
424
468
|
|
|
469
|
+
### Button
|
|
470
|
+
|
|
471
|
+
Per-state views with Tween animations. Each state accepts a `ViewInput` for full asset control:
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
// Graphics-based (prototyping)
|
|
475
|
+
const btn = new Button({
|
|
476
|
+
width: 200, height: 60, borderRadius: 12,
|
|
477
|
+
colors: { default: 0xffd700, hover: 0xffe44d, pressed: 0xccac00, disabled: 0x666666 },
|
|
478
|
+
text: 'SPIN',
|
|
479
|
+
onPress: () => spin(),
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
// Asset-based (production)
|
|
483
|
+
const btn = new Button({
|
|
484
|
+
defaultView: 'btn-idle', // texture name
|
|
485
|
+
hoverView: 'btn-hover',
|
|
486
|
+
pressedView: 'btn-pressed',
|
|
487
|
+
disabledView: 'btn-disabled',
|
|
488
|
+
text: 'SPIN',
|
|
489
|
+
onPress: () => spin(),
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
// NineSlice button
|
|
493
|
+
const btn = new Button({
|
|
494
|
+
defaultView: new NineSliceSprite({ texture: Texture.from('btn-9s'), leftWidth: 20, topHeight: 20, rightWidth: 20, bottomHeight: 20 }),
|
|
495
|
+
text: 'BET MAX',
|
|
496
|
+
});
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### ProgressBar
|
|
500
|
+
|
|
501
|
+
Animated fill bar with optional custom track/fill views:
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
// Graphics-based
|
|
505
|
+
const bar = new ProgressBar({ width: 400, height: 20, fillColor: 0x00ff00, animated: true });
|
|
506
|
+
bar.progress = 0.75;
|
|
507
|
+
bar.update(dt);
|
|
508
|
+
|
|
509
|
+
// Asset-based
|
|
510
|
+
const bar = new ProgressBar({
|
|
511
|
+
width: 400, height: 20,
|
|
512
|
+
trackView: 'bar-track', // texture name
|
|
513
|
+
fillView: new NineSliceSprite({ ... }), // or any Container
|
|
514
|
+
});
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### Slider
|
|
518
|
+
|
|
519
|
+
Draggable slider with customizable track, fill, and handle views:
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
// Graphics-based
|
|
523
|
+
const volume = new Slider({
|
|
524
|
+
min: 0, max: 1, value: 0.5, step: 0.1,
|
|
525
|
+
width: 200, height: 8,
|
|
526
|
+
fillColor: 0xffd700,
|
|
527
|
+
onUpdate: (v) => audio.setVolume('music', v),
|
|
528
|
+
onChange: (v) => console.log('Final:', v),
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
// Asset-based
|
|
532
|
+
const volume = new Slider({
|
|
533
|
+
min: 0, max: 1, value: 0.5,
|
|
534
|
+
width: 200, height: 8,
|
|
535
|
+
trackView: 'slider-track',
|
|
536
|
+
fillView: 'slider-fill',
|
|
537
|
+
handleView: 'slider-handle',
|
|
538
|
+
onUpdate: (v) => audio.setVolume('music', v),
|
|
539
|
+
});
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
`onUpdate` fires continuously during drag, `onChange` fires once when drag ends.
|
|
543
|
+
|
|
544
|
+
### Toggle
|
|
545
|
+
|
|
546
|
+
Two-state toggle switch with animation:
|
|
547
|
+
|
|
548
|
+
```typescript
|
|
549
|
+
// Graphics-based
|
|
550
|
+
const mute = new Toggle({
|
|
551
|
+
value: false,
|
|
552
|
+
width: 52, height: 28,
|
|
553
|
+
onColor: 0x22cc22, offColor: 0x666666,
|
|
554
|
+
onChange: (on) => audio.muteAll(!on),
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
// Asset-based (custom ON/OFF views with crossfade)
|
|
558
|
+
const ante = new Toggle({
|
|
559
|
+
value: false,
|
|
560
|
+
onView: 'toggle-on',
|
|
561
|
+
offView: 'toggle-off',
|
|
562
|
+
onChange: (on) => setAnteBet(on),
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
// Programmatic control
|
|
566
|
+
mute.forceSwitch(true);
|
|
567
|
+
```
|
|
568
|
+
|
|
425
569
|
### ScrollContainer
|
|
426
570
|
|
|
427
|
-
Touch/drag
|
|
571
|
+
Touch/drag scrolling with mouse wheel, inertia, and optional visual scrollbar:
|
|
428
572
|
|
|
429
573
|
```typescript
|
|
430
574
|
const scroll = new ScrollContainer({
|
|
@@ -432,66 +576,60 @@ const scroll = new ScrollContainer({
|
|
|
432
576
|
direction: 'vertical',
|
|
433
577
|
elementsMargin: 8,
|
|
434
578
|
backgroundColor: 0x1a1a2e,
|
|
579
|
+
scrollbar: true, // show scrollbar indicator
|
|
580
|
+
scrollbarColor: 0xaaaaaa, // or provide custom view:
|
|
581
|
+
// thumbView: 'scrollbar-thumb', // texture name, Texture, or Container
|
|
435
582
|
});
|
|
436
583
|
for (let i = 0; i < 50; i++) scroll.addItem(createRow(i));
|
|
437
584
|
```
|
|
438
585
|
|
|
439
|
-
###
|
|
586
|
+
### Panel
|
|
440
587
|
|
|
441
|
-
|
|
588
|
+
Background panel with FlexContainer content layout. Supports Graphics or 9-slice backgrounds:
|
|
442
589
|
|
|
443
590
|
```typescript
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
591
|
+
// Graphics background
|
|
592
|
+
const panel = new Panel({ width: 600, height: 400, backgroundColor: 0x1a1a2e, borderRadius: 16, padding: 16 });
|
|
593
|
+
panel.addContent(myLabel);
|
|
594
|
+
|
|
595
|
+
// 9-slice texture background
|
|
596
|
+
const panel = new Panel({
|
|
597
|
+
nineSliceTexture: 'panel-bg',
|
|
598
|
+
nineSliceBorders: [20, 20, 20, 20],
|
|
599
|
+
width: 600, height: 400, padding: 16,
|
|
450
600
|
});
|
|
451
|
-
spinBtn.onPress.connect(() => console.log('Spin!'));
|
|
452
|
-
spinBtn.disable();
|
|
453
|
-
spinBtn.enable();
|
|
454
601
|
```
|
|
455
602
|
|
|
456
603
|
### Other UI Components
|
|
457
604
|
|
|
458
|
-
**Label** — styled text
|
|
459
|
-
```typescript
|
|
460
|
-
new Label({ text: 'TOTAL WIN', style: { fontSize: 36, fill: 0xffffff } });
|
|
461
|
-
```
|
|
462
|
-
|
|
463
|
-
**BalanceDisplay** — animated currency display:
|
|
464
|
-
```typescript
|
|
465
|
-
const balance = new BalanceDisplay({ currency: 'USD', animated: true });
|
|
466
|
-
balance.setValue(9500);
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
**WinDisplay** — countup win animation:
|
|
605
|
+
**Label** — styled text with auto-fit and currency formatting:
|
|
470
606
|
```typescript
|
|
471
|
-
|
|
607
|
+
const label = new Label({ text: 'TOTAL WIN', style: { fontSize: 36, fill: 0xffffff }, maxWidth: 300, autoFit: true });
|
|
608
|
+
label.setCurrency(1500, 'USD'); // → "$1,500.00"
|
|
472
609
|
```
|
|
473
610
|
|
|
474
|
-
**
|
|
611
|
+
**BalanceDisplay** — animated currency countup/countdown:
|
|
475
612
|
```typescript
|
|
476
|
-
const
|
|
477
|
-
|
|
478
|
-
bar.update(dt); // call each frame for animation
|
|
613
|
+
const balance = new BalanceDisplay({ prefix: 'BALANCE', currency: 'USD', animated: true });
|
|
614
|
+
balance.setValue(9500); // smooth countup
|
|
479
615
|
```
|
|
480
616
|
|
|
481
|
-
**
|
|
617
|
+
**WinDisplay** — dramatic countup with scale pop:
|
|
482
618
|
```typescript
|
|
483
|
-
|
|
484
|
-
|
|
619
|
+
await winDisplay.showWin(5000);
|
|
620
|
+
winDisplay.hide();
|
|
485
621
|
```
|
|
486
622
|
|
|
487
|
-
**Modal** — full-screen overlay
|
|
623
|
+
**Modal** — full-screen overlay with enter/exit animations:
|
|
488
624
|
```typescript
|
|
489
625
|
const modal = new Modal({ overlayAlpha: 0.7, closeOnOverlay: true, animationDuration: 300 });
|
|
626
|
+
modal.content.addChild(settingsPanel);
|
|
490
627
|
await modal.show(viewWidth, viewHeight);
|
|
491
628
|
```
|
|
492
629
|
|
|
493
|
-
**Toast** —
|
|
630
|
+
**Toast** — transient notifications with optional custom background:
|
|
494
631
|
```typescript
|
|
632
|
+
const toast = new Toast({ duration: 3000, backgroundView: 'toast-bg' });
|
|
495
633
|
await toast.show('Free spins activated!', 'success', viewWidth, viewHeight);
|
|
496
634
|
```
|
|
497
635
|
|
|
@@ -533,7 +671,7 @@ export default defineGameConfig({
|
|
|
533
671
|
});
|
|
534
672
|
```
|
|
535
673
|
|
|
536
|
-
**What `defineGameConfig` provides:** ESNext build target
|
|
674
|
+
**What `defineGameConfig` provides:** ESNext build target, asset inlining (<8KB), PixiJS chunk splitting, DevBridge auto-injection in dev mode, dependency deduplication (`pixi.js`, `react`, etc.), and pre-bundling optimization.
|
|
537
675
|
|
|
538
676
|
---
|
|
539
677
|
|
|
@@ -686,42 +824,102 @@ bridge.destroy();
|
|
|
686
824
|
|
|
687
825
|
## React Integration
|
|
688
826
|
|
|
689
|
-
Built-in React reconciler for PixiJS. No `@pixi/react` needed — renders React trees directly into PixiJS Containers.
|
|
827
|
+
Built-in React reconciler for PixiJS. No `@pixi/react` needed — renders React trees directly into PixiJS Containers. All engine UI components work declaratively in JSX with full TypeScript autocompletion.
|
|
690
828
|
|
|
691
|
-
|
|
692
|
-
import { ReactScene, extendPixiElements, useSDK, useViewport, useBalance } from '@energy8platform/game-engine/react';
|
|
829
|
+
### Setup
|
|
693
830
|
|
|
694
|
-
|
|
831
|
+
```typescript
|
|
832
|
+
import { extendPixiElements, extendUIElements } from '@energy8platform/game-engine/react';
|
|
833
|
+
|
|
834
|
+
extendPixiElements(); // Container, Sprite, Text, Graphics, etc.
|
|
835
|
+
extendUIElements(); // Button, Label, FlexContainer, Panel, etc.
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
### ReactScene
|
|
839
|
+
|
|
840
|
+
```tsx
|
|
841
|
+
import { ReactScene, useEngine, useBalance } from '@energy8platform/game-engine/react';
|
|
842
|
+
import { useState } from 'react';
|
|
695
843
|
|
|
696
|
-
export class
|
|
697
|
-
render() { return <
|
|
844
|
+
export class SlotScene extends ReactScene {
|
|
845
|
+
render() { return <SlotUI />; }
|
|
698
846
|
}
|
|
699
847
|
|
|
700
|
-
function
|
|
701
|
-
const {
|
|
848
|
+
function SlotUI() {
|
|
849
|
+
const { screen } = useEngine();
|
|
702
850
|
const balance = useBalance();
|
|
703
|
-
const
|
|
851
|
+
const [bet, setBet] = useState(1);
|
|
704
852
|
|
|
705
853
|
return (
|
|
706
|
-
<
|
|
707
|
-
|
|
708
|
-
<
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
854
|
+
<flexContainer direction="column" width={screen.width} height={screen.height} padding={20}>
|
|
855
|
+
{/* Top bar */}
|
|
856
|
+
<flexContainer direction="row" justifyContent="space-between" alignItems="center">
|
|
857
|
+
<balanceDisplay currency="USD" animated value={balance} />
|
|
858
|
+
<label text={`BET: $${bet.toFixed(2)}`} style-fontSize={18} style-fill={0xcccccc} />
|
|
859
|
+
</flexContainer>
|
|
860
|
+
|
|
861
|
+
{/* Controls */}
|
|
862
|
+
<flexContainer direction="row" justifyContent="center" gap={12} alignItems="center">
|
|
863
|
+
<button width={50} height={50} borderRadius={25} text="-"
|
|
864
|
+
colors-default={0x444444}
|
|
865
|
+
onPress={() => setBet(b => Math.max(0.2, b - 0.5))} />
|
|
866
|
+
<button width={140} height={60} borderRadius={30} text="SPIN"
|
|
867
|
+
colors-default={0x22aa44} colors-hover={0x33cc55}
|
|
868
|
+
onPress={() => { /* spin */ }} />
|
|
869
|
+
<button width={50} height={50} borderRadius={25} text="+"
|
|
870
|
+
colors-default={0x444444}
|
|
871
|
+
onPress={() => setBet(b => b + 0.5)} />
|
|
872
|
+
</flexContainer>
|
|
873
|
+
</flexContainer>
|
|
716
874
|
);
|
|
717
875
|
}
|
|
718
876
|
```
|
|
719
877
|
|
|
878
|
+
### Declarative UI Components
|
|
879
|
+
|
|
880
|
+
All engine UI components are config-based: the reconciler passes JSX props as a config object to the constructor, and calls `updateConfig()` on prop changes. Children of `<flexContainer>`, `<panel>`, and `<scrollContainer>` automatically participate in their layout system.
|
|
881
|
+
|
|
882
|
+
```tsx
|
|
883
|
+
{/* Asset-skinned button */}
|
|
884
|
+
<button defaultView="btn-idle" hoverView="btn-hover" text="SPIN" onPress={handler} />
|
|
885
|
+
|
|
886
|
+
{/* Panel with 9-slice background */}
|
|
887
|
+
<panel nineSliceTexture="panel-bg" nineSliceBorders={[20,20,20,20]} width={400} height={300}>
|
|
888
|
+
<label text="Settings" style-fontSize={24} />
|
|
889
|
+
</panel>
|
|
890
|
+
|
|
891
|
+
{/* Progress bar with custom track/fill */}
|
|
892
|
+
<progressBar trackView="bar-track" fillView="bar-fill" progress={0.75} width={300} height={20} />
|
|
893
|
+
|
|
894
|
+
{/* Scrollable list */}
|
|
895
|
+
<scrollContainer width={500} height={400} direction="vertical" scrollbar elementsMargin={8}>
|
|
896
|
+
<label text="Item 1" />
|
|
897
|
+
<label text="Item 2" />
|
|
898
|
+
</scrollContainer>
|
|
899
|
+
|
|
900
|
+
{/* Slider */}
|
|
901
|
+
<slider min={0} max={1} value={volume} width={200} height={8}
|
|
902
|
+
fillColor={0xffd700} onUpdate={setVolume} />
|
|
903
|
+
|
|
904
|
+
{/* Toggle */}
|
|
905
|
+
<toggle value={isMuted} onColor={0x22cc22} onChange={setIsMuted} />
|
|
906
|
+
|
|
907
|
+
{/* Flex item props — work on any element inside <flexContainer> */}
|
|
908
|
+
<flexContainer direction="row" width={800} height={60}>
|
|
909
|
+
<graphics draw={drawBg} flexExclude /> {/* excluded from flow */}
|
|
910
|
+
<label text="Logo" flexShrink={0} /> {/* won't shrink */}
|
|
911
|
+
<container flexGrow={1} /> {/* fills remaining space */}
|
|
912
|
+
<button text="Menu" alignSelf="center" /> {/* centered on cross-axis */}
|
|
913
|
+
</flexContainer>
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
**Dash-notation** for nested config: `colors-default={0xff0000}` → `{ colors: { default: 0xff0000 } }`, `style-fontSize={24}` → `{ style: { fontSize: 24 } }`.
|
|
917
|
+
|
|
720
918
|
### Hooks
|
|
721
919
|
|
|
722
920
|
| Hook | Returns | Description |
|
|
723
921
|
| --- | --- | --- |
|
|
724
|
-
| `useEngine()` | `EngineContextValue` | Full engine context |
|
|
922
|
+
| `useEngine()` | `EngineContextValue` | Full engine context (app, sdk, audio, screen, etc.) |
|
|
725
923
|
| `useSDK()` | `CasinoGameSDK \| null` | SDK instance |
|
|
726
924
|
| `useAudio()` | `AudioManager` | Audio manager |
|
|
727
925
|
| `useInput()` | `InputManager` | Input manager |
|
|
@@ -733,18 +931,18 @@ function GameRoot() {
|
|
|
733
931
|
### Element Registration
|
|
734
932
|
|
|
735
933
|
```typescript
|
|
736
|
-
import { extendPixiElements,
|
|
934
|
+
import { extendPixiElements, extendUIElements, extendCustomElements } from '@energy8platform/game-engine/react';
|
|
737
935
|
|
|
738
|
-
extendPixiElements();
|
|
739
|
-
|
|
740
|
-
|
|
936
|
+
extendPixiElements(); // Container, Sprite, Text, Graphics, AnimatedSprite, etc.
|
|
937
|
+
extendUIElements(); // Button, Label, FlexContainer, Panel, ProgressBar, etc.
|
|
938
|
+
extendCustomElements({ MyWidget }); // your own classes
|
|
741
939
|
```
|
|
742
940
|
|
|
743
|
-
After registration, use as lowercase JSX: `<container>`, `<sprite>`, `<text>`, `<graphics>`, `<button
|
|
941
|
+
After registration, use as lowercase JSX: `<container>`, `<sprite>`, `<text>`, `<graphics>`, `<button>`, `<flexContainer>`, `<panel>`, etc.
|
|
744
942
|
|
|
745
|
-
**Props:** Regular props set directly (`alpha`, `visible`, `scale`). Nested via dash: `position-x`, `scale-y`. Events: `onClick
|
|
943
|
+
**Props:** Regular props set directly (`alpha`, `visible`, `scale`). Nested via dash: `position-x`, `scale-y`, `colors-default`. Events: `onClick`, `onPointerDown`, `onPress` (Button).
|
|
746
944
|
|
|
747
|
-
> React is entirely optional. Imperative (`Scene`) and React (`ReactScene`) scenes can coexist.
|
|
945
|
+
> React is entirely optional. Imperative (`Scene`) and React (`ReactScene`) scenes can coexist in the same game.
|
|
748
946
|
|
|
749
947
|
---
|
|
750
948
|
|