core2d 2.10.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/LICENSE +21 -0
- package/README.md +62 -0
- package/package.json +50 -0
- package/src/ACL.mjs +72 -0
- package/src/Animation.mjs +56 -0
- package/src/Axis.mjs +10 -0
- package/src/ButtonLayout.mjs +43 -0
- package/src/ButtonLayoutMap.mjs +5 -0
- package/src/Color.mjs +154 -0
- package/src/Command.mjs +16 -0
- package/src/CompositeOperations.mjs +15 -0
- package/src/Controller.mjs +67 -0
- package/src/Core2D.mjs +135 -0
- package/src/Direction.mjs +30 -0
- package/src/Engine.mjs +467 -0
- package/src/FontFamily.mjs +9 -0
- package/src/Frame.mjs +26 -0
- package/src/GamePad.mjs +50 -0
- package/src/Input.mjs +123 -0
- package/src/Key.mjs +22 -0
- package/src/KeyMap.mjs +25 -0
- package/src/Keyboard.mjs +34 -0
- package/src/Mouse.mjs +34 -0
- package/src/Point.mjs +38 -0
- package/src/Pointer.mjs +44 -0
- package/src/Rect.mjs +127 -0
- package/src/RenderableList.mjs +19 -0
- package/src/Scene.mjs +108 -0
- package/src/Sound.mjs +138 -0
- package/src/Sprite.mjs +368 -0
- package/src/Static.mjs +77 -0
- package/src/TextSprite.mjs +144 -0
- package/src/Touch.mjs +40 -0
- package/src/Transition.mjs +21 -0
- package/src/plugin/BaseTile.mjs +10 -0
- package/src/plugin/ClickableSprite.mjs +24 -0
- package/src/plugin/ControllableSprite.mjs +38 -0
- package/src/plugin/CursorSprite.mjs +45 -0
- package/src/plugin/Fog.mjs +31 -0
- package/src/plugin/FontSprite.mjs +74 -0
- package/src/plugin/JumperSprite.mjs +143 -0
- package/src/plugin/RandomRectTransition.mjs +34 -0
- package/src/plugin/Starfield.mjs +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 Diogo Eichert
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# About
|
|
4
|
+
Core2D is the powerhouse used by [Maragato マラガト](https://maragato.itch.io) apps, among others. It is the evolution of Videogame, which in turn was the evolution of Quick. In its current form, it adopts [JavaScript modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules), leveraging the full power of [Object-oriented programming](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object-oriented_programming).
|
|
5
|
+
|
|
6
|
+
## Concept
|
|
7
|
+
Apps created with Core2D are made of one or more [scenes](src/Scene.mjs), which may contain one or more [sprites](src/Sprite.mjs). These objects have properties that can be customized to shape their behavior. It's that simple.
|
|
8
|
+
|
|
9
|
+
# Get Started
|
|
10
|
+
[Download](https://github.com/dgchrt/core2d-skel/archive/refs/heads/main.zip) or clone/fork the [skeleton project](https://github.com/dgchrt/core2d-skel/) to start building your app. Alternatively, the library can be also installed to your existing/new project:
|
|
11
|
+
```shell
|
|
12
|
+
npm install core2d
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Learn
|
|
16
|
+
The best way to learn is by doing, and you can see what Core2D is capable of through existing open-sourced apps. Check the [Hall of Fame](#hall-of-fame) below for some source code.
|
|
17
|
+
|
|
18
|
+
## Support
|
|
19
|
+
Please consider joining the [Discussions](https://github.com/dgchrt/core2d/discussions) for collaboration and support.
|
|
20
|
+
|
|
21
|
+
# Features
|
|
22
|
+
|
|
23
|
+
## Collision Detection
|
|
24
|
+
Translated to callbacks, to keep update logic clean.
|
|
25
|
+
|
|
26
|
+
## Assets Caching
|
|
27
|
+
Assets and their transformations are reused automatically to keep a solid performance.
|
|
28
|
+
|
|
29
|
+
## User Input
|
|
30
|
+
Human interaction is unified via abstractions, so that apps will just work, regardless of the devices in use.
|
|
31
|
+
|
|
32
|
+
### Controllers
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
Gamepads or keyboard. When using a keyboard, sensible defaults (minding accessibility) are used, as seen in [KeyMap.mjs](https://github.com/dgchrt/core2d/blob/main/src/KeyMap.mjs).
|
|
36
|
+
|
|
37
|
+
### Pointers
|
|
38
|
+

|
|
39
|
+
|
|
40
|
+
Mice or touch screen.
|
|
41
|
+
|
|
42
|
+
## Virtual Resolution
|
|
43
|
+
Internal geometry frees the app logic from displays, i.e. your app can have an internal logic resolution of 800x600, while running on any display size.
|
|
44
|
+
|
|
45
|
+
# Contributing
|
|
46
|
+
The core of the library (under `src/`) should remain agnostic and lean. Updates to the core library are usually related to technology developments in the platform (web API advances), while staying true to the basic concepts of the library, which are common to all apps.
|
|
47
|
+
|
|
48
|
+
Opinionated functionality should be implemented in the form of a plugin (under `src/plugin/`). Plugins can add features that are domain driven, such as elements that can be reused by multiple apps, but not necessarily by every app.
|
|
49
|
+
|
|
50
|
+
# Hall of Fame
|
|
51
|
+
Apps created with Core2D:
|
|
52
|
+
- [Asteroids Remake](https://chamun.github.io/asteroids-remake/) ([source](https://github.com/chamun/asteroids-remake))
|
|
53
|
+
- [Cityscape](https://puter.com/app/cityscape) - Single-player arcade survival game
|
|
54
|
+
- [Cucurbita's Halloween](https://www.kongregate.com/games/bbastudios/cucurbitas-halloween)
|
|
55
|
+
- [Dragonfire](http://staudt.github.io/dragonfire) ([source](https://github.com/staudt/dragonfire))
|
|
56
|
+
- [Missile Commander](https://dgchrt.github.io/missile-commander/) ([source](https://github.com/dgchrt/missile-commander))
|
|
57
|
+
- [Ms. Starship](https://puter.com/app/ms-starship) - Multi-player arcade shoot'em up
|
|
58
|
+
- [Mythology](https://puter.com/app/mythology) - Single-player arcade pinball
|
|
59
|
+
- [Raycaster](https://staudt.github.io/raycaster/) ([source](https://github.com/staudt/raycaster))
|
|
60
|
+
- [Starship](https://puter.com/app/starship) - Single-player arcade shoot'em up
|
|
61
|
+
- [Super Breakout Bros.](https://staudt.github.io/SuperBreakoutBros/) ([source](https://github.com/staudt/SuperBreakoutBros))
|
|
62
|
+
- [Tower Defense](https://danielcolnaghi.github.io/towerdefense) ([source](https://github.com/danielcolnaghi/towerdefense))
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "core2d",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "2.10.2",
|
|
5
|
+
"description": "Multiplatform 2D interaction engine",
|
|
6
|
+
"files": [
|
|
7
|
+
"src"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"lint": "eslint",
|
|
11
|
+
"prepublishOnly": "git checkout main && git pull --rebase && npm test && git push && git push --tags",
|
|
12
|
+
"test": "npm run lint && for test in ./test/*.mjs; do node $test; done"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/diogoeichert/core2d.git"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"2d",
|
|
20
|
+
"core",
|
|
21
|
+
"core2d",
|
|
22
|
+
"engine",
|
|
23
|
+
"game",
|
|
24
|
+
"game-engine",
|
|
25
|
+
"gamepad",
|
|
26
|
+
"interaction",
|
|
27
|
+
"keyboard",
|
|
28
|
+
"mouse",
|
|
29
|
+
"multi-platform",
|
|
30
|
+
"multimedia",
|
|
31
|
+
"object-oriented",
|
|
32
|
+
"sprites",
|
|
33
|
+
"scenes",
|
|
34
|
+
"touch"
|
|
35
|
+
],
|
|
36
|
+
"author": "Diogo Eichert",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/diogoeichert/core2d/issues"
|
|
40
|
+
},
|
|
41
|
+
"funding": {
|
|
42
|
+
"url": "https://github.com/sponsors/diogoeichert"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://diogoeichert.github.io/core2d/",
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@eslint/js": "^9.30.1",
|
|
47
|
+
"eslint": "^9.30.1",
|
|
48
|
+
"globals": "^16.3.0"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/ACL.mjs
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sets up the environment based on its runtime (browser or not).
|
|
5
|
+
*/
|
|
6
|
+
if (typeof(global) != "undefined") {
|
|
7
|
+
global.addEventListener = () => {};
|
|
8
|
+
|
|
9
|
+
global.document = {
|
|
10
|
+
createElement: (name) => {
|
|
11
|
+
if (name == "canvas") {
|
|
12
|
+
return {
|
|
13
|
+
getContext: () => {
|
|
14
|
+
return {
|
|
15
|
+
measureText: (text) => {
|
|
16
|
+
return {
|
|
17
|
+
width: text.length,
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
getElementById: (id) => {
|
|
26
|
+
if (id == "app") {
|
|
27
|
+
return {
|
|
28
|
+
focus: () => {},
|
|
29
|
+
getContext: () => {
|
|
30
|
+
return {
|
|
31
|
+
fillRect: () => {},
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
height: 400,
|
|
35
|
+
offsetLeft: 0,
|
|
36
|
+
offsetTop: 0,
|
|
37
|
+
style: {},
|
|
38
|
+
width: 640,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {};
|
|
43
|
+
},
|
|
44
|
+
getElementsByTagName: () => {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
global.localStorage = {};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* For older Node.js versions.
|
|
53
|
+
*/
|
|
54
|
+
if (!global.navigator) {
|
|
55
|
+
global.navigator = {};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
global.window = {
|
|
59
|
+
focus: () => {},
|
|
60
|
+
innerHeight: 600,
|
|
61
|
+
innerWidth: 800,
|
|
62
|
+
requestAnimationFrame: () => true
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Anti-Corruption Layer, to be used instead of direct API calls.
|
|
68
|
+
*/
|
|
69
|
+
export const ACL = {
|
|
70
|
+
document,
|
|
71
|
+
window,
|
|
72
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { Frame } from "./Frame.mjs";
|
|
4
|
+
|
|
5
|
+
export class Animation {
|
|
6
|
+
constructor(frames) {
|
|
7
|
+
this._frames = frames;
|
|
8
|
+
this._index = 0;
|
|
9
|
+
this._tick = 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
static fromImages(images, duration) {
|
|
13
|
+
return new this(images.map(image => new Frame(image, duration)));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get image() {
|
|
17
|
+
return this._frames[this._index].image;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get width() {
|
|
21
|
+
return this._frames[this._index].width;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get height() {
|
|
25
|
+
return this._frames[this._index].height;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
setFrameIndex(index) {
|
|
29
|
+
if (index < this._frames.length) {
|
|
30
|
+
this._index = index;
|
|
31
|
+
this._tick = 0;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
set frameIndex(index) {
|
|
36
|
+
this.setFrameIndex(index);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
sync() {
|
|
40
|
+
const DURATION = this._frames[this._index].duration;
|
|
41
|
+
let hasLooped = false;
|
|
42
|
+
|
|
43
|
+
if (DURATION && ++this._tick >= DURATION) {
|
|
44
|
+
let index = this._index + 1;
|
|
45
|
+
|
|
46
|
+
if (index == this._frames.length) {
|
|
47
|
+
hasLooped = true;
|
|
48
|
+
index = 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.setFrameIndex(index);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return hasLooped;
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/Axis.mjs
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { Static } from "./Static.mjs";
|
|
4
|
+
|
|
5
|
+
export const ButtonLayout = {
|
|
6
|
+
reversed: Static.makeEnum([
|
|
7
|
+
"B",
|
|
8
|
+
"A",
|
|
9
|
+
"Y",
|
|
10
|
+
"X",
|
|
11
|
+
"L1",
|
|
12
|
+
"R1",
|
|
13
|
+
"L2",
|
|
14
|
+
"R2",
|
|
15
|
+
"SELECT",
|
|
16
|
+
"START",
|
|
17
|
+
"L3",
|
|
18
|
+
"R3",
|
|
19
|
+
"UP",
|
|
20
|
+
"DOWN",
|
|
21
|
+
"LEFT",
|
|
22
|
+
"RIGHT",
|
|
23
|
+
]),
|
|
24
|
+
|
|
25
|
+
standard: Static.makeEnum([
|
|
26
|
+
"A",
|
|
27
|
+
"B",
|
|
28
|
+
"X",
|
|
29
|
+
"Y",
|
|
30
|
+
"L1",
|
|
31
|
+
"R1",
|
|
32
|
+
"L2",
|
|
33
|
+
"R2",
|
|
34
|
+
"SELECT",
|
|
35
|
+
"START",
|
|
36
|
+
"L3",
|
|
37
|
+
"R3",
|
|
38
|
+
"UP",
|
|
39
|
+
"DOWN",
|
|
40
|
+
"LEFT",
|
|
41
|
+
"RIGHT",
|
|
42
|
+
])
|
|
43
|
+
};
|
package/src/Color.mjs
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { Static } from "./Static.mjs";
|
|
4
|
+
|
|
5
|
+
export const Color = Static.makeHash([
|
|
6
|
+
"AliceBlue",
|
|
7
|
+
"AntiqueWhite",
|
|
8
|
+
"Aqua",
|
|
9
|
+
"Aquamarine",
|
|
10
|
+
"Azure",
|
|
11
|
+
"Beige",
|
|
12
|
+
"Bisque",
|
|
13
|
+
"Black",
|
|
14
|
+
"BlanchedAlmond",
|
|
15
|
+
"Blue",
|
|
16
|
+
"BlueViolet",
|
|
17
|
+
"Brown",
|
|
18
|
+
"BurlyWood",
|
|
19
|
+
"CadetBlue",
|
|
20
|
+
"Chartreuse",
|
|
21
|
+
"Chocolate",
|
|
22
|
+
"Coral",
|
|
23
|
+
"CornflowerBlue",
|
|
24
|
+
"Cornsilk",
|
|
25
|
+
"Crimson",
|
|
26
|
+
"Cyan",
|
|
27
|
+
"DarkBlue",
|
|
28
|
+
"DarkCyan",
|
|
29
|
+
"DarkGoldenRod",
|
|
30
|
+
"DarkGray",
|
|
31
|
+
"DarkGreen",
|
|
32
|
+
"DarkGrey",
|
|
33
|
+
"DarkKhaki",
|
|
34
|
+
"DarkMagenta",
|
|
35
|
+
"DarkOliveGreen",
|
|
36
|
+
"Darkorange",
|
|
37
|
+
"DarkOrchid",
|
|
38
|
+
"DarkRed",
|
|
39
|
+
"DarkSalmon",
|
|
40
|
+
"DarkSeaGreen",
|
|
41
|
+
"DarkSlateBlue",
|
|
42
|
+
"DarkSlateGray",
|
|
43
|
+
"DarkSlateGrey",
|
|
44
|
+
"DarkTurquoise",
|
|
45
|
+
"DarkViolet",
|
|
46
|
+
"DeepPink",
|
|
47
|
+
"DeepSkyBlue",
|
|
48
|
+
"DimGray",
|
|
49
|
+
"DimGrey",
|
|
50
|
+
"DodgerBlue",
|
|
51
|
+
"FireBrick",
|
|
52
|
+
"FloralWhite",
|
|
53
|
+
"ForestGreen",
|
|
54
|
+
"Fuchsia",
|
|
55
|
+
"Gainsboro",
|
|
56
|
+
"GhostWhite",
|
|
57
|
+
"Gold",
|
|
58
|
+
"GoldenRod",
|
|
59
|
+
"Gray",
|
|
60
|
+
"Green",
|
|
61
|
+
"GreenYellow",
|
|
62
|
+
"Grey",
|
|
63
|
+
"HoneyDew",
|
|
64
|
+
"HotPink",
|
|
65
|
+
"IndianRed",
|
|
66
|
+
"Indigo",
|
|
67
|
+
"Ivory",
|
|
68
|
+
"Khaki",
|
|
69
|
+
"Lavender",
|
|
70
|
+
"LavenderBlush",
|
|
71
|
+
"LawnGreen",
|
|
72
|
+
"LemonChiffon",
|
|
73
|
+
"LightBlue",
|
|
74
|
+
"LightCoral",
|
|
75
|
+
"LightCyan",
|
|
76
|
+
"LightGoldenRodYellow",
|
|
77
|
+
"LightGray",
|
|
78
|
+
"LightGreen",
|
|
79
|
+
"LightGrey",
|
|
80
|
+
"LightPink",
|
|
81
|
+
"LightSalmon",
|
|
82
|
+
"LightSeaGreen",
|
|
83
|
+
"LightSkyBlue",
|
|
84
|
+
"LightSlateGray",
|
|
85
|
+
"LightSlateGrey",
|
|
86
|
+
"LightSteelBlue",
|
|
87
|
+
"LightYellow",
|
|
88
|
+
"Lime",
|
|
89
|
+
"LimeGreen",
|
|
90
|
+
"Linen",
|
|
91
|
+
"Magenta",
|
|
92
|
+
"Maroon",
|
|
93
|
+
"MediumAquaMarine",
|
|
94
|
+
"MediumBlue",
|
|
95
|
+
"MediumOrchid",
|
|
96
|
+
"MediumPurple",
|
|
97
|
+
"MediumSeaGreen",
|
|
98
|
+
"MediumSlateBlue",
|
|
99
|
+
"MediumSpringGreen",
|
|
100
|
+
"MediumTurquoise",
|
|
101
|
+
"MediumVioletRed",
|
|
102
|
+
"MidnightBlue",
|
|
103
|
+
"MintCream",
|
|
104
|
+
"MistyRose",
|
|
105
|
+
"Moccasin",
|
|
106
|
+
"NavajoWhite",
|
|
107
|
+
"Navy",
|
|
108
|
+
"OldLace",
|
|
109
|
+
"Olive",
|
|
110
|
+
"OliveDrab",
|
|
111
|
+
"Orange",
|
|
112
|
+
"OrangeRed",
|
|
113
|
+
"Orchid",
|
|
114
|
+
"PaleGoldenRod",
|
|
115
|
+
"PaleGreen",
|
|
116
|
+
"PaleTurquoise",
|
|
117
|
+
"PaleVioletRed",
|
|
118
|
+
"PapayaWhip",
|
|
119
|
+
"PeachPuff",
|
|
120
|
+
"Peru",
|
|
121
|
+
"Pink",
|
|
122
|
+
"Plum",
|
|
123
|
+
"PowderBlue",
|
|
124
|
+
"Purple",
|
|
125
|
+
"RebeccaPurple",
|
|
126
|
+
"Red",
|
|
127
|
+
"RosyBrown",
|
|
128
|
+
"RoyalBlue",
|
|
129
|
+
"SaddleBrown",
|
|
130
|
+
"Salmon",
|
|
131
|
+
"SandyBrown",
|
|
132
|
+
"SeaGreen",
|
|
133
|
+
"SeaShell",
|
|
134
|
+
"Sienna",
|
|
135
|
+
"Silver",
|
|
136
|
+
"SkyBlue",
|
|
137
|
+
"SlateBlue",
|
|
138
|
+
"SlateGray",
|
|
139
|
+
"SlateGrey",
|
|
140
|
+
"Snow",
|
|
141
|
+
"SpringGreen",
|
|
142
|
+
"SteelBlue",
|
|
143
|
+
"Tan",
|
|
144
|
+
"Teal",
|
|
145
|
+
"Thistle",
|
|
146
|
+
"Tomato",
|
|
147
|
+
"Turquoise",
|
|
148
|
+
"Violet",
|
|
149
|
+
"Wheat",
|
|
150
|
+
"White",
|
|
151
|
+
"WhiteSmoke",
|
|
152
|
+
"Yellow",
|
|
153
|
+
"YellowGreen",
|
|
154
|
+
]);
|
package/src/Command.mjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
export const CompositeOperations = {
|
|
4
|
+
COPY: "copy",
|
|
5
|
+
DESTINATION_ATOP: "destination-atop",
|
|
6
|
+
DESTINATION_IN: "destination-in",
|
|
7
|
+
DESTINATION_OUT: "destination-out",
|
|
8
|
+
DESTINATION_OVER: "destination-over",
|
|
9
|
+
LIGHTER: "lighter",
|
|
10
|
+
SOURCE_ATOP: "source-atop",
|
|
11
|
+
SOURCE_IN: "source-in",
|
|
12
|
+
SOURCE_OUT: "source-out",
|
|
13
|
+
SOURCE_OVER: "source-over",
|
|
14
|
+
XOR: "xor",
|
|
15
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { Command } from "./Command.mjs";
|
|
4
|
+
|
|
5
|
+
export class Controller {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.tolerance = 0;
|
|
8
|
+
this._active = {};
|
|
9
|
+
this._device = null;
|
|
10
|
+
this._hold = {};
|
|
11
|
+
this._sequence = [];
|
|
12
|
+
this._tick = 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
didPerform(commands) {
|
|
16
|
+
for (let i = 1; i <= commands.length; ++i) {
|
|
17
|
+
if (this._sequence[this._sequence.length - i] != commands[commands.length - i]) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
this._sequence = [];
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
keyDown(command) {
|
|
27
|
+
return this._active[command];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
keyPush(command) {
|
|
31
|
+
return this._active[command] && !this._hold[command];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
setDevice(device) {
|
|
35
|
+
this._device = device;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
update() {
|
|
39
|
+
if (!this._device) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
this._hold = {};
|
|
44
|
+
const LAST = this._active;
|
|
45
|
+
this._active = this._device.commands;
|
|
46
|
+
|
|
47
|
+
for (let i in this._active) {
|
|
48
|
+
if (LAST[i]) {
|
|
49
|
+
this._hold[i] = true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (this.tolerance && ++this._tick > this.tolerance) {
|
|
54
|
+
this._sequence = [];
|
|
55
|
+
this._tick = 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (let i in Command) {
|
|
59
|
+
const COMMAND = Command[i];
|
|
60
|
+
|
|
61
|
+
if (this.keyPush(COMMAND)) {
|
|
62
|
+
this._sequence.push(COMMAND);
|
|
63
|
+
this._tick = 0;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|