@guinetik/gcanvas 1.0.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/.github/workflows/release.yaml +70 -0
- package/.jshintrc +4 -0
- package/.vscode/settings.json +22 -0
- package/CLAUDE.md +310 -0
- package/blackhole.jpg +0 -0
- package/demo.png +0 -0
- package/demos/CNAME +1 -0
- package/demos/animations.html +31 -0
- package/demos/basic.html +38 -0
- package/demos/baskara.html +31 -0
- package/demos/bezier.html +35 -0
- package/demos/beziersignature.html +29 -0
- package/demos/blackhole.html +28 -0
- package/demos/blob.html +35 -0
- package/demos/demos.css +289 -0
- package/demos/easing.html +28 -0
- package/demos/events.html +195 -0
- package/demos/fluent.html +647 -0
- package/demos/fractals.html +36 -0
- package/demos/genart.html +26 -0
- package/demos/gendream.html +26 -0
- package/demos/group.html +36 -0
- package/demos/home.html +587 -0
- package/demos/index.html +364 -0
- package/demos/isometric.html +34 -0
- package/demos/js/animations.js +452 -0
- package/demos/js/basic.js +204 -0
- package/demos/js/baskara.js +751 -0
- package/demos/js/bezier.js +692 -0
- package/demos/js/beziersignature.js +241 -0
- package/demos/js/blackhole/accretiondisk.obj.js +379 -0
- package/demos/js/blackhole/blackhole.obj.js +318 -0
- package/demos/js/blackhole/index.js +409 -0
- package/demos/js/blackhole/particle.js +56 -0
- package/demos/js/blackhole/starfield.obj.js +218 -0
- package/demos/js/blob.js +2263 -0
- package/demos/js/easing.js +477 -0
- package/demos/js/fluent.js +183 -0
- package/demos/js/fractals.js +931 -0
- package/demos/js/fractalworker.js +93 -0
- package/demos/js/genart.js +268 -0
- package/demos/js/gendream.js +209 -0
- package/demos/js/group.js +140 -0
- package/demos/js/info-toggle.js +25 -0
- package/demos/js/isometric.js +863 -0
- package/demos/js/kerr.js +1556 -0
- package/demos/js/lavalamp.js +590 -0
- package/demos/js/layout.js +354 -0
- package/demos/js/mondrian.js +285 -0
- package/demos/js/opacity.js +275 -0
- package/demos/js/painter.js +484 -0
- package/demos/js/particles-showcase.js +514 -0
- package/demos/js/particles.js +299 -0
- package/demos/js/patterns.js +397 -0
- package/demos/js/penrose/artifact.js +69 -0
- package/demos/js/penrose/blackhole.js +121 -0
- package/demos/js/penrose/constants.js +73 -0
- package/demos/js/penrose/game.js +943 -0
- package/demos/js/penrose/lore.js +278 -0
- package/demos/js/penrose/penrosescene.js +892 -0
- package/demos/js/penrose/ship.js +216 -0
- package/demos/js/penrose/sounds.js +211 -0
- package/demos/js/penrose/voidparticle.js +55 -0
- package/demos/js/penrose/voidscene.js +258 -0
- package/demos/js/penrose/voidship.js +144 -0
- package/demos/js/penrose/wormhole.js +46 -0
- package/demos/js/pipeline.js +555 -0
- package/demos/js/scene.js +304 -0
- package/demos/js/scenes.js +320 -0
- package/demos/js/schrodinger.js +410 -0
- package/demos/js/schwarzschild.js +1023 -0
- package/demos/js/shapes.js +628 -0
- package/demos/js/space/alien.js +171 -0
- package/demos/js/space/boom.js +98 -0
- package/demos/js/space/boss.js +353 -0
- package/demos/js/space/buff.js +73 -0
- package/demos/js/space/bullet.js +102 -0
- package/demos/js/space/constants.js +85 -0
- package/demos/js/space/game.js +1884 -0
- package/demos/js/space/hud.js +112 -0
- package/demos/js/space/laserbeam.js +179 -0
- package/demos/js/space/lightning.js +277 -0
- package/demos/js/space/minion.js +192 -0
- package/demos/js/space/missile.js +212 -0
- package/demos/js/space/player.js +430 -0
- package/demos/js/space/powerup.js +90 -0
- package/demos/js/space/starfield.js +58 -0
- package/demos/js/space/starpower.js +90 -0
- package/demos/js/spacetime.js +559 -0
- package/demos/js/svgtween.js +204 -0
- package/demos/js/tde/accretiondisk.js +418 -0
- package/demos/js/tde/blackhole.js +219 -0
- package/demos/js/tde/blackholescene.js +209 -0
- package/demos/js/tde/config.js +59 -0
- package/demos/js/tde/index.js +695 -0
- package/demos/js/tde/jets.js +290 -0
- package/demos/js/tde/lensedstarfield.js +147 -0
- package/demos/js/tde/tdestar.js +317 -0
- package/demos/js/tde/tidalstream.js +356 -0
- package/demos/js/tde_old/blackhole.obj.js +354 -0
- package/demos/js/tde_old/debris.obj.js +791 -0
- package/demos/js/tde_old/flare.obj.js +239 -0
- package/demos/js/tde_old/index.js +448 -0
- package/demos/js/tde_old/star.obj.js +812 -0
- package/demos/js/tiles.js +312 -0
- package/demos/js/tweendemo.js +79 -0
- package/demos/js/visibility.js +102 -0
- package/demos/kerr.html +28 -0
- package/demos/lavalamp.html +27 -0
- package/demos/layouts.html +37 -0
- package/demos/logo.svg +4 -0
- package/demos/loop.html +84 -0
- package/demos/mondrian.html +32 -0
- package/demos/og_image.png +0 -0
- package/demos/opacity.html +36 -0
- package/demos/painter.html +39 -0
- package/demos/particles-showcase.html +28 -0
- package/demos/particles.html +24 -0
- package/demos/patterns.html +33 -0
- package/demos/penrose-game.html +31 -0
- package/demos/pipeline.html +737 -0
- package/demos/scene.html +33 -0
- package/demos/scenes.html +96 -0
- package/demos/schrodinger.html +27 -0
- package/demos/schwarzschild.html +27 -0
- package/demos/shapes.html +16 -0
- package/demos/space.html +85 -0
- package/demos/spacetime.html +27 -0
- package/demos/svgtween.html +29 -0
- package/demos/tde.html +28 -0
- package/demos/tiles.html +28 -0
- package/demos/transforms.html +400 -0
- package/demos/tween.html +45 -0
- package/demos/visibility.html +33 -0
- package/disk_example.png +0 -0
- package/docs/README.md +222 -0
- package/docs/concepts/architecture-overview.md +204 -0
- package/docs/concepts/lifecycle.md +255 -0
- package/docs/concepts/rendering-pipeline.md +279 -0
- package/docs/concepts/tde-zorder.md +106 -0
- package/docs/concepts/two-layer-architecture.md +229 -0
- package/docs/getting-started/first-game.md +354 -0
- package/docs/getting-started/hello-world.md +269 -0
- package/docs/getting-started/installation.md +157 -0
- package/docs/modules/collision/README.md +453 -0
- package/docs/modules/fluent/README.md +1075 -0
- package/docs/modules/game/README.md +303 -0
- package/docs/modules/isometric-camera.md +210 -0
- package/docs/modules/isometric.md +275 -0
- package/docs/modules/painter/README.md +328 -0
- package/docs/modules/particle/README.md +559 -0
- package/docs/modules/shapes/README.md +221 -0
- package/docs/modules/shapes/base/euclidian.md +123 -0
- package/docs/modules/shapes/base/geometry2d.md +204 -0
- package/docs/modules/shapes/base/renderable.md +215 -0
- package/docs/modules/shapes/base/shape.md +262 -0
- package/docs/modules/shapes/base/transformable.md +243 -0
- package/docs/modules/shapes/hierarchy.md +218 -0
- package/docs/modules/state/README.md +577 -0
- package/docs/modules/util/README.md +99 -0
- package/docs/modules/util/camera3d.md +412 -0
- package/docs/modules/util/scene3d.md +395 -0
- package/index.html +17 -0
- package/jsdoc.json +50 -0
- package/package.json +55 -0
- package/readme.md +599 -0
- package/scripts/build-demo.js +69 -0
- package/scripts/bundle4llm.js +276 -0
- package/scripts/clearconsole.js +48 -0
- package/src/collision/collision-system.js +332 -0
- package/src/collision/collision.js +303 -0
- package/src/collision/index.js +10 -0
- package/src/fluent/fluent-game.js +430 -0
- package/src/fluent/fluent-go.js +1060 -0
- package/src/fluent/fluent-layer.js +152 -0
- package/src/fluent/fluent-scene.js +291 -0
- package/src/fluent/index.js +98 -0
- package/src/fluent/sketch.js +380 -0
- package/src/game/game.js +467 -0
- package/src/game/index.js +49 -0
- package/src/game/objects/go.js +220 -0
- package/src/game/objects/imagego.js +30 -0
- package/src/game/objects/index.js +54 -0
- package/src/game/objects/isometric-scene.js +260 -0
- package/src/game/objects/layoutscene.js +549 -0
- package/src/game/objects/scene.js +175 -0
- package/src/game/objects/scene3d.js +118 -0
- package/src/game/objects/text.js +221 -0
- package/src/game/objects/wrapper.js +232 -0
- package/src/game/pipeline.js +243 -0
- package/src/game/ui/button.js +396 -0
- package/src/game/ui/cursor.js +93 -0
- package/src/game/ui/fps.js +91 -0
- package/src/game/ui/index.js +5 -0
- package/src/game/ui/togglebutton.js +93 -0
- package/src/game/ui/tooltip.js +249 -0
- package/src/index.js +25 -0
- package/src/io/events.js +20 -0
- package/src/io/index.js +86 -0
- package/src/io/input.js +70 -0
- package/src/io/keys.js +152 -0
- package/src/io/mouse.js +61 -0
- package/src/io/touch.js +39 -0
- package/src/logger/debugtab.js +138 -0
- package/src/logger/index.js +3 -0
- package/src/logger/loggable.js +47 -0
- package/src/logger/logger.js +113 -0
- package/src/math/complex.js +37 -0
- package/src/math/constants.js +1 -0
- package/src/math/fractal.js +1271 -0
- package/src/math/gr.js +201 -0
- package/src/math/heat.js +202 -0
- package/src/math/index.js +12 -0
- package/src/math/noise.js +433 -0
- package/src/math/orbital.js +191 -0
- package/src/math/patterns.js +1339 -0
- package/src/math/penrose.js +259 -0
- package/src/math/quantum.js +115 -0
- package/src/math/random.js +195 -0
- package/src/math/tensor.js +1009 -0
- package/src/mixins/anchor.js +131 -0
- package/src/mixins/draggable.js +72 -0
- package/src/mixins/index.js +2 -0
- package/src/motion/bezier.js +132 -0
- package/src/motion/bounce.js +58 -0
- package/src/motion/easing.js +349 -0
- package/src/motion/float.js +130 -0
- package/src/motion/follow.js +125 -0
- package/src/motion/hop.js +52 -0
- package/src/motion/index.js +82 -0
- package/src/motion/motion.js +1124 -0
- package/src/motion/orbit.js +49 -0
- package/src/motion/oscillate.js +39 -0
- package/src/motion/parabolic.js +141 -0
- package/src/motion/patrol.js +147 -0
- package/src/motion/pendulum.js +48 -0
- package/src/motion/pulse.js +88 -0
- package/src/motion/shake.js +83 -0
- package/src/motion/spiral.js +144 -0
- package/src/motion/spring.js +150 -0
- package/src/motion/swing.js +47 -0
- package/src/motion/tween.js +92 -0
- package/src/motion/tweenetik.js +139 -0
- package/src/motion/waypoint.js +210 -0
- package/src/painter/index.js +8 -0
- package/src/painter/painter.colors.js +331 -0
- package/src/painter/painter.effects.js +230 -0
- package/src/painter/painter.img.js +229 -0
- package/src/painter/painter.js +295 -0
- package/src/painter/painter.lines.js +189 -0
- package/src/painter/painter.opacity.js +41 -0
- package/src/painter/painter.shapes.js +277 -0
- package/src/painter/painter.text.js +273 -0
- package/src/particle/emitter.js +124 -0
- package/src/particle/index.js +11 -0
- package/src/particle/particle-system.js +322 -0
- package/src/particle/particle.js +71 -0
- package/src/particle/updaters.js +170 -0
- package/src/shapes/arc.js +43 -0
- package/src/shapes/arrow.js +33 -0
- package/src/shapes/bezier.js +42 -0
- package/src/shapes/circle.js +62 -0
- package/src/shapes/clouds.js +56 -0
- package/src/shapes/cone.js +219 -0
- package/src/shapes/cross.js +70 -0
- package/src/shapes/cube.js +244 -0
- package/src/shapes/cylinder.js +254 -0
- package/src/shapes/diamond.js +48 -0
- package/src/shapes/euclidian.js +111 -0
- package/src/shapes/figure.js +115 -0
- package/src/shapes/geometry.js +220 -0
- package/src/shapes/group.js +375 -0
- package/src/shapes/heart.js +42 -0
- package/src/shapes/hexagon.js +26 -0
- package/src/shapes/image.js +192 -0
- package/src/shapes/index.js +111 -0
- package/src/shapes/line.js +29 -0
- package/src/shapes/pattern.js +90 -0
- package/src/shapes/pin.js +44 -0
- package/src/shapes/poly.js +31 -0
- package/src/shapes/prism.js +226 -0
- package/src/shapes/rect.js +35 -0
- package/src/shapes/renderable.js +333 -0
- package/src/shapes/ring.js +26 -0
- package/src/shapes/roundrect.js +95 -0
- package/src/shapes/shape.js +117 -0
- package/src/shapes/slice.js +26 -0
- package/src/shapes/sphere.js +314 -0
- package/src/shapes/sphere3d.js +537 -0
- package/src/shapes/square.js +15 -0
- package/src/shapes/star.js +99 -0
- package/src/shapes/svg.js +408 -0
- package/src/shapes/text.js +553 -0
- package/src/shapes/traceable.js +83 -0
- package/src/shapes/transform.js +357 -0
- package/src/shapes/transformable.js +172 -0
- package/src/shapes/triangle.js +26 -0
- package/src/sound/index.js +17 -0
- package/src/sound/sound.js +473 -0
- package/src/sound/synth.analyzer.js +149 -0
- package/src/sound/synth.effects.js +207 -0
- package/src/sound/synth.envelope.js +59 -0
- package/src/sound/synth.js +229 -0
- package/src/sound/synth.musical.js +160 -0
- package/src/sound/synth.noise.js +85 -0
- package/src/sound/synth.oscillators.js +293 -0
- package/src/state/index.js +10 -0
- package/src/state/state-machine.js +371 -0
- package/src/util/camera3d.js +438 -0
- package/src/util/index.js +6 -0
- package/src/util/isometric-camera.js +235 -0
- package/src/util/layout.js +317 -0
- package/src/util/position.js +147 -0
- package/src/util/tasks.js +47 -0
- package/src/util/zindex.js +287 -0
- package/src/webgl/index.js +9 -0
- package/src/webgl/shaders/sphere-shaders.js +994 -0
- package/src/webgl/webgl-renderer.js +388 -0
- package/tde.png +0 -0
- package/test/math/orbital.test.js +61 -0
- package/test/math/tensor.test.js +114 -0
- package/test/particle/emitter.test.js +204 -0
- package/test/particle/particle-system.test.js +310 -0
- package/test/particle/particle.test.js +116 -0
- package/test/particle/updaters.test.js +386 -0
- package/test/setup.js +120 -0
- package/test/shapes/euclidian.test.js +44 -0
- package/test/shapes/geometry.test.js +86 -0
- package/test/shapes/group.test.js +86 -0
- package/test/shapes/rectangle.test.js +64 -0
- package/test/shapes/transform.test.js +379 -0
- package/test/util/camera3d.test.js +428 -0
- package/test/util/scene3d.test.js +352 -0
- package/types/collision.d.ts +249 -0
- package/types/common.d.ts +155 -0
- package/types/game.d.ts +497 -0
- package/types/index.d.ts +309 -0
- package/types/io.d.ts +188 -0
- package/types/logger.d.ts +127 -0
- package/types/math.d.ts +268 -0
- package/types/mixins.d.ts +92 -0
- package/types/motion.d.ts +678 -0
- package/types/painter.d.ts +378 -0
- package/types/shapes.d.ts +864 -0
- package/types/sound.d.ts +672 -0
- package/types/state.d.ts +251 -0
- package/types/util.d.ts +253 -0
- package/vite.config.js +50 -0
- package/vitest.config.js +13 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
# First Game
|
|
2
|
+
|
|
3
|
+
> Create an interactive game with the Game layer.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This guide shows how to use the Game layer to create interactive applications. We'll build a simple game with keyboard input, collision detection, and animations.
|
|
8
|
+
|
|
9
|
+
## Basic Game Setup
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import { Game, Scene, GameObject, Circle, Group, Rectangle, TextShape } from 'gcanvas';
|
|
13
|
+
|
|
14
|
+
class MyGame extends Game {
|
|
15
|
+
constructor(canvas) {
|
|
16
|
+
super(canvas);
|
|
17
|
+
this.enableFluidSize(); // Canvas fills window
|
|
18
|
+
this.backgroundColor = '#1a1a2e';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
init() {
|
|
22
|
+
super.init(); // Initialize input systems
|
|
23
|
+
|
|
24
|
+
// Create a scene
|
|
25
|
+
this.scene = new Scene(this);
|
|
26
|
+
this.pipeline.add(this.scene);
|
|
27
|
+
|
|
28
|
+
// Add game objects
|
|
29
|
+
this.scene.add(new Player(this));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Start the game
|
|
34
|
+
const canvas = document.getElementById('game');
|
|
35
|
+
const game = new MyGame(canvas);
|
|
36
|
+
game.start();
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Creating a Player
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
class Player extends GameObject {
|
|
43
|
+
constructor(game) {
|
|
44
|
+
super(game);
|
|
45
|
+
|
|
46
|
+
// Create the player shape
|
|
47
|
+
this.shape = new Circle(30, {
|
|
48
|
+
color: '#4ecdc4',
|
|
49
|
+
stroke: '#fff',
|
|
50
|
+
lineWidth: 2
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Position at center
|
|
54
|
+
this.shape.x = game.width / 2;
|
|
55
|
+
this.shape.y = game.height / 2;
|
|
56
|
+
|
|
57
|
+
// Movement speed (pixels per second)
|
|
58
|
+
this.speed = 300;
|
|
59
|
+
|
|
60
|
+
// Enable mouse/touch input on this shape
|
|
61
|
+
this.enableInteractivity(this.shape);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
update(dt) {
|
|
65
|
+
// Handle keyboard input
|
|
66
|
+
const input = this.game.input;
|
|
67
|
+
|
|
68
|
+
if (input.isKeyDown('ArrowLeft') || input.isKeyDown('KeyA')) {
|
|
69
|
+
this.shape.x -= this.speed * dt;
|
|
70
|
+
}
|
|
71
|
+
if (input.isKeyDown('ArrowRight') || input.isKeyDown('KeyD')) {
|
|
72
|
+
this.shape.x += this.speed * dt;
|
|
73
|
+
}
|
|
74
|
+
if (input.isKeyDown('ArrowUp') || input.isKeyDown('KeyW')) {
|
|
75
|
+
this.shape.y -= this.speed * dt;
|
|
76
|
+
}
|
|
77
|
+
if (input.isKeyDown('ArrowDown') || input.isKeyDown('KeyS')) {
|
|
78
|
+
this.shape.y += this.speed * dt;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Keep player on screen
|
|
82
|
+
this.shape.x = Math.max(30, Math.min(this.game.width - 30, this.shape.x));
|
|
83
|
+
this.shape.y = Math.max(30, Math.min(this.game.height - 30, this.shape.y));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
render() {
|
|
87
|
+
this.shape.draw();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Called when player is clicked
|
|
91
|
+
onPointerDown(e) {
|
|
92
|
+
console.log('Player clicked!');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Adding Enemies
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
class Enemy extends GameObject {
|
|
101
|
+
constructor(game, x, y) {
|
|
102
|
+
super(game);
|
|
103
|
+
|
|
104
|
+
this.shape = new Rectangle({
|
|
105
|
+
x: x,
|
|
106
|
+
y: y,
|
|
107
|
+
width: 40,
|
|
108
|
+
height: 40,
|
|
109
|
+
color: '#ff6b6b'
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Random direction
|
|
113
|
+
this.vx = (Math.random() - 0.5) * 200;
|
|
114
|
+
this.vy = (Math.random() - 0.5) * 200;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
update(dt) {
|
|
118
|
+
// Move
|
|
119
|
+
this.shape.x += this.vx * dt;
|
|
120
|
+
this.shape.y += this.vy * dt;
|
|
121
|
+
|
|
122
|
+
// Bounce off walls
|
|
123
|
+
if (this.shape.x < 20 || this.shape.x > this.game.width - 20) {
|
|
124
|
+
this.vx *= -1;
|
|
125
|
+
}
|
|
126
|
+
if (this.shape.y < 20 || this.shape.y > this.game.height - 20) {
|
|
127
|
+
this.vy *= -1;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Rotate
|
|
131
|
+
this.shape.rotation += dt * 2;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
render() {
|
|
135
|
+
this.shape.draw();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Complete Game Example
|
|
141
|
+
|
|
142
|
+
Here's a complete game from `demos/js/basic.js`:
|
|
143
|
+
|
|
144
|
+
```js
|
|
145
|
+
import {
|
|
146
|
+
Game,
|
|
147
|
+
GameObject,
|
|
148
|
+
Scene,
|
|
149
|
+
Circle,
|
|
150
|
+
Rectangle,
|
|
151
|
+
TextShape,
|
|
152
|
+
Group,
|
|
153
|
+
Motion,
|
|
154
|
+
Easing,
|
|
155
|
+
FPSCounter
|
|
156
|
+
} from 'gcanvas';
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* HelloWorldBox - A simple animated text box
|
|
160
|
+
*/
|
|
161
|
+
class HelloWorldBox extends GameObject {
|
|
162
|
+
constructor(game) {
|
|
163
|
+
super(game);
|
|
164
|
+
|
|
165
|
+
// Create a group to hold shapes
|
|
166
|
+
this.group = new Group({});
|
|
167
|
+
|
|
168
|
+
// Background box
|
|
169
|
+
this.box = new Rectangle({
|
|
170
|
+
width: 200,
|
|
171
|
+
height: 80,
|
|
172
|
+
color: '#333'
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Text label
|
|
176
|
+
this.label = new TextShape('Hello World!', {
|
|
177
|
+
font: '18px monospace',
|
|
178
|
+
color: '#0f0',
|
|
179
|
+
align: 'center',
|
|
180
|
+
baseline: 'middle'
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Add to group
|
|
184
|
+
this.group.add(this.box);
|
|
185
|
+
this.group.add(this.label);
|
|
186
|
+
|
|
187
|
+
// Animation time
|
|
188
|
+
this.animTime = 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
update(dt) {
|
|
192
|
+
this.animTime += dt;
|
|
193
|
+
|
|
194
|
+
// Pulse the text opacity
|
|
195
|
+
const pulse = Motion.pulse(
|
|
196
|
+
0, 1, // min, max opacity
|
|
197
|
+
this.animTime,
|
|
198
|
+
2, // 2 second cycle
|
|
199
|
+
true, // loop
|
|
200
|
+
false, // no yoyo
|
|
201
|
+
Easing.easeInOutSine
|
|
202
|
+
);
|
|
203
|
+
this.label.opacity = pulse.value;
|
|
204
|
+
|
|
205
|
+
// Float the group
|
|
206
|
+
const float = Motion.float(
|
|
207
|
+
{ x: 0, y: 0 },
|
|
208
|
+
this.animTime,
|
|
209
|
+
5, // 5 second cycle
|
|
210
|
+
0.5, // speed
|
|
211
|
+
0.5, // randomness
|
|
212
|
+
50, // radius
|
|
213
|
+
true,
|
|
214
|
+
Easing.easeInOutSine
|
|
215
|
+
);
|
|
216
|
+
this.group.x = float.x;
|
|
217
|
+
this.group.y = float.y;
|
|
218
|
+
|
|
219
|
+
super.update(dt);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
render() {
|
|
223
|
+
this.group.render();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* DemoGame - Main game class
|
|
229
|
+
*/
|
|
230
|
+
class DemoGame extends Game {
|
|
231
|
+
constructor(canvas) {
|
|
232
|
+
super(canvas);
|
|
233
|
+
this.enableFluidSize();
|
|
234
|
+
this.backgroundColor = 'black';
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
init() {
|
|
238
|
+
super.init();
|
|
239
|
+
|
|
240
|
+
// Create main scene
|
|
241
|
+
this.gameScene = new Scene(this);
|
|
242
|
+
this.gameScene.add(new HelloWorldBox(this));
|
|
243
|
+
this.pipeline.add(this.gameScene);
|
|
244
|
+
|
|
245
|
+
// Add orbiting circle
|
|
246
|
+
this.floatingCircle = new Circle(30, {
|
|
247
|
+
x: this.width / 2 + 200,
|
|
248
|
+
y: this.height / 2,
|
|
249
|
+
color: '#0f0'
|
|
250
|
+
});
|
|
251
|
+
this.floatingCircle.animTime = 0;
|
|
252
|
+
this.pipeline.add(this.floatingCircle);
|
|
253
|
+
|
|
254
|
+
// Add FPS counter
|
|
255
|
+
this.pipeline.add(new FPSCounter(this, {
|
|
256
|
+
anchor: 'bottom-right'
|
|
257
|
+
}));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
update(dt) {
|
|
261
|
+
super.update(dt);
|
|
262
|
+
|
|
263
|
+
// Center the scene
|
|
264
|
+
this.gameScene.x = this.width / 2;
|
|
265
|
+
this.gameScene.y = this.height / 2;
|
|
266
|
+
|
|
267
|
+
// Orbit the circle
|
|
268
|
+
this.floatingCircle.animTime += dt;
|
|
269
|
+
const orbit = Motion.orbit(
|
|
270
|
+
this.width / 2, this.height / 2,
|
|
271
|
+
200, 200, // radius X, Y
|
|
272
|
+
0, // start angle
|
|
273
|
+
this.floatingCircle.animTime,
|
|
274
|
+
8, // 8 second orbit
|
|
275
|
+
true, // loop
|
|
276
|
+
true // clockwise
|
|
277
|
+
);
|
|
278
|
+
this.floatingCircle.x = orbit.x;
|
|
279
|
+
this.floatingCircle.y = orbit.y;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Run the game
|
|
284
|
+
window.addEventListener('load', () => {
|
|
285
|
+
const canvas = document.getElementById('game');
|
|
286
|
+
const game = new DemoGame(canvas);
|
|
287
|
+
game.start();
|
|
288
|
+
});
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## HTML Template
|
|
292
|
+
|
|
293
|
+
```html
|
|
294
|
+
<!DOCTYPE html>
|
|
295
|
+
<html>
|
|
296
|
+
<head>
|
|
297
|
+
<meta charset="UTF-8">
|
|
298
|
+
<title>My First Game</title>
|
|
299
|
+
<style>
|
|
300
|
+
body { margin: 0; overflow: hidden; }
|
|
301
|
+
canvas { display: block; }
|
|
302
|
+
</style>
|
|
303
|
+
</head>
|
|
304
|
+
<body>
|
|
305
|
+
<canvas id="game"></canvas>
|
|
306
|
+
<script type="module" src="./game.js"></script>
|
|
307
|
+
</body>
|
|
308
|
+
</html>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Key Concepts
|
|
312
|
+
|
|
313
|
+
| Concept | Description |
|
|
314
|
+
|---------|-------------|
|
|
315
|
+
| `Game` | Main class managing loop, canvas, input |
|
|
316
|
+
| `Scene` | Container for GameObjects |
|
|
317
|
+
| `GameObject` | Interactive entity with update/render |
|
|
318
|
+
| `enableInteractivity(shape)` | Enable click/hover on a shape |
|
|
319
|
+
| `dt` | Delta time in seconds |
|
|
320
|
+
| `game.input.isKeyDown(key)` | Check if key is pressed |
|
|
321
|
+
| `Motion.*` | Animation helper functions |
|
|
322
|
+
| `FPSCounter` | Built-in FPS display |
|
|
323
|
+
|
|
324
|
+
## Input Reference
|
|
325
|
+
|
|
326
|
+
```js
|
|
327
|
+
// Keyboard
|
|
328
|
+
game.input.isKeyDown('ArrowUp')
|
|
329
|
+
game.input.isKeyDown('KeyW')
|
|
330
|
+
game.input.isKeyDown('Space')
|
|
331
|
+
|
|
332
|
+
// Mouse position
|
|
333
|
+
game.mouse.x
|
|
334
|
+
game.mouse.y
|
|
335
|
+
|
|
336
|
+
// GameObject events
|
|
337
|
+
onPointerDown(e) { }
|
|
338
|
+
onPointerUp(e) { }
|
|
339
|
+
onPointerMove(e) { }
|
|
340
|
+
onMouseOver() { }
|
|
341
|
+
onMouseOut() { }
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## Next Steps
|
|
345
|
+
|
|
346
|
+
- [Game Module](../modules/game/README.md) - Full Game API reference
|
|
347
|
+
- [Motion Patterns](../modules/motion/README.md) - Animation functions
|
|
348
|
+
- [Input Handling](../modules/io/README.md) - Mouse, keyboard, touch
|
|
349
|
+
|
|
350
|
+
## Related
|
|
351
|
+
|
|
352
|
+
- [Hello World](./hello-world.md)
|
|
353
|
+
- [Two-Layer Architecture](../concepts/two-layer-architecture.md)
|
|
354
|
+
- [Game Lifecycle](../concepts/lifecycle.md)
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# Hello World
|
|
2
|
+
|
|
3
|
+
> Draw your first shape with GCanvas.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This guide shows the simplest way to draw a shape on canvas using GCanvas. We'll start with the Shape Layer (no game loop) and progress to a simple animation.
|
|
8
|
+
|
|
9
|
+
## Basic Setup
|
|
10
|
+
|
|
11
|
+
Create an HTML file with a canvas:
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<!DOCTYPE html>
|
|
15
|
+
<html>
|
|
16
|
+
<head>
|
|
17
|
+
<title>GCanvas Hello World</title>
|
|
18
|
+
<style>
|
|
19
|
+
body { margin: 0; background: #000; }
|
|
20
|
+
canvas { display: block; }
|
|
21
|
+
</style>
|
|
22
|
+
</head>
|
|
23
|
+
<body>
|
|
24
|
+
<canvas id="canvas" width="800" height="600"></canvas>
|
|
25
|
+
<script type="module">
|
|
26
|
+
// Your code here
|
|
27
|
+
</script>
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Step 1: Draw a Circle
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
import { Circle, Painter } from './dist/gcanvas.es.min.js';
|
|
36
|
+
|
|
37
|
+
// Get canvas and initialize Painter
|
|
38
|
+
const canvas = document.getElementById('canvas');
|
|
39
|
+
Painter.init(canvas.getContext('2d'));
|
|
40
|
+
|
|
41
|
+
// Create a circle
|
|
42
|
+
const circle = new Circle(50, {
|
|
43
|
+
x: 400,
|
|
44
|
+
y: 300,
|
|
45
|
+
color: 'red'
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Draw it
|
|
49
|
+
circle.draw();
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Result:** A red circle with radius 50, centered at (400, 300).
|
|
53
|
+
|
|
54
|
+
## Step 2: Add More Shapes
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
import { Circle, Rectangle, Star, Painter } from './dist/gcanvas.es.min.js';
|
|
58
|
+
|
|
59
|
+
const canvas = document.getElementById('canvas');
|
|
60
|
+
Painter.init(canvas.getContext('2d'));
|
|
61
|
+
|
|
62
|
+
// Circle
|
|
63
|
+
const circle = new Circle(50, {
|
|
64
|
+
x: 200,
|
|
65
|
+
y: 300,
|
|
66
|
+
color: '#ff6b6b'
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Rectangle
|
|
70
|
+
const rect = new Rectangle({
|
|
71
|
+
x: 400,
|
|
72
|
+
y: 300,
|
|
73
|
+
width: 120,
|
|
74
|
+
height: 80,
|
|
75
|
+
color: '#4ecdc4',
|
|
76
|
+
stroke: '#fff',
|
|
77
|
+
lineWidth: 2
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Star
|
|
81
|
+
const star = new Star(40, 5, {
|
|
82
|
+
x: 600,
|
|
83
|
+
y: 300,
|
|
84
|
+
color: '#ffe66d',
|
|
85
|
+
rotation: Math.PI / 10
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Draw all shapes
|
|
89
|
+
circle.draw();
|
|
90
|
+
rect.draw();
|
|
91
|
+
star.draw();
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Step 3: Group Shapes Together
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
import { Circle, Rectangle, TextShape, Group, Painter } from './dist/gcanvas.es.min.js';
|
|
98
|
+
|
|
99
|
+
const canvas = document.getElementById('canvas');
|
|
100
|
+
Painter.init(canvas.getContext('2d'));
|
|
101
|
+
|
|
102
|
+
// Create a group
|
|
103
|
+
const group = new Group({ x: 400, y: 300 });
|
|
104
|
+
|
|
105
|
+
// Add shapes to the group (positions relative to group)
|
|
106
|
+
group.add(new Rectangle({
|
|
107
|
+
width: 200,
|
|
108
|
+
height: 80,
|
|
109
|
+
color: '#333',
|
|
110
|
+
stroke: '#0f0',
|
|
111
|
+
lineWidth: 2
|
|
112
|
+
}));
|
|
113
|
+
|
|
114
|
+
group.add(new TextShape('Hello World!', {
|
|
115
|
+
font: '24px monospace',
|
|
116
|
+
color: '#0f0',
|
|
117
|
+
align: 'center',
|
|
118
|
+
baseline: 'middle'
|
|
119
|
+
}));
|
|
120
|
+
|
|
121
|
+
// Draw the group
|
|
122
|
+
group.draw();
|
|
123
|
+
|
|
124
|
+
// Rotate the entire group
|
|
125
|
+
group.rotation = Math.PI / 12; // 15 degrees
|
|
126
|
+
Painter.clear();
|
|
127
|
+
group.draw();
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Step 4: Simple Animation
|
|
131
|
+
|
|
132
|
+
Add a render loop for animation:
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
import { Circle, Painter } from './dist/gcanvas.es.min.js';
|
|
136
|
+
|
|
137
|
+
const canvas = document.getElementById('canvas');
|
|
138
|
+
const ctx = canvas.getContext('2d');
|
|
139
|
+
Painter.init(ctx);
|
|
140
|
+
|
|
141
|
+
// Create a circle
|
|
142
|
+
const circle = new Circle(50, {
|
|
143
|
+
x: 400,
|
|
144
|
+
y: 300,
|
|
145
|
+
color: '#4ecdc4'
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Animation variables
|
|
149
|
+
let time = 0;
|
|
150
|
+
|
|
151
|
+
function animate() {
|
|
152
|
+
// Clear canvas
|
|
153
|
+
Painter.clear();
|
|
154
|
+
|
|
155
|
+
// Update circle position (oscillate)
|
|
156
|
+
time += 0.02;
|
|
157
|
+
circle.x = 400 + Math.sin(time) * 200;
|
|
158
|
+
circle.y = 300 + Math.cos(time * 0.5) * 100;
|
|
159
|
+
|
|
160
|
+
// Pulse the opacity
|
|
161
|
+
circle.opacity = 0.5 + Math.sin(time * 2) * 0.5;
|
|
162
|
+
|
|
163
|
+
// Draw
|
|
164
|
+
circle.draw();
|
|
165
|
+
|
|
166
|
+
// Next frame
|
|
167
|
+
requestAnimationFrame(animate);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Start animation
|
|
171
|
+
animate();
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Complete Example
|
|
175
|
+
|
|
176
|
+
Here's a complete example with multiple animated shapes:
|
|
177
|
+
|
|
178
|
+
```html
|
|
179
|
+
<!DOCTYPE html>
|
|
180
|
+
<html>
|
|
181
|
+
<head>
|
|
182
|
+
<title>GCanvas Hello World</title>
|
|
183
|
+
<style>
|
|
184
|
+
body { margin: 0; background: #1a1a2e; overflow: hidden; }
|
|
185
|
+
canvas { display: block; }
|
|
186
|
+
</style>
|
|
187
|
+
</head>
|
|
188
|
+
<body>
|
|
189
|
+
<canvas id="canvas"></canvas>
|
|
190
|
+
<script type="module">
|
|
191
|
+
import { Circle, Rectangle, Star, Group, Painter } from './dist/gcanvas.es.min.js';
|
|
192
|
+
|
|
193
|
+
// Setup
|
|
194
|
+
const canvas = document.getElementById('canvas');
|
|
195
|
+
canvas.width = window.innerWidth;
|
|
196
|
+
canvas.height = window.innerHeight;
|
|
197
|
+
Painter.init(canvas.getContext('2d'));
|
|
198
|
+
|
|
199
|
+
const centerX = canvas.width / 2;
|
|
200
|
+
const centerY = canvas.height / 2;
|
|
201
|
+
|
|
202
|
+
// Create shapes
|
|
203
|
+
const circle = new Circle(60, { color: '#ff6b6b' });
|
|
204
|
+
const rect = new Rectangle({ width: 100, height: 60, color: '#4ecdc4' });
|
|
205
|
+
const star = new Star(40, 5, { color: '#ffe66d' });
|
|
206
|
+
|
|
207
|
+
let time = 0;
|
|
208
|
+
|
|
209
|
+
function animate() {
|
|
210
|
+
Painter.clear();
|
|
211
|
+
time += 0.016;
|
|
212
|
+
|
|
213
|
+
// Orbit the shapes around center
|
|
214
|
+
const radius = 150;
|
|
215
|
+
|
|
216
|
+
circle.x = centerX + Math.cos(time) * radius;
|
|
217
|
+
circle.y = centerY + Math.sin(time) * radius;
|
|
218
|
+
|
|
219
|
+
rect.x = centerX + Math.cos(time + Math.PI * 0.66) * radius;
|
|
220
|
+
rect.y = centerY + Math.sin(time + Math.PI * 0.66) * radius;
|
|
221
|
+
rect.rotation = time;
|
|
222
|
+
|
|
223
|
+
star.x = centerX + Math.cos(time + Math.PI * 1.33) * radius;
|
|
224
|
+
star.y = centerY + Math.sin(time + Math.PI * 1.33) * radius;
|
|
225
|
+
star.rotation = -time * 2;
|
|
226
|
+
|
|
227
|
+
// Draw
|
|
228
|
+
circle.draw();
|
|
229
|
+
rect.draw();
|
|
230
|
+
star.draw();
|
|
231
|
+
|
|
232
|
+
requestAnimationFrame(animate);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
animate();
|
|
236
|
+
|
|
237
|
+
// Handle resize
|
|
238
|
+
window.addEventListener('resize', () => {
|
|
239
|
+
canvas.width = window.innerWidth;
|
|
240
|
+
canvas.height = window.innerHeight;
|
|
241
|
+
});
|
|
242
|
+
</script>
|
|
243
|
+
</body>
|
|
244
|
+
</html>
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Key Concepts
|
|
248
|
+
|
|
249
|
+
| Concept | Description |
|
|
250
|
+
|---------|-------------|
|
|
251
|
+
| `Painter.init(ctx)` | Initialize the drawing system with canvas context |
|
|
252
|
+
| `Painter.clear()` | Clear the entire canvas |
|
|
253
|
+
| `shape.draw()` | Draw a shape at its current position |
|
|
254
|
+
| `shape.x`, `shape.y` | Position (center of shape) |
|
|
255
|
+
| `shape.rotation` | Rotation in radians |
|
|
256
|
+
| `shape.opacity` | Transparency (0 to 1) |
|
|
257
|
+
| `Group` | Container for multiple shapes |
|
|
258
|
+
|
|
259
|
+
## Next Steps
|
|
260
|
+
|
|
261
|
+
- [First Game](./first-game.md) - Add interactivity with the Game layer
|
|
262
|
+
- [Rendering Pipeline](../concepts/rendering-pipeline.md) - Understand the shape hierarchy
|
|
263
|
+
- [Shapes Module](../modules/shapes/README.md) - Explore all available shapes
|
|
264
|
+
|
|
265
|
+
## Related
|
|
266
|
+
|
|
267
|
+
- [Installation](./installation.md)
|
|
268
|
+
- [Two-Layer Architecture](../concepts/two-layer-architecture.md)
|
|
269
|
+
- [Shapes Module](../modules/shapes/README.md)
|