hippie/source/code/game.js

252 lines
5.9 KiB
JavaScript
Raw Normal View History

class HippieCrosshair {
constructor(canvas, options = {}) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.debug = options.debug || false;
// Crosshair options
this.size = options.size || 16;
this.thickness = options.thickness || 2;
this.color = options.color || '#000';
this.gapSize = options.gapSize || 8;
this.style = options.style || 'cross';
// Line options
this.lineColor = options.lineColor || '#fff';
this.lineWidth = options.lineWidth || 1;
this.showConnector = options.showConnector !== false;
// Symbol options
this.symbolDistance = options.symbolDistance || 128; // Distance to draw next symbol
this.symbolSpacing = options.symbolSpacing || 64; // Space between symbols
this.symbolSize = options.symbolSize || 8;
this.symbolColor = options.symbolColor || '#000';
this.symbolStyle = options.symbolStyle || 'arrow';
this.mouseX = canvas.width / 2;
this.mouseY = canvas.height / 2;
2026-03-22 22:21:26 +01:00
// Animation control
this.isAnimating = true;
this.animationFrameId = null;
this.setupEventListeners();
this.animate();
}
setupEventListeners() {
2026-03-22 22:21:26 +01:00
document.addEventListener('mousemove', (event) => {
this.mouseX = event.clientX;
this.mouseY = event.clientY;
});
}
animate() {
2026-03-22 22:21:26 +01:00
if (!this.isAnimating) {
this.animationFrameId = requestAnimationFrame(() => this.animate());
return;
}
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
if (this.showConnector) {
if (this.debug) this.drawLine();
this.drawConnector();
}
// TODO: Autom. Zug zum Zentrum hin ermöglichen
this.drawCrosshair();
2026-03-22 22:21:26 +01:00
this.animationFrameId = requestAnimationFrame(() => this.animate());
}
drawLine() {
const centerX = this.canvas.width / 2;
const centerY = this.canvas.height / 2;
this.ctx.strokeStyle = this.lineColor;
this.ctx.lineWidth = this.lineWidth;
this.ctx.beginPath();
this.ctx.moveTo(centerX, centerY);
this.ctx.lineTo(this.mouseX, this.mouseY);
this.ctx.stroke();
}
// TODO: Ausblenden nach Distanz
drawConnector() {
const centerX = this.canvas.width / 2;
const centerY = this.canvas.height / 2;
const dx = this.mouseX - centerX;
const dy = this.mouseY - centerY;
const distance = Math.sqrt(dx * dx + dy * dy);
// Only draw symbols if cursor is far enough from center
if (distance < this.symbolDistance) {
return;
}
const angle = Math.atan2(dy, dx);
// Calculate how many symbols to draw
const symbolCount = Math.floor((distance - this.symbolDistance) / this.symbolSpacing);
for (let i = 0; i < symbolCount; i++) {
const symbolDistance = this.symbolDistance + (i * this.symbolSpacing);
const symbolX = centerX + Math.cos(angle) * symbolDistance;
const symbolY = centerY + Math.sin(angle) * symbolDistance;
this.drawSymbol(symbolX, symbolY, angle);
}
}
drawSymbol(x, y, angle = 0) {
this.ctx.fillStyle = this.symbolColor;
this.ctx.strokeStyle = this.symbolColor;
this.ctx.lineWidth = 1;
switch (this.symbolStyle) {
case 'circle':
this.ctx.beginPath();
this.ctx.arc(x, y, this.symbolSize / 2, 0, Math.PI * 2);
this.ctx.fill();
break;
case 'diamond':
const size = this.symbolSize - (this.symbolSize / 4);
this.ctx.beginPath();
this.ctx.moveTo(x, y - size);
this.ctx.lineTo(x + size, y);
this.ctx.lineTo(x, y + size);
this.ctx.lineTo(x - size, y);
this.ctx.closePath();
this.ctx.fill();
break;
case 'square':
this.ctx.fillRect(
x - this.symbolSize / 2,
y - this.symbolSize / 2,
this.symbolSize,
this.symbolSize
);
break;
case 'arrow':
this.arrow(x, y, angle);
break;
}
}
arrow(x, y, angle) {
const size = this.symbolSize - (this.symbolSize / 4);
this.ctx.save();
this.ctx.translate(x, y);
this.ctx.rotate(angle);
// Arrow pointing right
this.ctx.beginPath();
this.ctx.moveTo(size, 0); // Tip
this.ctx.lineTo(-size, -size); // Back left
// this.ctx.lineTo(-size * 0.4, 0); // Middle
this.ctx.lineTo(-size, size); // Back right
this.ctx.closePath();
this.ctx.fill();
this.ctx.restore();
}
drawCrosshair() {
this.ctx.strokeStyle = this.color;
this.ctx.lineWidth = this.thickness;
this.ctx.lineCap = 'round';
switch (this.style) {
case 'cross':
this.cross();
break;
case 'circle':
this.circle();
break;
case 'dot':
this.dot();
break;
}
}
cross() {
// Horizontal line
this.ctx.beginPath();
this.ctx.moveTo(this.mouseX - this.size, this.mouseY);
this.ctx.lineTo(this.mouseX - this.gapSize, this.mouseY);
this.ctx.stroke();
this.ctx.beginPath();
this.ctx.moveTo(this.mouseX + this.gapSize, this.mouseY);
this.ctx.lineTo(this.mouseX + this.size, this.mouseY);
this.ctx.stroke();
// Vertical line
this.ctx.beginPath();
this.ctx.moveTo(this.mouseX, this.mouseY - this.size);
this.ctx.lineTo(this.mouseX, this.mouseY - this.gapSize);
this.ctx.stroke();
this.ctx.beginPath();
this.ctx.moveTo(this.mouseX, this.mouseY + this.gapSize);
this.ctx.lineTo(this.mouseX, this.mouseY + this.size);
this.ctx.stroke();
}
circle() {
// Outer circle
this.ctx.beginPath();
this.ctx.arc(this.mouseX, this.mouseY, this.size, 0, Math.PI * 2);
this.ctx.stroke();
// Inner dot
this.ctx.fillStyle = this.color;
this.ctx.beginPath();
this.ctx.arc(this.mouseX, this.mouseY, this.thickness * 1.5, 0, Math.PI * 2);
this.ctx.fill();
}
dot() {
this.ctx.fillStyle = this.color;
this.ctx.beginPath();
this.ctx.arc(this.mouseX, this.mouseY, this.size / 4, 0, Math.PI * 2);
this.ctx.fill();
}
setCrosshairStyle(style) {
this.style = style;
}
setColor(color) {
this.color = color;
}
setSymbolStyle(style) {
this.symbolStyle = style;
}
setSymbolColor(color) {
this.symbolColor = color;
}
setLineVisible(visible) {
this.showConnector = visible;
}
2026-03-22 22:21:26 +01:00
startAnimation() {
this.isAnimating = true;
}
stopAnimation() {
this.isAnimating = false;
}
toggleAnimation() {
this.isAnimating = !this.isAnimating;
}
}