first commit
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* FireButton.js
|
||||
* Virtual fire button component positioned at the bottom-right of the screen.
|
||||
* Overlaid as a separate layer above the map when they intersect.
|
||||
*/
|
||||
|
||||
const {
|
||||
SCREEN_WIDTH,
|
||||
SCREEN_HEIGHT,
|
||||
} = require('../base/GameGlobal');
|
||||
|
||||
class FireButton {
|
||||
constructor() {
|
||||
this.radius = 35;
|
||||
// Anchored to screen bottom-right, shifted slightly towards upper-left
|
||||
const padding = this.radius + 40;
|
||||
this.cx = SCREEN_WIDTH - padding - 15; // right edge + extra leftward offset
|
||||
this.cy = SCREEN_HEIGHT - padding - 30; // bottom edge + extra upward offset
|
||||
|
||||
this._pressed = false;
|
||||
this._touchId = null;
|
||||
this._fireCallback = null;
|
||||
|
||||
// Visual feedback
|
||||
this._pressScale = 1;
|
||||
|
||||
// Touch area
|
||||
this._touchAreaRadius = this.radius * 1.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the callback for when fire is triggered.
|
||||
* @param {Function} cb
|
||||
*/
|
||||
onFire(cb) {
|
||||
this._fireCallback = cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle touch events.
|
||||
* @param {string} eventType
|
||||
* @param {Touch} touch
|
||||
* @returns {boolean} Whether this button consumed the touch.
|
||||
*/
|
||||
handleTouch(eventType, touch) {
|
||||
const tx = touch.clientX;
|
||||
const ty = touch.clientY;
|
||||
|
||||
if (eventType === 'touchstart') {
|
||||
const dist = Math.sqrt((tx - this.cx) ** 2 + (ty - this.cy) ** 2);
|
||||
if (dist <= this._touchAreaRadius) {
|
||||
this._pressed = true;
|
||||
this._touchId = touch.identifier;
|
||||
this._pressScale = 0.85;
|
||||
|
||||
// Fire immediately on press
|
||||
if (this._fireCallback) {
|
||||
this._fireCallback();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (eventType === 'touchend') {
|
||||
if (this._pressed && touch.identifier === this._touchId) {
|
||||
this._pressed = false;
|
||||
this._touchId = null;
|
||||
this._pressScale = 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the fire button.
|
||||
* @param {CanvasRenderingContext2D} ctx
|
||||
*/
|
||||
render(ctx) {
|
||||
ctx.save();
|
||||
ctx.globalAlpha = 0.5;
|
||||
|
||||
const r = this.radius * this._pressScale;
|
||||
|
||||
// Outer ring
|
||||
ctx.strokeStyle = '#FF4444';
|
||||
ctx.lineWidth = 3;
|
||||
ctx.beginPath();
|
||||
ctx.arc(this.cx, this.cy, r, 0, Math.PI * 2);
|
||||
ctx.stroke();
|
||||
|
||||
// Inner fill
|
||||
ctx.fillStyle = this._pressed ? '#FF6666' : '#CC3333';
|
||||
ctx.beginPath();
|
||||
ctx.arc(this.cx, this.cy, r * 0.75, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
// Fire icon (crosshair)
|
||||
ctx.globalAlpha = 0.8;
|
||||
ctx.strokeStyle = '#FFFFFF';
|
||||
ctx.lineWidth = 2;
|
||||
const crossSize = r * 0.35;
|
||||
|
||||
// Horizontal line
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(this.cx - crossSize, this.cy);
|
||||
ctx.lineTo(this.cx + crossSize, this.cy);
|
||||
ctx.stroke();
|
||||
|
||||
// Vertical line
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(this.cx, this.cy - crossSize);
|
||||
ctx.lineTo(this.cx, this.cy + crossSize);
|
||||
ctx.stroke();
|
||||
|
||||
// Center dot
|
||||
ctx.fillStyle = '#FFFFFF';
|
||||
ctx.beginPath();
|
||||
ctx.arc(this.cx, this.cy, 3, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
/** Whether the button is currently pressed. */
|
||||
get pressed() {
|
||||
return this._pressed;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FireButton;
|
||||
Reference in New Issue
Block a user