canvasengine 1.3.0 → 2.0.1-beta.1
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/.cursorrules +0 -0
- package/.github/workflows/ci.yml +29 -0
- package/README.md +79 -0
- package/dist/compiler/vite.js +119 -0
- package/dist/compiler/vite.js.map +1 -0
- package/dist/index.d.ts +846 -0
- package/dist/index.js +3340 -0
- package/dist/index.js.map +1 -0
- package/index.d.ts +6 -0
- package/logo.png +0 -0
- package/package.json +84 -18
- package/src/compiler/grammar.pegjs +180 -0
- package/src/compiler/vite.ts +166 -0
- package/src/components/Canvas.ts +134 -0
- package/src/components/Container.ts +46 -0
- package/src/components/DisplayObject.ts +458 -0
- package/src/components/DrawMap/index.ts +65 -0
- package/src/components/Graphic.ts +147 -0
- package/src/components/NineSliceSprite.ts +46 -0
- package/src/components/ParticleEmitter.ts +39 -0
- package/src/components/Scene.ts +6 -0
- package/src/components/Sprite.ts +493 -0
- package/src/components/Text.ts +145 -0
- package/src/components/Tilemap/Tile.ts +79 -0
- package/src/components/Tilemap/TileGroup.ts +207 -0
- package/src/components/Tilemap/TileLayer.ts +163 -0
- package/src/components/Tilemap/TileSet.ts +41 -0
- package/src/components/Tilemap/index.ts +80 -0
- package/src/components/TilingSprite.ts +39 -0
- package/src/components/Viewport.ts +159 -0
- package/src/components/index.ts +12 -0
- package/src/components/types/DisplayObject.ts +68 -0
- package/src/components/types/MouseEvent.ts +3 -0
- package/src/components/types/Spritesheet.ts +389 -0
- package/src/components/types/index.ts +4 -0
- package/src/directives/Drag.ts +84 -0
- package/src/directives/KeyboardControls.ts +922 -0
- package/src/directives/Scheduler.ts +112 -0
- package/src/directives/Sound.ts +91 -0
- package/src/directives/Transition.ts +45 -0
- package/src/directives/ViewportCull.ts +40 -0
- package/src/directives/ViewportFollow.ts +26 -0
- package/src/directives/index.ts +7 -0
- package/src/engine/animation.ts +113 -0
- package/src/engine/bootstrap.ts +19 -0
- package/src/engine/directive.ts +23 -0
- package/src/engine/reactive.ts +379 -0
- package/src/engine/signal.ts +138 -0
- package/src/engine/trigger.ts +40 -0
- package/src/engine/utils.ts +135 -0
- package/src/hooks/addContext.ts +6 -0
- package/src/hooks/useProps.ts +155 -0
- package/src/hooks/useRef.ts +21 -0
- package/src/index.ts +14 -0
- package/src/presets/Bar.ts +89 -0
- package/src/presets/Button.ts +0 -0
- package/src/presets/Joystick.ts +286 -0
- package/src/presets/NightAmbiant.ts +122 -0
- package/src/presets/Particle.ts +53 -0
- package/src/utils/Ease.ts +33 -0
- package/src/utils/RadialGradient.ts +86 -0
- package/starter/assets/logo.png +0 -0
- package/starter/components/app.ce +18 -0
- package/starter/components/hello.ce +35 -0
- package/starter/index.html +21 -0
- package/starter/main.ts +6 -0
- package/starter/package.json +20 -0
- package/starter/tsconfig.json +32 -0
- package/starter/vite.config.ts +12 -0
- package/tsconfig.json +32 -0
- package/tsconfig.node.json +10 -0
- package/tsup.config.ts +28 -0
- package/vitest.config.ts +12 -0
- package/.gitattributes +0 -22
- package/.npmignore +0 -163
- package/canvasengine-1.3.0.all.min.js +0 -21
- package/canvasengine.js +0 -5802
- package/core/DB.js +0 -24
- package/core/ModelServer.js +0 -348
- package/core/Users.js +0 -190
- package/core/engine-common.js +0 -952
- package/doc/cocoonjs.md +0 -36
- package/doc/doc-lang.yml +0 -43
- package/doc/doc-router.yml +0 -14
- package/doc/doc-tuto.yml +0 -9
- package/doc/doc.yml +0 -39
- package/doc/element.md +0 -37
- package/doc/entity.md +0 -90
- package/doc/extend.md +0 -47
- package/doc/get_started.md +0 -19
- package/doc/images/entity.png +0 -0
- package/doc/multitouch.md +0 -58
- package/doc/nodejs.md +0 -142
- package/doc/scene.md +0 -44
- package/doc/text.md +0 -156
- package/examples/server/client.html +0 -31
- package/examples/server/server.js +0 -16
- package/examples/tiled_server/client.html +0 -52
- package/examples/tiled_server/images/tiles_spritesheet.png +0 -0
- package/examples/tiled_server/server/map.json +0 -50
- package/examples/tiled_server/server/map.tmx +0 -16
- package/examples/tiled_server/server/server.js +0 -16
- package/extends/Animation.js +0 -910
- package/extends/Effect.js +0 -252
- package/extends/Gleed2d.js +0 -252
- package/extends/Hit.js +0 -1509
- package/extends/Input.js +0 -699
- package/extends/Marshal.js +0 -716
- package/extends/Scrolling.js +0 -388
- package/extends/Soundmanager2.js +0 -5466
- package/extends/Spritesheet.js +0 -196
- package/extends/Text.js +0 -366
- package/extends/Tiled.js +0 -403
- package/extends/Window.js +0 -575
- package/extends/gamepad.js +0 -397
- package/extends/socket.io.min.js +0 -2
- package/extends/swf/soundmanager2.swf +0 -0
- package/extends/swf/soundmanager2_debug.swf +0 -0
- package/extends/swf/soundmanager2_flash9.swf +0 -0
- package/extends/swf/soundmanager2_flash9_debug.swf +0 -0
- package/extends/swf/soundmanager2_flash_xdomain.zip +0 -0
- package/extends/workers/transition.js +0 -43
- package/index.js +0 -46
- package/license.txt +0 -19
- package/readme.md +0 -483
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { isSignal, signal } from "@signe/reactive"
|
|
2
|
+
import { isPrimitive } from "../engine/reactive"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Converts props into reactive signals if they are primitive values.
|
|
6
|
+
*
|
|
7
|
+
* @param {object} props - The properties to convert.
|
|
8
|
+
* @param {object} [defaults={}] - Default values for properties.
|
|
9
|
+
* @returns {object} An object with reactive signals.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const props = useProps({ count: 0, name: "John" });
|
|
13
|
+
* console.log(props.count()); // 0
|
|
14
|
+
* props.count.set(1);
|
|
15
|
+
* console.log(props.count()); // 1
|
|
16
|
+
*/
|
|
17
|
+
export const useProps = (props, defaults = {}): any => {
|
|
18
|
+
if (isSignal(props)) {
|
|
19
|
+
return props()
|
|
20
|
+
}
|
|
21
|
+
const obj = {}
|
|
22
|
+
for (let key in props) {
|
|
23
|
+
const value = props[key]
|
|
24
|
+
obj[key] = isPrimitive(value) ? signal(value) : value
|
|
25
|
+
}
|
|
26
|
+
for (let key in defaults) {
|
|
27
|
+
if (!(key in obj)) {
|
|
28
|
+
obj[key] = signal(defaults[key])
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return obj
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type PropType = NumberConstructor | StringConstructor | BooleanConstructor |
|
|
35
|
+
FunctionConstructor | ObjectConstructor | ArrayConstructor |
|
|
36
|
+
null | (new (...args: any[]) => any);
|
|
37
|
+
|
|
38
|
+
interface PropConfig {
|
|
39
|
+
type?: PropType | PropType[];
|
|
40
|
+
required?: boolean;
|
|
41
|
+
default?: any | ((props: any) => any);
|
|
42
|
+
validator?: (value: any, props: any) => boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type PropSchema = {
|
|
46
|
+
[key: string]: PropType | PropType[] | PropConfig;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Validates and defines properties based on a schema.
|
|
51
|
+
*
|
|
52
|
+
* @param {object} props - The properties to validate.
|
|
53
|
+
* @returns {function} A function that takes a schema and returns validated properties.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* const schema = {
|
|
57
|
+
* age: { type: Number, required: true },
|
|
58
|
+
* name: { type: String, default: "Anonymous" }
|
|
59
|
+
* };
|
|
60
|
+
* const validatedProps = useDefineProps({ age: 25 })(schema);
|
|
61
|
+
* console.log(validatedProps.age()); // 25
|
|
62
|
+
* console.log(validatedProps.name()); // "Anonymous"
|
|
63
|
+
*/
|
|
64
|
+
export const useDefineProps = (props: any) => {
|
|
65
|
+
return (schema?: PropSchema) => {
|
|
66
|
+
const rawProps = isSignal(props) ? props() : props
|
|
67
|
+
const validatedProps: { [key: string]: any } = {}
|
|
68
|
+
|
|
69
|
+
for (const key in schema) {
|
|
70
|
+
const propConfig = schema[key]
|
|
71
|
+
const value = rawProps[key]
|
|
72
|
+
let validatedValue: any
|
|
73
|
+
|
|
74
|
+
// Handle simple type definition
|
|
75
|
+
if (typeof propConfig === 'function') {
|
|
76
|
+
validateType(key, value, [propConfig])
|
|
77
|
+
validatedValue = value
|
|
78
|
+
}
|
|
79
|
+
// Handle array of types
|
|
80
|
+
else if (Array.isArray(propConfig)) {
|
|
81
|
+
validateType(key, value, propConfig)
|
|
82
|
+
validatedValue = value
|
|
83
|
+
}
|
|
84
|
+
// Handle detailed configuration object
|
|
85
|
+
else if (propConfig && typeof propConfig === 'object') {
|
|
86
|
+
// Check required prop
|
|
87
|
+
if (propConfig.required && value === undefined) {
|
|
88
|
+
throw new Error(`Missing required prop: ${key}`)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Validate type if specified
|
|
92
|
+
if (propConfig.type) {
|
|
93
|
+
const types = Array.isArray(propConfig.type) ? propConfig.type : [propConfig.type]
|
|
94
|
+
validateType(key, value, types)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Run custom validator if provided
|
|
98
|
+
if (propConfig.validator && !propConfig.validator(value, rawProps)) {
|
|
99
|
+
throw new Error(`Invalid prop: custom validation failed for prop "${key}"`)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Set default value if value is undefined
|
|
103
|
+
if (value === undefined && 'default' in propConfig) {
|
|
104
|
+
validatedValue = typeof propConfig.default === 'function'
|
|
105
|
+
? propConfig.default(rawProps)
|
|
106
|
+
: propConfig.default
|
|
107
|
+
} else {
|
|
108
|
+
validatedValue = value
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
validatedProps[key] = isSignal(validatedValue)
|
|
113
|
+
? validatedValue
|
|
114
|
+
: signal(validatedValue)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
...useProps(rawProps),
|
|
119
|
+
...validatedProps
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Validates the type of a property.
|
|
126
|
+
*
|
|
127
|
+
* @param {string} key - The property key.
|
|
128
|
+
* @param {any} value - The property value.
|
|
129
|
+
* @param {any[]} types - The expected types.
|
|
130
|
+
* @throws Will throw an error if the type check fails.
|
|
131
|
+
*/
|
|
132
|
+
function validateType(key: string, value: any, types: any[]) {
|
|
133
|
+
if (value === undefined || value === null) return
|
|
134
|
+
|
|
135
|
+
// Si c'est un signal, on vérifie la valeur du signal
|
|
136
|
+
const valueToCheck = isSignal(value) ? value() : value
|
|
137
|
+
|
|
138
|
+
const valid = types.some(type => {
|
|
139
|
+
if (type === Number) return typeof valueToCheck === 'number'
|
|
140
|
+
if (type === String) return typeof valueToCheck === 'string'
|
|
141
|
+
if (type === Boolean) return typeof valueToCheck === 'boolean'
|
|
142
|
+
if (type === Function) return typeof valueToCheck === 'function'
|
|
143
|
+
if (type === Object) return typeof valueToCheck === 'object'
|
|
144
|
+
if (type === Array) return Array.isArray(valueToCheck)
|
|
145
|
+
if (type === null) return valueToCheck === null
|
|
146
|
+
return valueToCheck instanceof type
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
if (!valid) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
`Invalid prop: type check failed for prop "${key}". ` +
|
|
152
|
+
`Expected ${types.map(t => t.name).join(' or ')}`
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Element } from "../engine/reactive";
|
|
2
|
+
import { ComponentInstance } from "../components/DisplayObject";
|
|
3
|
+
|
|
4
|
+
export function useRef(element: Element<ComponentInstance>, ref: string): Element<ComponentInstance> | null {
|
|
5
|
+
const { props } = element;
|
|
6
|
+
if (props.ref == ref) {
|
|
7
|
+
return element;
|
|
8
|
+
}
|
|
9
|
+
// Recursive search for the component with the given id
|
|
10
|
+
if (props.children) {
|
|
11
|
+
for (const child of props.children) {
|
|
12
|
+
const result = useRef(child, ref);
|
|
13
|
+
if (result) {
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// If not found, return undefined
|
|
20
|
+
return null;
|
|
21
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import './directives'
|
|
2
|
+
export * from '@signe/reactive'
|
|
3
|
+
export { Howler } from 'howler'
|
|
4
|
+
export * from './components'
|
|
5
|
+
export * from './engine/reactive'
|
|
6
|
+
export * from './engine/signal'
|
|
7
|
+
export * from './engine/trigger'
|
|
8
|
+
export * from './engine/bootstrap'
|
|
9
|
+
export * from './engine/animation'
|
|
10
|
+
export { useProps, useDefineProps } from './hooks/useProps'
|
|
11
|
+
|
|
12
|
+
export * from './presets/Bar'
|
|
13
|
+
export * from './presets/Particle'
|
|
14
|
+
export * from './utils/Ease'
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Graphics } from "../components";
|
|
2
|
+
import { h } from "../engine/signal";
|
|
3
|
+
import * as PIXI from "pixi.js";
|
|
4
|
+
import { useProps } from "../hooks/useProps";
|
|
5
|
+
|
|
6
|
+
interface BarProps {
|
|
7
|
+
backgroundColor?: string;
|
|
8
|
+
foregroundColor?: string;
|
|
9
|
+
value: number;
|
|
10
|
+
maxValue: number;
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function componentToHex(c) {
|
|
16
|
+
var hex = c.toString(16);
|
|
17
|
+
return hex.length == 1 ? "0" + hex : hex;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function rgbToHex(r, g, b) {
|
|
21
|
+
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function Bar(opts: BarProps) {
|
|
25
|
+
const {
|
|
26
|
+
width,
|
|
27
|
+
height,
|
|
28
|
+
value,
|
|
29
|
+
maxValue,
|
|
30
|
+
backgroundColor,
|
|
31
|
+
foregroundColor,
|
|
32
|
+
border,
|
|
33
|
+
innerMargin,
|
|
34
|
+
borderRadius,
|
|
35
|
+
} = useProps(opts, {
|
|
36
|
+
backgroundColor: "#000000",
|
|
37
|
+
foregroundColor: "#FFFFFF",
|
|
38
|
+
innerMargin: 0,
|
|
39
|
+
borderRadius: 0,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return h(
|
|
43
|
+
Graphics,
|
|
44
|
+
{
|
|
45
|
+
...opts,
|
|
46
|
+
width,
|
|
47
|
+
height,
|
|
48
|
+
draw(g: PIXI.Graphics) {
|
|
49
|
+
if (borderRadius()) {
|
|
50
|
+
g.roundRect(0, 0, width(), height(), borderRadius());
|
|
51
|
+
} else {
|
|
52
|
+
g.rect(0, 0, width(), height());
|
|
53
|
+
}
|
|
54
|
+
if (border) {
|
|
55
|
+
g.stroke(border);
|
|
56
|
+
}
|
|
57
|
+
g.fill(backgroundColor());
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
h(Graphics, {
|
|
61
|
+
width,
|
|
62
|
+
height,
|
|
63
|
+
draw(g: PIXI.Graphics) {
|
|
64
|
+
const margin = innerMargin();
|
|
65
|
+
const _borderRadius = borderRadius();
|
|
66
|
+
const w = Math.max(
|
|
67
|
+
0,
|
|
68
|
+
Math.min(
|
|
69
|
+
width() - 2 * margin,
|
|
70
|
+
(value() / maxValue()) * (width() - 2 * margin)
|
|
71
|
+
)
|
|
72
|
+
);
|
|
73
|
+
const h = height() - 2 * margin;
|
|
74
|
+
if (borderRadius) {
|
|
75
|
+
g.roundRect(margin, margin, w, h, _borderRadius);
|
|
76
|
+
} else {
|
|
77
|
+
g.rect(margin, margin, w, h);
|
|
78
|
+
}
|
|
79
|
+
const color = foregroundColor();
|
|
80
|
+
if (color.startsWith("rgba")) {
|
|
81
|
+
const [r, g, b, a] = color.match(/\d+(\.\d+)?/g).map(Number);
|
|
82
|
+
g.fill({ color: rgbToHex(r, g, b), alpha: a });
|
|
83
|
+
} else {
|
|
84
|
+
g.fill(color);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
})
|
|
88
|
+
);
|
|
89
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Joystick
|
|
3
|
+
*
|
|
4
|
+
* Inspired by https://github.com/endel/pixi-virtual-joystick
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as PIXI from "pixi.js";
|
|
8
|
+
import { Container, Graphics, Sprite } from "../components";
|
|
9
|
+
import { h } from "../engine/signal";
|
|
10
|
+
import { signal } from "@signe/reactive";
|
|
11
|
+
|
|
12
|
+
export interface JoystickChangeEvent {
|
|
13
|
+
angle: number;
|
|
14
|
+
direction: Direction;
|
|
15
|
+
power: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export enum Direction {
|
|
19
|
+
LEFT = "left",
|
|
20
|
+
TOP = "top",
|
|
21
|
+
BOTTOM = "bottom",
|
|
22
|
+
RIGHT = "right",
|
|
23
|
+
TOP_LEFT = "top_left",
|
|
24
|
+
TOP_RIGHT = "top_right",
|
|
25
|
+
BOTTOM_LEFT = "bottom_left",
|
|
26
|
+
BOTTOM_RIGHT = "bottom_right",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface JoystickSettings {
|
|
30
|
+
outer?: string;
|
|
31
|
+
inner?: string;
|
|
32
|
+
outerScale?: { x: number; y: number };
|
|
33
|
+
innerScale?: { x: number; y: number };
|
|
34
|
+
onChange?: (data: JoystickChangeEvent) => void;
|
|
35
|
+
onStart?: () => void;
|
|
36
|
+
onEnd?: () => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function Joystick(opts: JoystickSettings = {}) {
|
|
40
|
+
const settings = Object.assign(
|
|
41
|
+
{
|
|
42
|
+
outerScale: { x: 1, y: 1 },
|
|
43
|
+
innerScale: { x: 1, y: 1 },
|
|
44
|
+
},
|
|
45
|
+
opts
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
let outerRadius = 70;
|
|
49
|
+
let innerRadius = 10;
|
|
50
|
+
const innerAlphaStandby = 0.5;
|
|
51
|
+
|
|
52
|
+
let dragging = false;
|
|
53
|
+
let startPosition: PIXI.PointData | null = null;
|
|
54
|
+
let power = 0;
|
|
55
|
+
|
|
56
|
+
const innerPositionX = signal(0);
|
|
57
|
+
const innerPositionY = signal(0);
|
|
58
|
+
const innerAlpha = signal(innerAlphaStandby);
|
|
59
|
+
|
|
60
|
+
function getPower(centerPoint: PIXI.Point) {
|
|
61
|
+
const a = centerPoint.x - 0;
|
|
62
|
+
const b = centerPoint.y - 0;
|
|
63
|
+
return Math.min(1, Math.sqrt(a * a + b * b) / outerRadius);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getDirection(center: PIXI.Point) {
|
|
67
|
+
let rad = Math.atan2(center.y, center.x); // [-PI, PI]
|
|
68
|
+
if ((rad >= -Math.PI / 8 && rad < 0) || (rad >= 0 && rad < Math.PI / 8)) {
|
|
69
|
+
return Direction.RIGHT;
|
|
70
|
+
} else if (rad >= Math.PI / 8 && rad < (3 * Math.PI) / 8) {
|
|
71
|
+
return Direction.BOTTOM_RIGHT;
|
|
72
|
+
} else if (rad >= (3 * Math.PI) / 8 && rad < (5 * Math.PI) / 8) {
|
|
73
|
+
return Direction.BOTTOM;
|
|
74
|
+
} else if (rad >= (5 * Math.PI) / 8 && rad < (7 * Math.PI) / 8) {
|
|
75
|
+
return Direction.BOTTOM_LEFT;
|
|
76
|
+
} else if (
|
|
77
|
+
(rad >= (7 * Math.PI) / 8 && rad < Math.PI) ||
|
|
78
|
+
(rad >= -Math.PI && rad < (-7 * Math.PI) / 8)
|
|
79
|
+
) {
|
|
80
|
+
return Direction.LEFT;
|
|
81
|
+
} else if (rad >= (-7 * Math.PI) / 8 && rad < (-5 * Math.PI) / 8) {
|
|
82
|
+
return Direction.TOP_LEFT;
|
|
83
|
+
} else if (rad >= (-5 * Math.PI) / 8 && rad < (-3 * Math.PI) / 8) {
|
|
84
|
+
return Direction.TOP;
|
|
85
|
+
} else {
|
|
86
|
+
return Direction.TOP_RIGHT;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function handleDragStart(event: PIXI.FederatedPointerEvent) {
|
|
91
|
+
startPosition = event.getLocalPosition(this);
|
|
92
|
+
dragging = true;
|
|
93
|
+
innerAlpha.set(1);
|
|
94
|
+
settings.onStart?.();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function handleDragEnd() {
|
|
98
|
+
if (!dragging) return;
|
|
99
|
+
innerPositionX.set(0);
|
|
100
|
+
innerPositionY.set(0);
|
|
101
|
+
dragging = false;
|
|
102
|
+
innerAlpha.set(innerAlphaStandby);
|
|
103
|
+
settings.onEnd?.();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function handleDragMove(event: PIXI.FederatedPointerEvent) {
|
|
107
|
+
if (dragging == false) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let newPosition = event.getLocalPosition(this);
|
|
112
|
+
|
|
113
|
+
let sideX = newPosition.x - (startPosition?.x ?? 0);
|
|
114
|
+
let sideY = newPosition.y - (startPosition?.y ?? 0);
|
|
115
|
+
|
|
116
|
+
let centerPoint = new PIXI.Point(0, 0);
|
|
117
|
+
let angle = 0;
|
|
118
|
+
|
|
119
|
+
if (sideX == 0 && sideY == 0) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let calRadius = 0;
|
|
124
|
+
|
|
125
|
+
if (sideX * sideX + sideY * sideY >= outerRadius * outerRadius) {
|
|
126
|
+
calRadius = outerRadius;
|
|
127
|
+
} else {
|
|
128
|
+
calRadius = outerRadius - innerRadius;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* x: -1 <-> 1
|
|
133
|
+
* y: -1 <-> 1
|
|
134
|
+
* Y
|
|
135
|
+
* ^
|
|
136
|
+
* |
|
|
137
|
+
* 180 | 90
|
|
138
|
+
* ------------> X
|
|
139
|
+
* 270 | 360
|
|
140
|
+
* |
|
|
141
|
+
* |
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
let direction = Direction.LEFT;
|
|
145
|
+
|
|
146
|
+
if (sideX == 0) {
|
|
147
|
+
if (sideY > 0) {
|
|
148
|
+
centerPoint.set(0, sideY > outerRadius ? outerRadius : sideY);
|
|
149
|
+
angle = 270;
|
|
150
|
+
direction = Direction.BOTTOM;
|
|
151
|
+
} else {
|
|
152
|
+
centerPoint.set(
|
|
153
|
+
0,
|
|
154
|
+
-(Math.abs(sideY) > outerRadius ? outerRadius : Math.abs(sideY))
|
|
155
|
+
);
|
|
156
|
+
angle = 90;
|
|
157
|
+
direction = Direction.TOP;
|
|
158
|
+
}
|
|
159
|
+
innerPositionX.set(centerPoint.x);
|
|
160
|
+
innerPositionY.set(centerPoint.y);
|
|
161
|
+
power = getPower(centerPoint);
|
|
162
|
+
settings.onChange?.({ angle, direction, power });
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (sideY == 0) {
|
|
167
|
+
if (sideX > 0) {
|
|
168
|
+
centerPoint.set(
|
|
169
|
+
Math.abs(sideX) > outerRadius ? outerRadius : Math.abs(sideX),
|
|
170
|
+
0
|
|
171
|
+
);
|
|
172
|
+
angle = 0;
|
|
173
|
+
direction = Direction.LEFT;
|
|
174
|
+
} else {
|
|
175
|
+
centerPoint.set(
|
|
176
|
+
-(Math.abs(sideX) > outerRadius ? outerRadius : Math.abs(sideX)),
|
|
177
|
+
0
|
|
178
|
+
);
|
|
179
|
+
angle = 180;
|
|
180
|
+
direction = Direction.RIGHT;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
innerPositionX.set(centerPoint.x);
|
|
184
|
+
innerPositionY.set(centerPoint.y);
|
|
185
|
+
power = getPower(centerPoint);
|
|
186
|
+
settings.onChange?.({ angle, direction, power });
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
let tanVal = Math.abs(sideY / sideX);
|
|
191
|
+
let radian = Math.atan(tanVal);
|
|
192
|
+
angle = (radian * 180) / Math.PI;
|
|
193
|
+
|
|
194
|
+
let centerX = 0;
|
|
195
|
+
let centerY = 0;
|
|
196
|
+
|
|
197
|
+
if (sideX * sideX + sideY * sideY >= outerRadius * outerRadius) {
|
|
198
|
+
centerX = outerRadius * Math.cos(radian);
|
|
199
|
+
centerY = outerRadius * Math.sin(radian);
|
|
200
|
+
} else {
|
|
201
|
+
centerX = Math.abs(sideX) > outerRadius ? outerRadius : Math.abs(sideX);
|
|
202
|
+
centerY = Math.abs(sideY) > outerRadius ? outerRadius : Math.abs(sideY);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (sideY < 0) {
|
|
206
|
+
centerY = -Math.abs(centerY);
|
|
207
|
+
}
|
|
208
|
+
if (sideX < 0) {
|
|
209
|
+
centerX = -Math.abs(centerX);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (sideX > 0 && sideY < 0) {
|
|
213
|
+
// < 90
|
|
214
|
+
} else if (sideX < 0 && sideY < 0) {
|
|
215
|
+
// 90 ~ 180
|
|
216
|
+
angle = 180 - angle;
|
|
217
|
+
} else if (sideX < 0 && sideY > 0) {
|
|
218
|
+
// 180 ~ 270
|
|
219
|
+
angle = angle + 180;
|
|
220
|
+
} else if (sideX > 0 && sideY > 0) {
|
|
221
|
+
// 270 ~ 369
|
|
222
|
+
angle = 360 - angle;
|
|
223
|
+
}
|
|
224
|
+
centerPoint.set(centerX, centerY);
|
|
225
|
+
power = getPower(centerPoint);
|
|
226
|
+
|
|
227
|
+
direction = getDirection(centerPoint);
|
|
228
|
+
innerPositionX.set(centerPoint.x);
|
|
229
|
+
innerPositionY.set(centerPoint.y);
|
|
230
|
+
|
|
231
|
+
settings.onChange?.({ angle, direction, power });
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
let innerElement;
|
|
235
|
+
let outerElement;
|
|
236
|
+
|
|
237
|
+
if (!settings.outer) {
|
|
238
|
+
outerElement = h(Graphics, {
|
|
239
|
+
draw: (g) => {
|
|
240
|
+
g.circle(0, 0, outerRadius).fill(0x000000);
|
|
241
|
+
},
|
|
242
|
+
alpha: 0.5,
|
|
243
|
+
});
|
|
244
|
+
} else {
|
|
245
|
+
outerElement = h(Sprite, {
|
|
246
|
+
image: settings.outer,
|
|
247
|
+
anchor: { x: 0.5, y: 0.5 },
|
|
248
|
+
scale: settings.outerScale,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const innerOptions: any = {
|
|
253
|
+
scale: settings.innerScale,
|
|
254
|
+
x: innerPositionX,
|
|
255
|
+
y: innerPositionY,
|
|
256
|
+
alpha: innerAlpha,
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
if (!settings.inner) {
|
|
260
|
+
innerElement = h(Graphics, {
|
|
261
|
+
draw: (g) => {
|
|
262
|
+
g.circle(0, 0, innerRadius * 2.5).fill(0x000000);
|
|
263
|
+
},
|
|
264
|
+
...innerOptions,
|
|
265
|
+
});
|
|
266
|
+
} else {
|
|
267
|
+
innerElement = h(Sprite, {
|
|
268
|
+
image: settings.inner,
|
|
269
|
+
anchor: { x: 0.5, y: 0.5 },
|
|
270
|
+
...innerOptions,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return h(
|
|
275
|
+
Container,
|
|
276
|
+
{
|
|
277
|
+
...opts,
|
|
278
|
+
pointerdown: handleDragStart,
|
|
279
|
+
pointerup: handleDragEnd,
|
|
280
|
+
pointerupoutside: handleDragEnd,
|
|
281
|
+
pointermove: handleDragMove,
|
|
282
|
+
},
|
|
283
|
+
outerElement,
|
|
284
|
+
innerElement
|
|
285
|
+
);
|
|
286
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { Container, Graphics } from "../components";
|
|
2
|
+
import { h, mount } from "../engine/signal";
|
|
3
|
+
import { animatedSignal } from "../engine/animation";
|
|
4
|
+
import { RadialGradient } from "../utils/RadialGradient";
|
|
5
|
+
import { effect, isSignal, signal } from "@signe/reactive";
|
|
6
|
+
import { useProps } from "../hooks/useProps";
|
|
7
|
+
import { isObservable } from "rxjs";
|
|
8
|
+
|
|
9
|
+
export function LightSpot(opts) {
|
|
10
|
+
const { radius } = useProps(opts);
|
|
11
|
+
const scale = animatedSignal(1);
|
|
12
|
+
|
|
13
|
+
const minScale = 1;
|
|
14
|
+
const maxScale = 2; // Reduced max scale for subtler effect
|
|
15
|
+
const scintillationSpeed = 0.001; // Significantly reduced for slower scintillation
|
|
16
|
+
|
|
17
|
+
const animate = () => {
|
|
18
|
+
// Use time-based animation for smoother, slower scintillation
|
|
19
|
+
const time = Date.now() * scintillationSpeed;
|
|
20
|
+
|
|
21
|
+
// Combine multiple sine waves for a more natural, less predictable effect
|
|
22
|
+
const scintillationFactor =
|
|
23
|
+
(Math.sin(time) + Math.sin(time * 1.3) + Math.sin(time * 0.7)) / 3;
|
|
24
|
+
|
|
25
|
+
// Map the scintillation factor to the scale range
|
|
26
|
+
const newScale =
|
|
27
|
+
minScale + (maxScale - minScale) * (scintillationFactor * 0.5 + 0.5);
|
|
28
|
+
|
|
29
|
+
scale.update(() => newScale);
|
|
30
|
+
|
|
31
|
+
requestAnimationFrame(animate);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
animate();
|
|
35
|
+
|
|
36
|
+
const draw = (g) => {
|
|
37
|
+
const size = radius() * 2;
|
|
38
|
+
const gradient = new RadialGradient(size, size, 0, size, size, 0);
|
|
39
|
+
gradient.addColorStop(0, "rgba(255, 255, 0, 1)");
|
|
40
|
+
gradient.addColorStop(0.5, "rgba(255, 255, 0, 0.3)");
|
|
41
|
+
gradient.addColorStop(0.8, "rgba(255, 255, 0, 0)");
|
|
42
|
+
|
|
43
|
+
const translate = size / 2;
|
|
44
|
+
|
|
45
|
+
g.rect(-translate, -translate, size, size).fill(
|
|
46
|
+
gradient.render({ translate: { x: translate, y: translate } })
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return h(Graphics, {
|
|
51
|
+
draw,
|
|
52
|
+
...opts,
|
|
53
|
+
scale,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function NightAmbiant(props) {
|
|
58
|
+
const { children } = props;
|
|
59
|
+
let el
|
|
60
|
+
const width = signal(0);
|
|
61
|
+
const height = signal(0);
|
|
62
|
+
let subscription
|
|
63
|
+
const draw = (rectAndHole) => {
|
|
64
|
+
const margin = 80
|
|
65
|
+
rectAndHole.rect(-margin, -margin, width() + margin*2, height() + margin*2);
|
|
66
|
+
rectAndHole.fill(0x000000);
|
|
67
|
+
const applyChildren = (child) => {
|
|
68
|
+
const x = isSignal(child.propObservables.x)
|
|
69
|
+
? child.propObservables.x()
|
|
70
|
+
: child.props.x;
|
|
71
|
+
const y = isSignal(child.propObservables.y)
|
|
72
|
+
? child.propObservables.y()
|
|
73
|
+
: child.props.y;
|
|
74
|
+
const radius = isSignal(child.propObservables.radius)
|
|
75
|
+
? child.propObservables.radius()
|
|
76
|
+
: child.props.radius;
|
|
77
|
+
rectAndHole.circle(x, y, radius);
|
|
78
|
+
rectAndHole.cut();
|
|
79
|
+
}
|
|
80
|
+
for (let child of children) {
|
|
81
|
+
if (isObservable(child)) {
|
|
82
|
+
if (subscription) {
|
|
83
|
+
subscription.unsubscribe()
|
|
84
|
+
}
|
|
85
|
+
subscription = child.subscribe((event) => {
|
|
86
|
+
for (let child of event.fullElements) {
|
|
87
|
+
applyChildren(child)
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
applyChildren(child)
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
mount((el) => {
|
|
97
|
+
effect(() => {
|
|
98
|
+
const { displayWidth, displayHeight } = el.componentInstance
|
|
99
|
+
const w = +displayWidth()
|
|
100
|
+
const h = +displayHeight()
|
|
101
|
+
setTimeout(() => {
|
|
102
|
+
width.update(() => w)
|
|
103
|
+
height.update(() => h)
|
|
104
|
+
}, 0) // hack
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return h(
|
|
109
|
+
Container,
|
|
110
|
+
{
|
|
111
|
+
width: "100%",
|
|
112
|
+
height: "100%",
|
|
113
|
+
...props,
|
|
114
|
+
},
|
|
115
|
+
h(Graphics, {
|
|
116
|
+
draw,
|
|
117
|
+
alpha: 0.8,
|
|
118
|
+
blur: 80,
|
|
119
|
+
}),
|
|
120
|
+
...children
|
|
121
|
+
);
|
|
122
|
+
}
|