@where-stars-drift/core 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/LICENSE +20 -0
- package/README.md +143 -0
- package/dist/src/base/bounded-body.d.ts +8 -0
- package/dist/src/base/bounded-body.js +10 -0
- package/dist/src/base/celestial-body.d.ts +12 -0
- package/dist/src/base/celestial-body.js +11 -0
- package/dist/src/base/hoverable.d.ts +10 -0
- package/dist/src/base/hoverable.js +4 -0
- package/dist/src/base/massive-body.d.ts +8 -0
- package/dist/src/base/massive-body.js +10 -0
- package/dist/src/config/effects.d.ts +14 -0
- package/dist/src/config/effects.js +14 -0
- package/dist/src/config/grid.d.ts +10 -0
- package/dist/src/config/grid.js +10 -0
- package/dist/src/config/panel.d.ts +26 -0
- package/dist/src/config/panel.js +26 -0
- package/dist/src/config/simulation.d.ts +21 -0
- package/dist/src/config/simulation.js +23 -0
- package/dist/src/controllers/clan-controller.d.ts +7 -0
- package/dist/src/controllers/clan-controller.js +12 -0
- package/dist/src/controllers/debug-controller.d.ts +45 -0
- package/dist/src/controllers/debug-controller.js +82 -0
- package/dist/src/controllers/effects-controller.d.ts +17 -0
- package/dist/src/controllers/effects-controller.js +71 -0
- package/dist/src/controllers/hover-controller.d.ts +11 -0
- package/dist/src/controllers/hover-controller.js +107 -0
- package/dist/src/controllers/layer-controller.d.ts +16 -0
- package/dist/src/controllers/layer-controller.js +64 -0
- package/dist/src/controllers/physics-controller.d.ts +14 -0
- package/dist/src/controllers/physics-controller.js +152 -0
- package/dist/src/controllers/star-controller.d.ts +12 -0
- package/dist/src/controllers/star-controller.js +38 -0
- package/dist/src/controllers/starship-controller.d.ts +17 -0
- package/dist/src/controllers/starship-controller.js +58 -0
- package/dist/src/draw-debug-line.d.ts +9 -0
- package/dist/src/draw-debug-line.js +29 -0
- package/dist/src/entities/black-hole-factory.d.ts +15 -0
- package/dist/src/entities/black-hole-factory.js +23 -0
- package/dist/src/entities/black-hole-shapes.d.ts +9 -0
- package/dist/src/entities/black-hole-shapes.js +224 -0
- package/dist/src/entities/black-hole.d.ts +69 -0
- package/dist/src/entities/black-hole.js +210 -0
- package/dist/src/entities/clan-manager.d.ts +12 -0
- package/dist/src/entities/clan-manager.js +22 -0
- package/dist/src/entities/clans.d.ts +15 -0
- package/dist/src/entities/clans.js +76 -0
- package/dist/src/entities/comet.d.ts +27 -0
- package/dist/src/entities/comet.js +81 -0
- package/dist/src/entities/docking-point.d.ts +20 -0
- package/dist/src/entities/docking-point.js +22 -0
- package/dist/src/entities/fleet.d.ts +45 -0
- package/dist/src/entities/fleet.js +374 -0
- package/dist/src/entities/formations.d.ts +51 -0
- package/dist/src/entities/formations.js +340 -0
- package/dist/src/entities/meteor.d.ts +26 -0
- package/dist/src/entities/meteor.js +48 -0
- package/dist/src/entities/nebula.d.ts +18 -0
- package/dist/src/entities/nebula.js +43 -0
- package/dist/src/entities/orbit.d.ts +23 -0
- package/dist/src/entities/orbit.js +43 -0
- package/dist/src/entities/pulsar.d.ts +18 -0
- package/dist/src/entities/pulsar.js +41 -0
- package/dist/src/entities/ring.d.ts +13 -0
- package/dist/src/entities/ring.js +26 -0
- package/dist/src/entities/ringed-planet.d.ts +21 -0
- package/dist/src/entities/ringed-planet.js +68 -0
- package/dist/src/entities/sector-grid.d.ts +16 -0
- package/dist/src/entities/sector-grid.js +70 -0
- package/dist/src/entities/star-factory.d.ts +29 -0
- package/dist/src/entities/star-factory.js +47 -0
- package/dist/src/entities/star.d.ts +48 -0
- package/dist/src/entities/star.js +167 -0
- package/dist/src/entities/starship-classes.d.ts +0 -0
- package/dist/src/entities/starship-classes.js +2 -0
- package/dist/src/entities/starship.d.ts +91 -0
- package/dist/src/entities/starship.js +760 -0
- package/dist/src/entities/supernova.d.ts +26 -0
- package/dist/src/entities/supernova.js +54 -0
- package/dist/src/index.d.ts +20 -0
- package/dist/src/index.js +19 -0
- package/dist/src/lib/energy-stream.d.ts +5 -0
- package/dist/src/lib/energy-stream.js +98 -0
- package/dist/src/lib/quadtree.d.ts +31 -0
- package/dist/src/lib/quadtree.js +124 -0
- package/dist/src/lib/simplified-stream.d.ts +6 -0
- package/dist/src/lib/simplified-stream.js +19 -0
- package/dist/src/types.d.ts +14 -0
- package/dist/src/types.js +1 -0
- package/dist/src/ui/black-holes-panel.d.ts +2 -0
- package/dist/src/ui/black-holes-panel.js +76 -0
- package/dist/src/ui/clans-panel.d.ts +2 -0
- package/dist/src/ui/clans-panel.js +20 -0
- package/dist/src/ui/debug-panel-controller.d.ts +41 -0
- package/dist/src/ui/debug-panel-controller.js +285 -0
- package/dist/src/ui/fleets-panel.d.ts +2 -0
- package/dist/src/ui/fleets-panel.js +127 -0
- package/dist/src/ui/formations-panel.d.ts +3 -0
- package/dist/src/ui/formations-panel.js +129 -0
- package/dist/src/ui/panel-config.d.ts +26 -0
- package/dist/src/ui/panel-config.js +26 -0
- package/dist/src/ui/ships-panel.d.ts +12 -0
- package/dist/src/ui/ships-panel.js +61 -0
- package/dist/src/ui/stars-panel.d.ts +2 -0
- package/dist/src/ui/stars-panel.js +120 -0
- package/dist/src/where-stars-drift.d.ts +71 -0
- package/dist/src/where-stars-drift.js +440 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +35 -0
- package/src/base/bounded-body.ts +14 -0
- package/src/base/celestial-body.ts +20 -0
- package/src/base/hoverable.ts +11 -0
- package/src/base/massive-body.ts +14 -0
- package/src/config/effects.ts +15 -0
- package/src/config/grid.ts +11 -0
- package/src/config/panel.ts +26 -0
- package/src/config/simulation.ts +25 -0
- package/src/controllers/clan-controller.ts +19 -0
- package/src/controllers/debug-controller.ts +112 -0
- package/src/controllers/effects-controller.ts +86 -0
- package/src/controllers/hover-controller.ts +128 -0
- package/src/controllers/layer-controller.ts +78 -0
- package/src/controllers/physics-controller.ts +173 -0
- package/src/controllers/star-controller.ts +51 -0
- package/src/controllers/starship-controller.ts +76 -0
- package/src/draw-debug-line.ts +37 -0
- package/src/entities/black-hole-factory.ts +28 -0
- package/src/entities/black-hole-shapes.ts +276 -0
- package/src/entities/black-hole.ts +246 -0
- package/src/entities/clan-manager.ts +33 -0
- package/src/entities/clans.ts +98 -0
- package/src/entities/comet.ts +102 -0
- package/src/entities/docking-point.ts +34 -0
- package/src/entities/fleet.ts +446 -0
- package/src/entities/formations.ts +423 -0
- package/src/entities/meteor.ts +59 -0
- package/src/entities/nebula.ts +50 -0
- package/src/entities/orbit.ts +53 -0
- package/src/entities/pulsar.ts +64 -0
- package/src/entities/ring.ts +42 -0
- package/src/entities/ringed-planet.ts +85 -0
- package/src/entities/sector-grid.ts +81 -0
- package/src/entities/star-factory.ts +59 -0
- package/src/entities/star.ts +222 -0
- package/src/entities/starship-classes.ts +1 -0
- package/src/entities/starship.ts +906 -0
- package/src/entities/supernova.ts +75 -0
- package/src/index.ts +24 -0
- package/src/lib/energy-stream.ts +127 -0
- package/src/lib/quadtree.ts +159 -0
- package/src/lib/simplified-stream.ts +28 -0
- package/src/types.ts +16 -0
- package/src/ui/black-holes-panel.ts +91 -0
- package/src/ui/clans-panel.ts +27 -0
- package/src/ui/debug-panel-controller.ts +339 -0
- package/src/ui/fleets-panel.ts +153 -0
- package/src/ui/formations-panel.ts +155 -0
- package/src/ui/panel-config.ts +26 -0
- package/src/ui/ships-panel.ts +85 -0
- package/src/ui/stars-panel.ts +146 -0
- package/src/where-stars-drift.ts +542 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Defines all black hole shape rendering functions.
|
|
3
|
+
*/
|
|
4
|
+
import { BLACK_HOLE_CONFIG } from './black-hole';
|
|
5
|
+
export const drawStandardShape = (ctx, hole) => {
|
|
6
|
+
// A simple white glow from behind
|
|
7
|
+
const ringRadius = hole.radius * 1.5;
|
|
8
|
+
ctx.save();
|
|
9
|
+
ctx.shadowColor = `rgba(255, 255, 255, 0.7)`;
|
|
10
|
+
ctx.shadowBlur = 20;
|
|
11
|
+
// Draw the black hole itself, the shadow will create the glow
|
|
12
|
+
ctx.beginPath();
|
|
13
|
+
ctx.fillStyle = hole.color;
|
|
14
|
+
ctx.arc(hole.x, hole.y, hole.radius, 0, Math.PI * 2);
|
|
15
|
+
ctx.fill();
|
|
16
|
+
ctx.restore();
|
|
17
|
+
};
|
|
18
|
+
export const drawWarpedDiskShape = (ctx, hole) => {
|
|
19
|
+
const config = BLACK_HOLE_CONFIG.WARPED_DISK;
|
|
20
|
+
const diskRadius = hole.radius * 2.5;
|
|
21
|
+
// 1. Draw outer, faint, warped lines
|
|
22
|
+
ctx.save();
|
|
23
|
+
ctx.translate(hole.x, hole.y);
|
|
24
|
+
ctx.globalCompositeOperation = 'lighter';
|
|
25
|
+
for (let i = 0; i < config.WARPED_LINE_COUNT; i++) {
|
|
26
|
+
const progress = i / config.WARPED_LINE_COUNT;
|
|
27
|
+
const startRadius = diskRadius * (1.5 + progress * 2);
|
|
28
|
+
const endRadius = diskRadius * (1.1 - progress * 0.2);
|
|
29
|
+
const startAngle = hole.warpAngle + progress * Math.PI * 0.4;
|
|
30
|
+
const endAngle = hole.warpAngle + Math.PI * 0.2 + progress * Math.PI * 0.8;
|
|
31
|
+
const startX = Math.cos(startAngle) * startRadius;
|
|
32
|
+
const startY = Math.sin(startAngle) * startRadius;
|
|
33
|
+
const endX = Math.cos(endAngle) * endRadius;
|
|
34
|
+
const endY = Math.sin(endAngle) * endRadius;
|
|
35
|
+
const cp1x = Math.cos(startAngle + 0.5) * startRadius * 0.8;
|
|
36
|
+
const cp1y = Math.sin(startAngle + 0.5) * startRadius * 0.8;
|
|
37
|
+
const cp2x = Math.cos(endAngle - 0.5) * endRadius * 1.2;
|
|
38
|
+
const cp2y = Math.sin(endAngle - 0.5) * endRadius * 1.2;
|
|
39
|
+
ctx.beginPath();
|
|
40
|
+
ctx.moveTo(startX, startY);
|
|
41
|
+
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, endX, endY);
|
|
42
|
+
ctx.strokeStyle = `rgba(255, 200, 150, ${0.05 + progress * 0.1})`;
|
|
43
|
+
ctx.lineWidth = 0.5 + progress * 1.0;
|
|
44
|
+
ctx.stroke();
|
|
45
|
+
}
|
|
46
|
+
ctx.restore();
|
|
47
|
+
// 2. Draw main accretion disk
|
|
48
|
+
ctx.save();
|
|
49
|
+
ctx.translate(hole.x, hole.y);
|
|
50
|
+
const gradient = ctx.createRadialGradient(0, 0, hole.radius, 0, 0, diskRadius);
|
|
51
|
+
gradient.addColorStop(0.3, config.DISK_COLOR_INNER);
|
|
52
|
+
gradient.addColorStop(0.6, config.DISK_COLOR_OUTER);
|
|
53
|
+
gradient.addColorStop(1, 'rgba(255, 150, 0, 0)');
|
|
54
|
+
ctx.strokeStyle = gradient;
|
|
55
|
+
ctx.lineWidth = hole.radius * 1.5;
|
|
56
|
+
ctx.shadowColor = config.DISK_COLOR_INNER;
|
|
57
|
+
ctx.shadowBlur = 30;
|
|
58
|
+
ctx.beginPath();
|
|
59
|
+
ctx.arc(0, 0, diskRadius, 0, Math.PI * 2);
|
|
60
|
+
ctx.stroke();
|
|
61
|
+
ctx.restore();
|
|
62
|
+
// 3. Draw the black hole itself
|
|
63
|
+
ctx.beginPath();
|
|
64
|
+
ctx.fillStyle = hole.color;
|
|
65
|
+
ctx.arc(hole.x, hole.y, hole.radius, 0, Math.PI * 2);
|
|
66
|
+
ctx.fill();
|
|
67
|
+
// 4. Draw the diagonal "cut" which creates the 3D effect
|
|
68
|
+
ctx.save();
|
|
69
|
+
ctx.translate(hole.x, hole.y);
|
|
70
|
+
ctx.fillStyle = 'rgba(0,0,0,1)';
|
|
71
|
+
ctx.shadowColor = 'black';
|
|
72
|
+
ctx.shadowBlur = 5;
|
|
73
|
+
ctx.fillRect(-diskRadius * 1.5, -hole.radius * 0.1, diskRadius * 3, hole.radius * 0.2);
|
|
74
|
+
ctx.restore();
|
|
75
|
+
ctx.shadowBlur = 0;
|
|
76
|
+
};
|
|
77
|
+
export const drawLensingShape = (ctx, hole) => {
|
|
78
|
+
// Gravitational Lensing Effect
|
|
79
|
+
const ringRadius = hole.radius * 1.5;
|
|
80
|
+
ctx.save();
|
|
81
|
+
ctx.shadowColor = `rgba(255, 255, 255, 0.5)`;
|
|
82
|
+
ctx.shadowBlur = 50;
|
|
83
|
+
ctx.beginPath();
|
|
84
|
+
ctx.strokeStyle = `rgba(255, 255, 255, 0.9)`;
|
|
85
|
+
ctx.lineWidth = hole.radius * 0.4;
|
|
86
|
+
ctx.arc(hole.x, hole.y, ringRadius, 0, Math.PI * 2);
|
|
87
|
+
ctx.stroke();
|
|
88
|
+
ctx.restore();
|
|
89
|
+
// Draw the black hole itself
|
|
90
|
+
ctx.beginPath();
|
|
91
|
+
ctx.fillStyle = hole.color;
|
|
92
|
+
ctx.arc(hole.x, hole.y, hole.radius, 0, Math.PI * 2);
|
|
93
|
+
ctx.fill();
|
|
94
|
+
};
|
|
95
|
+
export const drawAccretionDiskShape = (ctx, hole) => {
|
|
96
|
+
const diskRadius = hole.radius * 2.5;
|
|
97
|
+
const glowRadius = diskRadius * 0.6;
|
|
98
|
+
const config = BLACK_HOLE_CONFIG.ACCRETION_DISK;
|
|
99
|
+
// --- Draw Relativistic Jets ---
|
|
100
|
+
ctx.save();
|
|
101
|
+
ctx.translate(hole.x, hole.y);
|
|
102
|
+
ctx.rotate(hole.accretionDiskAngle);
|
|
103
|
+
ctx.globalCompositeOperation = 'lighter';
|
|
104
|
+
// Animate the nozzle length only every 5 frames for performance
|
|
105
|
+
if (hole.frameCount % 5 === 0) {
|
|
106
|
+
const maxNozzleLength = diskRadius * 1.1;
|
|
107
|
+
// nozzleLengthMultiplier will be between 0.5 (50%) and 1.0 (100%)
|
|
108
|
+
const nozzleLengthMultiplier = Math.random() * 0.5 + 0.5;
|
|
109
|
+
hole.nozzleLength = maxNozzleLength * nozzleLengthMultiplier;
|
|
110
|
+
}
|
|
111
|
+
// Always draw the jets using the cached nozzleLength
|
|
112
|
+
if (hole.nozzleLength > 0) {
|
|
113
|
+
ctx.shadowColor = 'white';
|
|
114
|
+
ctx.shadowBlur = 15;
|
|
115
|
+
const nozzleBaseWidth = hole.radius * 2; // Base is 2x the hole's radius
|
|
116
|
+
const jetColor = `rgba(200, 220, 255, ${0.1 + (hole.nozzleLength / (diskRadius * 1.1)) * 0.3})`;
|
|
117
|
+
ctx.fillStyle = jetColor;
|
|
118
|
+
// Jet 1 (positive x direction)
|
|
119
|
+
ctx.beginPath();
|
|
120
|
+
ctx.moveTo(hole.nozzleLength, 0); // Tip of the jet
|
|
121
|
+
ctx.lineTo(0, nozzleBaseWidth / 2); // Base centered at the hole
|
|
122
|
+
ctx.lineTo(0, -nozzleBaseWidth / 2); // Base centered at the hole
|
|
123
|
+
ctx.closePath();
|
|
124
|
+
ctx.fill();
|
|
125
|
+
// Jet 2 (negative x direction)
|
|
126
|
+
ctx.beginPath();
|
|
127
|
+
ctx.moveTo(-hole.nozzleLength, 0); // Tip of the jet
|
|
128
|
+
ctx.lineTo(0, nozzleBaseWidth / 2); // Base centered at the hole
|
|
129
|
+
ctx.lineTo(0, -nozzleBaseWidth / 2); // Base centered at the hole
|
|
130
|
+
ctx.closePath();
|
|
131
|
+
ctx.fill();
|
|
132
|
+
}
|
|
133
|
+
ctx.restore();
|
|
134
|
+
// 1. Draw the outer glow
|
|
135
|
+
ctx.save();
|
|
136
|
+
ctx.translate(hole.x, hole.y);
|
|
137
|
+
const glowGradient = ctx.createRadialGradient(0, 0, hole.radius, 0, 0, glowRadius);
|
|
138
|
+
glowGradient.addColorStop(0.2, config.GLOW_COLOR);
|
|
139
|
+
glowGradient.addColorStop(1, 'rgba(180, 210, 255, 0)');
|
|
140
|
+
ctx.fillStyle = glowGradient;
|
|
141
|
+
ctx.shadowColor = config.GLOW_COLOR;
|
|
142
|
+
ctx.shadowBlur = 30;
|
|
143
|
+
ctx.beginPath();
|
|
144
|
+
ctx.arc(0, 0, glowRadius, 0, Math.PI * 2);
|
|
145
|
+
ctx.fill();
|
|
146
|
+
ctx.restore();
|
|
147
|
+
// 2. Draw the black hole event horizon
|
|
148
|
+
ctx.beginPath();
|
|
149
|
+
ctx.fillStyle = hole.color;
|
|
150
|
+
ctx.arc(hole.x, hole.y, hole.radius, 0, Math.PI * 2);
|
|
151
|
+
ctx.fill();
|
|
152
|
+
// 3. Draw the flat white line crossing the front
|
|
153
|
+
ctx.save();
|
|
154
|
+
ctx.translate(hole.x, hole.y);
|
|
155
|
+
ctx.rotate(hole.accretionDiskAngle);
|
|
156
|
+
const lineGradient = ctx.createLinearGradient(-diskRadius * 1.1, 0, diskRadius * 1.1, 0);
|
|
157
|
+
lineGradient.addColorStop(0, 'rgba(255, 255, 255, 0)');
|
|
158
|
+
lineGradient.addColorStop(0.25, 'rgba(255, 255, 255, 0.95)');
|
|
159
|
+
lineGradient.addColorStop(0.75, 'rgba(255, 255, 255, 0.95)');
|
|
160
|
+
lineGradient.addColorStop(1, 'rgba(255, 255, 255, 0)');
|
|
161
|
+
ctx.fillStyle = lineGradient;
|
|
162
|
+
ctx.shadowColor = 'white';
|
|
163
|
+
ctx.shadowBlur = 15;
|
|
164
|
+
const lineHeight = hole.radius * 0.35;
|
|
165
|
+
ctx.fillRect(-diskRadius * 1.1, -lineHeight / 2, diskRadius * 2.2, lineHeight);
|
|
166
|
+
ctx.restore();
|
|
167
|
+
ctx.shadowBlur = 0;
|
|
168
|
+
};
|
|
169
|
+
export const drawVortexShape = (ctx, hole) => {
|
|
170
|
+
const config = BLACK_HOLE_CONFIG.VORTEX;
|
|
171
|
+
const outerRadius = hole.radius * 5;
|
|
172
|
+
// 1. Draw the vast, faint outer glow
|
|
173
|
+
ctx.save();
|
|
174
|
+
ctx.translate(hole.x, hole.y);
|
|
175
|
+
const outerGradient = ctx.createRadialGradient(0, 0, hole.radius, 0, 0, outerRadius);
|
|
176
|
+
outerGradient.addColorStop(0.3, config.VORTEX_COLOR_MID);
|
|
177
|
+
outerGradient.addColorStop(1, config.VORTEX_COLOR_OUTER);
|
|
178
|
+
ctx.fillStyle = outerGradient;
|
|
179
|
+
ctx.beginPath();
|
|
180
|
+
ctx.arc(0, 0, outerRadius, 0, Math.PI * 2);
|
|
181
|
+
ctx.fill();
|
|
182
|
+
ctx.restore();
|
|
183
|
+
// 2. Draw the swirling, fiery arms
|
|
184
|
+
ctx.save();
|
|
185
|
+
ctx.translate(hole.x, hole.y);
|
|
186
|
+
ctx.globalCompositeOperation = 'lighter';
|
|
187
|
+
for (let i = 0; i < config.PARTICLE_COUNT; i++) {
|
|
188
|
+
const progress = i / config.PARTICLE_COUNT;
|
|
189
|
+
const angle = hole.vortexAngle + progress * Math.PI * 2;
|
|
190
|
+
const startRadius = hole.radius * (1.2 + progress * 1.5);
|
|
191
|
+
const endRadius = hole.radius * (1.0 + progress * 1.0);
|
|
192
|
+
const flameColor = i % 2 === 0 ? `rgba(255, 220, 150, 0.15)` : `rgba(255, 180, 50, 0.1)`;
|
|
193
|
+
ctx.beginPath();
|
|
194
|
+
ctx.arc(0, 0, startRadius, angle, angle + Math.PI * 0.8);
|
|
195
|
+
ctx.arc(0, 0, endRadius, angle + Math.PI * 0.8, angle, true);
|
|
196
|
+
ctx.closePath();
|
|
197
|
+
ctx.fillStyle = flameColor;
|
|
198
|
+
ctx.shadowColor = 'rgba(255, 150, 0, 0.5)';
|
|
199
|
+
ctx.shadowBlur = 45;
|
|
200
|
+
ctx.fill();
|
|
201
|
+
}
|
|
202
|
+
ctx.restore();
|
|
203
|
+
// 3. Draw the bright inner ring
|
|
204
|
+
ctx.save();
|
|
205
|
+
ctx.translate(hole.x, hole.y);
|
|
206
|
+
const innerRingRadius = hole.radius * 1.2;
|
|
207
|
+
const innerGradient = ctx.createRadialGradient(0, 0, 0, 0, 0, innerRingRadius);
|
|
208
|
+
innerGradient.addColorStop(0, 'rgba(255, 255, 255, 0.9)');
|
|
209
|
+
innerGradient.addColorStop(0.7, config.VORTEX_COLOR_INNER);
|
|
210
|
+
innerGradient.addColorStop(1, 'rgba(255, 200, 0, 0)');
|
|
211
|
+
ctx.fillStyle = innerGradient;
|
|
212
|
+
ctx.shadowColor = 'rgba(255, 255, 255, 0.7)';
|
|
213
|
+
ctx.shadowBlur = 20;
|
|
214
|
+
ctx.beginPath();
|
|
215
|
+
ctx.arc(0, 0, innerRingRadius, 0, Math.PI * 2);
|
|
216
|
+
ctx.fill();
|
|
217
|
+
ctx.restore();
|
|
218
|
+
// 4. Draw the central black hole
|
|
219
|
+
ctx.beginPath();
|
|
220
|
+
ctx.fillStyle = hole.color;
|
|
221
|
+
ctx.arc(hole.x, hole.y, hole.radius, 0, Math.PI * 2);
|
|
222
|
+
ctx.fill();
|
|
223
|
+
ctx.shadowBlur = 0;
|
|
224
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Defines the BlackHle class for the night sky simulation.
|
|
3
|
+
*/
|
|
4
|
+
import { MassiveBody } from '../base/massive-body';
|
|
5
|
+
import type { Hoverable } from '../base/hoverable';
|
|
6
|
+
import { Star } from './star';
|
|
7
|
+
export declare const BLACK_HOLE_CONFIG: {
|
|
8
|
+
RADIUS_BASE: number;
|
|
9
|
+
RADIUS_VARIANCE: number;
|
|
10
|
+
MASS_MULTIPLIER: number;
|
|
11
|
+
HOVER_TIMEOUT: number;
|
|
12
|
+
INITIAL_VELOCITY_RANGE: number;
|
|
13
|
+
ATTRACTION_RADIUS: number;
|
|
14
|
+
STAR_ATTRACTION_RADIUS: number;
|
|
15
|
+
DECELERATION_DURATION: number;
|
|
16
|
+
PAUSE_DURATION: number;
|
|
17
|
+
ENERGY_STREAM_DISTANCE: number;
|
|
18
|
+
PULSE_FREQUENCY_MIN: number;
|
|
19
|
+
PULSE_FREQUENCY_VARIANCE: number;
|
|
20
|
+
ACCRETION_DISK: {
|
|
21
|
+
GLOW_COLOR: string;
|
|
22
|
+
};
|
|
23
|
+
VORTEX: {
|
|
24
|
+
PARTICLE_COUNT: number;
|
|
25
|
+
HOTSPOT_COUNT: number;
|
|
26
|
+
VORTEX_COLOR_INNER: string;
|
|
27
|
+
VORTEX_COLOR_MID: string;
|
|
28
|
+
VORTEX_COLOR_OUTER: string;
|
|
29
|
+
};
|
|
30
|
+
WARPED_DISK: {
|
|
31
|
+
WARPED_LINE_COUNT: number;
|
|
32
|
+
DISK_COLOR_INNER: string;
|
|
33
|
+
DISK_COLOR_OUTER: string;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export type BlackHoleType = 'LENSING' | 'ACCRETION_DISK' | 'VORTEX' | 'WARPED_DISK' | 'STANDARD';
|
|
37
|
+
type MergeState = 'IDLE' | 'DECELERATING' | 'PAUSED';
|
|
38
|
+
export declare class BlackHole extends MassiveBody implements Hoverable {
|
|
39
|
+
id: number;
|
|
40
|
+
name: string;
|
|
41
|
+
radius: number;
|
|
42
|
+
baseRadius: number;
|
|
43
|
+
color: string;
|
|
44
|
+
isHovered: boolean;
|
|
45
|
+
hoverRadius: number;
|
|
46
|
+
hoverTimer: number;
|
|
47
|
+
eatenStars: number;
|
|
48
|
+
type: BlackHoleType;
|
|
49
|
+
vortexAngle: number;
|
|
50
|
+
warpAngle: number;
|
|
51
|
+
accretionDiskAngle: number;
|
|
52
|
+
mergeState: MergeState;
|
|
53
|
+
mergeStateTimer: number;
|
|
54
|
+
preDecelerationVx: number;
|
|
55
|
+
preDecelerationVy: number;
|
|
56
|
+
attractionTargets: BlackHole[];
|
|
57
|
+
pulseFrequency: number;
|
|
58
|
+
pulsePhase: number;
|
|
59
|
+
nozzleLength: number;
|
|
60
|
+
nozzleColor: string | CanvasGradient | null;
|
|
61
|
+
frameCount: number;
|
|
62
|
+
constructor(x: number, y: number, type: BlackHoleType);
|
|
63
|
+
absorb(body: Star | BlackHole): void;
|
|
64
|
+
reset(x: number, y: number, vx: number, vy: number): void;
|
|
65
|
+
update(ctx: CanvasRenderingContext2D, width: number, height: number, frameCount: number): void;
|
|
66
|
+
private drawDebugInfo;
|
|
67
|
+
draw(ctx: CanvasRenderingContext2D, pulseTime: number, frameCount: number): void;
|
|
68
|
+
}
|
|
69
|
+
export { BlackHole as BlackHle };
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Defines the BlackHle class for the night sky simulation.
|
|
3
|
+
*/
|
|
4
|
+
import { MassiveBody } from '../base/massive-body';
|
|
5
|
+
import { DEBUG_CONFIG } from '../config/simulation';
|
|
6
|
+
import { Star } from './star';
|
|
7
|
+
import { drawAccretionDiskShape, drawLensingShape, drawVortexShape, drawWarpedDiskShape, drawStandardShape } from './black-hole-shapes';
|
|
8
|
+
import { drawEnergyStream } from '../lib/energy-stream';
|
|
9
|
+
import { EFFECTS_CONFIG } from '../config/effects';
|
|
10
|
+
// --- Black Hole Configuration ---
|
|
11
|
+
export const BLACK_HOLE_CONFIG = {
|
|
12
|
+
RADIUS_BASE: 8,
|
|
13
|
+
RADIUS_VARIANCE: 4,
|
|
14
|
+
MASS_MULTIPLIER: 500,
|
|
15
|
+
HOVER_TIMEOUT: 120,
|
|
16
|
+
INITIAL_VELOCITY_RANGE: 0.025,
|
|
17
|
+
ATTRACTION_RADIUS: 100, // Only attract other black holes within this distance
|
|
18
|
+
STAR_ATTRACTION_RADIUS: 100, // Only attract stars within this distance
|
|
19
|
+
DECELERATION_DURATION: 180, // 3 seconds at 60fps
|
|
20
|
+
PAUSE_DURATION: 1200, // 20 seconds at 60fps
|
|
21
|
+
ENERGY_STREAM_DISTANCE: 300,
|
|
22
|
+
PULSE_FREQUENCY_MIN: 0.5,
|
|
23
|
+
PULSE_FREQUENCY_VARIANCE: 1.0,
|
|
24
|
+
ACCRETION_DISK: {
|
|
25
|
+
GLOW_COLOR: 'rgba(180, 210, 255, 0.4)',
|
|
26
|
+
},
|
|
27
|
+
VORTEX: {
|
|
28
|
+
PARTICLE_COUNT: 40,
|
|
29
|
+
HOTSPOT_COUNT: 5,
|
|
30
|
+
VORTEX_COLOR_INNER: 'rgba(255, 100, 0, 0.8)',
|
|
31
|
+
VORTEX_COLOR_MID: 'rgba(200, 50, 0, 0.3)',
|
|
32
|
+
VORTEX_COLOR_OUTER: 'rgba(150, 20, 0, 0)',
|
|
33
|
+
},
|
|
34
|
+
WARPED_DISK: {
|
|
35
|
+
WARPED_LINE_COUNT: 10,
|
|
36
|
+
DISK_COLOR_INNER: 'rgba(255, 220, 150, 1)',
|
|
37
|
+
DISK_COLOR_OUTER: 'rgba(255, 150, 0, 0.8)',
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
let blackHoleCounter = 0;
|
|
41
|
+
export class BlackHole extends MassiveBody {
|
|
42
|
+
constructor(x, y, type) {
|
|
43
|
+
const radius = Math.random() * BLACK_HOLE_CONFIG.RADIUS_VARIANCE + BLACK_HOLE_CONFIG.RADIUS_BASE;
|
|
44
|
+
const mass = radius * radius * BLACK_HOLE_CONFIG.MASS_MULTIPLIER;
|
|
45
|
+
super(x, y, radius, mass);
|
|
46
|
+
this.isHovered = false;
|
|
47
|
+
this.vortexAngle = 0;
|
|
48
|
+
this.warpAngle = 0;
|
|
49
|
+
this.accretionDiskAngle = 0;
|
|
50
|
+
this.mergeState = 'IDLE';
|
|
51
|
+
this.mergeStateTimer = 0;
|
|
52
|
+
this.preDecelerationVx = 0;
|
|
53
|
+
this.preDecelerationVy = 0;
|
|
54
|
+
this.attractionTargets = [];
|
|
55
|
+
this.nozzleLength = 0; // Cached nozzle length for stream effect
|
|
56
|
+
this.nozzleColor = null; // Cached nozzle color for stream effect
|
|
57
|
+
this.frameCount = 0; // Frame count for animations
|
|
58
|
+
this.id = ++blackHoleCounter;
|
|
59
|
+
this.name = `BH-${this.id}`;
|
|
60
|
+
this.radius = radius;
|
|
61
|
+
this.baseRadius = radius;
|
|
62
|
+
this.color = '#000000';
|
|
63
|
+
this.hoverTimer = 0;
|
|
64
|
+
this.hoverRadius = this.radius * 5;
|
|
65
|
+
this.eatenStars = 0;
|
|
66
|
+
this.type = type;
|
|
67
|
+
this.vx = Math.random() * BLACK_HOLE_CONFIG.INITIAL_VELOCITY_RANGE * 2 - BLACK_HOLE_CONFIG.INITIAL_VELOCITY_RANGE;
|
|
68
|
+
this.vy = Math.random() * BLACK_HOLE_CONFIG.INITIAL_VELOCITY_RANGE * 2 - BLACK_HOLE_CONFIG.INITIAL_VELOCITY_RANGE;
|
|
69
|
+
this.pulseFrequency = Math.random() * BLACK_HOLE_CONFIG.PULSE_FREQUENCY_VARIANCE + BLACK_HOLE_CONFIG.PULSE_FREQUENCY_MIN;
|
|
70
|
+
this.pulsePhase = Math.random() * Math.PI * 2;
|
|
71
|
+
}
|
|
72
|
+
absorb(body) {
|
|
73
|
+
if (body instanceof Star) {
|
|
74
|
+
this.eatenStars++;
|
|
75
|
+
}
|
|
76
|
+
else if (body instanceof BlackHole) {
|
|
77
|
+
this.mergeState = 'DECELERATING';
|
|
78
|
+
this.mergeStateTimer = BLACK_HOLE_CONFIG.DECELERATION_DURATION;
|
|
79
|
+
this.preDecelerationVx = this.vx;
|
|
80
|
+
this.preDecelerationVy = this.vy;
|
|
81
|
+
}
|
|
82
|
+
this.mass += body.mass;
|
|
83
|
+
this.radius = Math.sqrt(this.mass / BLACK_HOLE_CONFIG.MASS_MULTIPLIER);
|
|
84
|
+
this.boundingRadius = this.radius;
|
|
85
|
+
this.hoverRadius = this.radius * 5;
|
|
86
|
+
}
|
|
87
|
+
reset(x, y, vx, vy) {
|
|
88
|
+
const newRadius = Math.random() * BLACK_HOLE_CONFIG.RADIUS_VARIANCE + BLACK_HOLE_CONFIG.RADIUS_BASE;
|
|
89
|
+
this.mass = newRadius * newRadius * BLACK_HOLE_CONFIG.MASS_MULTIPLIER;
|
|
90
|
+
this.radius = newRadius;
|
|
91
|
+
this.x = x;
|
|
92
|
+
this.y = y;
|
|
93
|
+
this.vx = vx;
|
|
94
|
+
this.vy = vy;
|
|
95
|
+
this.eatenStars = 0;
|
|
96
|
+
this.mergeState = 'IDLE';
|
|
97
|
+
this.mergeStateTimer = 0;
|
|
98
|
+
}
|
|
99
|
+
update(ctx, width, height, frameCount) {
|
|
100
|
+
this.frameCount = frameCount;
|
|
101
|
+
// State machine for post-merger behavior
|
|
102
|
+
if (this.mergeState === 'DECELERATING') {
|
|
103
|
+
const decelerationFactor = Math.max(0, this.mergeStateTimer / BLACK_HOLE_CONFIG.DECELERATION_DURATION);
|
|
104
|
+
this.vx = this.preDecelerationVx * decelerationFactor;
|
|
105
|
+
this.vy = this.preDecelerationVy * decelerationFactor;
|
|
106
|
+
}
|
|
107
|
+
if (this.mergeState !== 'IDLE') {
|
|
108
|
+
this.mergeStateTimer--;
|
|
109
|
+
if (this.mergeStateTimer <= 0) {
|
|
110
|
+
if (this.mergeState === 'DECELERATING') {
|
|
111
|
+
this.vx = 0;
|
|
112
|
+
this.vy = 0;
|
|
113
|
+
this.mergeState = 'PAUSED';
|
|
114
|
+
this.mergeStateTimer = BLACK_HOLE_CONFIG.PAUSE_DURATION;
|
|
115
|
+
}
|
|
116
|
+
else if (this.mergeState === 'PAUSED') {
|
|
117
|
+
this.mergeState = 'IDLE';
|
|
118
|
+
this.vx = Math.random() * BLACK_HOLE_CONFIG.INITIAL_VELOCITY_RANGE * 2 - BLACK_HOLE_CONFIG.INITIAL_VELOCITY_RANGE;
|
|
119
|
+
this.vy = Math.random() * BLACK_HOLE_CONFIG.INITIAL_VELOCITY_RANGE * 2 - BLACK_HOLE_CONFIG.INITIAL_VELOCITY_RANGE;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
this.x += this.vx;
|
|
124
|
+
this.y += this.vy;
|
|
125
|
+
if (this.x < -this.radius)
|
|
126
|
+
this.x = width + this.radius;
|
|
127
|
+
if (this.x > width + this.radius)
|
|
128
|
+
this.x = -this.radius;
|
|
129
|
+
if (this.y < -this.radius)
|
|
130
|
+
this.y = height + this.radius;
|
|
131
|
+
if (this.y > height + this.radius)
|
|
132
|
+
this.y = -this.radius;
|
|
133
|
+
if (this.type === 'VORTEX') {
|
|
134
|
+
this.vortexAngle += 0.01;
|
|
135
|
+
}
|
|
136
|
+
if (this.type === 'WARPED_DISK') {
|
|
137
|
+
this.warpAngle += 0.002;
|
|
138
|
+
}
|
|
139
|
+
if (this.type === 'ACCRETION_DISK') {
|
|
140
|
+
this.accretionDiskAngle += 0.005 / 3;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
drawDebugInfo(ctx) {
|
|
144
|
+
const startX = this.x + this.hoverRadius + 15;
|
|
145
|
+
const boxPadding = 10;
|
|
146
|
+
const lineHeight = 14;
|
|
147
|
+
const infoLines = [
|
|
148
|
+
`Name: ${this.name}`,
|
|
149
|
+
`Type: ${this.constructor.name} (${this.type})`,
|
|
150
|
+
`Radius: ${this.radius.toFixed(2)}`,
|
|
151
|
+
`Mass: ${this.mass.toFixed(2)}`,
|
|
152
|
+
`Position: (${this.x.toFixed(0)}, ${this.y.toFixed(0)})`,
|
|
153
|
+
`Stars Eaten: ${this.eatenStars}`,
|
|
154
|
+
`Merge State: ${this.mergeState} (${this.mergeStateTimer})`
|
|
155
|
+
];
|
|
156
|
+
const boxHeight = infoLines.length * lineHeight + boxPadding * 2;
|
|
157
|
+
const boxWidth = Math.max(...infoLines.map(line => ctx.measureText(line).width)) + boxPadding * 2;
|
|
158
|
+
const boxY = this.y - boxHeight / 2;
|
|
159
|
+
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
|
|
160
|
+
ctx.strokeStyle = '#fff';
|
|
161
|
+
ctx.lineWidth = 1;
|
|
162
|
+
ctx.beginPath();
|
|
163
|
+
ctx.roundRect(startX, boxY, boxWidth, boxHeight, 5);
|
|
164
|
+
ctx.fill();
|
|
165
|
+
ctx.stroke();
|
|
166
|
+
ctx.fillStyle = 'white';
|
|
167
|
+
ctx.font = '10px "Roboto Mono", monospace';
|
|
168
|
+
ctx.textAlign = 'left';
|
|
169
|
+
ctx.textBaseline = 'top';
|
|
170
|
+
infoLines.forEach((line, index) => {
|
|
171
|
+
ctx.fillText(line, startX + boxPadding, boxY + boxPadding + index * lineHeight);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
draw(ctx, pulseTime, frameCount) {
|
|
175
|
+
this.frameCount = frameCount;
|
|
176
|
+
// 1. Draw streams from behind
|
|
177
|
+
if (EFFECTS_CONFIG.RENDER_INTER_HOLE_STREAMS && this.attractionTargets.length > 0) {
|
|
178
|
+
for (const target of this.attractionTargets) {
|
|
179
|
+
drawEnergyStream(ctx, this, target, pulseTime, frameCount);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// 2. Draw the main black hole shape
|
|
183
|
+
switch (this.type) {
|
|
184
|
+
case 'STANDARD':
|
|
185
|
+
drawStandardShape(ctx, this);
|
|
186
|
+
break;
|
|
187
|
+
case 'ACCRETION_DISK':
|
|
188
|
+
drawAccretionDiskShape(ctx, this);
|
|
189
|
+
break;
|
|
190
|
+
case 'VORTEX':
|
|
191
|
+
drawVortexShape(ctx, this);
|
|
192
|
+
break;
|
|
193
|
+
case 'WARPED_DISK':
|
|
194
|
+
drawWarpedDiskShape(ctx, this);
|
|
195
|
+
break;
|
|
196
|
+
case 'LENSING':
|
|
197
|
+
default:
|
|
198
|
+
drawLensingShape(ctx, this);
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
// 3. Draw hover effect if hovered
|
|
202
|
+
this.isHovered = this.hoverTimer > 0;
|
|
203
|
+
if (this.isHovered) {
|
|
204
|
+
if (DEBUG_CONFIG.SHOW_DEBUG_INFO && DEBUG_CONFIG.SHOW_ENTITY_HOVER_INFO) {
|
|
205
|
+
this.drawDebugInfo(ctx);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
export { BlackHole as BlackHle };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Defines the ClanManager for the night sky simulation.
|
|
3
|
+
*/
|
|
4
|
+
import { type Clan } from './clans';
|
|
5
|
+
export declare class ClanManager {
|
|
6
|
+
private clans;
|
|
7
|
+
private lastAssignedClanIndex;
|
|
8
|
+
constructor();
|
|
9
|
+
private initializeClans;
|
|
10
|
+
getClans(): Clan[];
|
|
11
|
+
getClanForNewFleet(): Clan;
|
|
12
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Defines the ClanManager for the night sky simulation.
|
|
3
|
+
*/
|
|
4
|
+
import { CLANS_CONFIG } from './clans';
|
|
5
|
+
export class ClanManager {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.clans = [];
|
|
8
|
+
this.lastAssignedClanIndex = -1;
|
|
9
|
+
this.initializeClans();
|
|
10
|
+
}
|
|
11
|
+
initializeClans() {
|
|
12
|
+
this.clans = CLANS_CONFIG.map(config => (Object.assign(Object.assign({}, config), { fleets: [], starships: [], fleetsCount: 0, starshipsCount: 0 })));
|
|
13
|
+
}
|
|
14
|
+
getClans() {
|
|
15
|
+
return this.clans;
|
|
16
|
+
}
|
|
17
|
+
getClanForNewFleet() {
|
|
18
|
+
// Simple round-robin assignment for now
|
|
19
|
+
this.lastAssignedClanIndex = (this.lastAssignedClanIndex + 1) % this.clans.length;
|
|
20
|
+
return this.clans[this.lastAssignedClanIndex];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Defines all clan properties for the night sky simulation.
|
|
3
|
+
*/
|
|
4
|
+
import type { Fleet } from './fleet';
|
|
5
|
+
import type { Starship } from './starship';
|
|
6
|
+
export interface Clan {
|
|
7
|
+
name: string;
|
|
8
|
+
color: string;
|
|
9
|
+
icon: (ctx: CanvasRenderingContext2D, size: number) => void;
|
|
10
|
+
fleets: Fleet[];
|
|
11
|
+
starships: Starship[];
|
|
12
|
+
fleetsCount: number;
|
|
13
|
+
starshipsCount: number;
|
|
14
|
+
}
|
|
15
|
+
export declare const CLANS_CONFIG: Pick<Clan, 'name' | 'color' | 'icon'>[];
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const drawIconCrescent = (ctx, size) => {
|
|
2
|
+
ctx.beginPath();
|
|
3
|
+
ctx.arc(0, 0, size / 2, 0, Math.PI * 2);
|
|
4
|
+
ctx.fill();
|
|
5
|
+
ctx.save();
|
|
6
|
+
ctx.globalCompositeOperation = 'destination-out';
|
|
7
|
+
ctx.beginPath();
|
|
8
|
+
ctx.arc(size * 0.2, 0, size / 2.5, 0, Math.PI * 2);
|
|
9
|
+
ctx.fill();
|
|
10
|
+
ctx.restore();
|
|
11
|
+
};
|
|
12
|
+
const drawIconSpikes = (ctx, size) => {
|
|
13
|
+
const points = 6;
|
|
14
|
+
ctx.beginPath();
|
|
15
|
+
for (let i = 0; i < points * 2; i++) {
|
|
16
|
+
const radius = i % 2 === 0 ? size / 2 : size / 4;
|
|
17
|
+
const angle = (i / points) * Math.PI;
|
|
18
|
+
ctx.lineTo(radius * Math.cos(angle), radius * Math.sin(angle));
|
|
19
|
+
}
|
|
20
|
+
ctx.closePath();
|
|
21
|
+
ctx.fill();
|
|
22
|
+
};
|
|
23
|
+
const drawIconTriangle = (ctx, size) => {
|
|
24
|
+
const h = size * (Math.sqrt(3) / 2);
|
|
25
|
+
ctx.beginPath();
|
|
26
|
+
ctx.moveTo(0, -h / 2);
|
|
27
|
+
ctx.lineTo(-size / 2, h / 2);
|
|
28
|
+
ctx.lineTo(size / 2, h / 2);
|
|
29
|
+
ctx.closePath();
|
|
30
|
+
ctx.stroke();
|
|
31
|
+
};
|
|
32
|
+
const drawIconHexagon = (ctx, size) => {
|
|
33
|
+
const r = size / 2;
|
|
34
|
+
ctx.beginPath();
|
|
35
|
+
ctx.moveTo(r * Math.cos(0), r * Math.sin(0));
|
|
36
|
+
for (let i = 1; i <= 6; i++) {
|
|
37
|
+
ctx.lineTo(r * Math.cos(i * 2 * Math.PI / 6), r * Math.sin(i * 2 * Math.PI / 6));
|
|
38
|
+
}
|
|
39
|
+
ctx.stroke();
|
|
40
|
+
};
|
|
41
|
+
const drawIconCross = (ctx, size) => {
|
|
42
|
+
const armLength = size / 2;
|
|
43
|
+
ctx.beginPath();
|
|
44
|
+
ctx.moveTo(-armLength, 0);
|
|
45
|
+
ctx.lineTo(armLength, 0);
|
|
46
|
+
ctx.moveTo(0, -armLength);
|
|
47
|
+
ctx.lineTo(0, armLength);
|
|
48
|
+
ctx.stroke();
|
|
49
|
+
};
|
|
50
|
+
export const CLANS_CONFIG = [
|
|
51
|
+
{
|
|
52
|
+
name: "Starkwood Sovereignty",
|
|
53
|
+
color: "#ADD8E6",
|
|
54
|
+
icon: drawIconCrescent
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "Crimson Covenant",
|
|
58
|
+
color: "#FF6B6B",
|
|
59
|
+
icon: drawIconSpikes
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "Golden Imperium",
|
|
63
|
+
color: "#FFD700",
|
|
64
|
+
icon: drawIconTriangle
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "Azure Assembly",
|
|
68
|
+
color: "#87CEEB",
|
|
69
|
+
icon: drawIconHexagon
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "Veridian Syndicate",
|
|
73
|
+
color: "#3D9970",
|
|
74
|
+
icon: drawIconCross
|
|
75
|
+
}
|
|
76
|
+
];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Defines the Comet class for the night sky simulation.
|
|
3
|
+
*/
|
|
4
|
+
import { BoundedBody } from '../base/bounded-body';
|
|
5
|
+
export declare const COMET_CONFIG: {
|
|
6
|
+
COUNT: number;
|
|
7
|
+
DORMANT_LIFE_MIN: number;
|
|
8
|
+
DORMANT_LIFE_VARIANCE: number;
|
|
9
|
+
MIN_RADIUS: number;
|
|
10
|
+
RADIUS_VARIANCE: number;
|
|
11
|
+
SPEED_MIN: number;
|
|
12
|
+
SPEED_VARIANCE: number;
|
|
13
|
+
MAX_LIFE_MIN: number;
|
|
14
|
+
MAX_LIFE_VARIANCE: number;
|
|
15
|
+
};
|
|
16
|
+
export declare class Comet extends BoundedBody {
|
|
17
|
+
radius: number;
|
|
18
|
+
color: string;
|
|
19
|
+
life: number;
|
|
20
|
+
maxLife: number;
|
|
21
|
+
dormant: boolean;
|
|
22
|
+
dormantLife: number;
|
|
23
|
+
constructor(width: number, height: number);
|
|
24
|
+
reset(width: number, height: number): void;
|
|
25
|
+
update(ctx: CanvasRenderingContext2D, width: number, height: number): void;
|
|
26
|
+
draw(ctx: CanvasRenderingContext2D): void;
|
|
27
|
+
}
|