first commit
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Bullet.js
|
||||
* Bullet entity that travels in a straight line and interacts with terrain/tanks.
|
||||
*/
|
||||
|
||||
const {
|
||||
BULLET_SPEED,
|
||||
BULLET_SIZE,
|
||||
DIRECTION,
|
||||
DIR_VECTORS,
|
||||
MAP_OFFSET_X,
|
||||
MAP_OFFSET_Y,
|
||||
MAP_WIDTH,
|
||||
MAP_HEIGHT,
|
||||
} = require('../base/GameGlobal');
|
||||
|
||||
class Bullet {
|
||||
constructor() {
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.direction = DIRECTION.UP;
|
||||
this.speed = BULLET_SPEED;
|
||||
this.size = BULLET_SIZE;
|
||||
this.halfSize = BULLET_SIZE / 2;
|
||||
this.alive = false;
|
||||
this.canBreakSteel = false;
|
||||
|
||||
/** @type {'player'|'enemy'} */
|
||||
this.owner = 'player';
|
||||
/** @type {object|null} Reference to the tank that fired this bullet */
|
||||
this.ownerTank = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize/reset the bullet for reuse from object pool.
|
||||
* @param {object} config
|
||||
* @param {number} config.x
|
||||
* @param {number} config.y
|
||||
* @param {number} config.direction
|
||||
* @param {string} config.owner - 'player' or 'enemy'
|
||||
* @param {boolean} [config.canBreakSteel]
|
||||
* @param {object} [config.ownerTank]
|
||||
*/
|
||||
init(config) {
|
||||
this.x = config.x;
|
||||
this.y = config.y;
|
||||
this.direction = config.direction;
|
||||
this.owner = config.owner || 'player';
|
||||
this.canBreakSteel = config.canBreakSteel || false;
|
||||
this.ownerTank = config.ownerTank || null;
|
||||
this.alive = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update bullet position.
|
||||
* @param {number} dt - Delta time in seconds.
|
||||
*/
|
||||
update(dt) {
|
||||
if (!this.alive) return;
|
||||
|
||||
const vec = DIR_VECTORS[this.direction];
|
||||
const moveAmount = this.speed * dt * 60;
|
||||
|
||||
this.x += vec.dx * moveAmount;
|
||||
this.y += vec.dy * moveAmount;
|
||||
|
||||
// Check map boundaries
|
||||
if (
|
||||
this.x < MAP_OFFSET_X ||
|
||||
this.y < MAP_OFFSET_Y ||
|
||||
this.x > MAP_OFFSET_X + MAP_WIDTH ||
|
||||
this.y > MAP_OFFSET_Y + MAP_HEIGHT
|
||||
) {
|
||||
this.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the bullet.
|
||||
* @param {CanvasRenderingContext2D} ctx
|
||||
*/
|
||||
render(ctx) {
|
||||
if (!this.alive) return;
|
||||
|
||||
ctx.fillStyle = this.owner === 'player' ? '#FFFF00' : '#FF6600';
|
||||
ctx.fillRect(
|
||||
this.x - this.halfSize,
|
||||
this.y - this.halfSize,
|
||||
this.size,
|
||||
this.size
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bounding box.
|
||||
* @returns {{x: number, y: number, w: number, h: number}}
|
||||
*/
|
||||
getBounds() {
|
||||
return {
|
||||
x: this.x - this.halfSize,
|
||||
y: this.y - this.halfSize,
|
||||
w: this.size,
|
||||
h: this.size,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the bullet (mark for recycling).
|
||||
*/
|
||||
destroy() {
|
||||
this.alive = false;
|
||||
// Decrement owner's active bullet count
|
||||
if (this.ownerTank && typeof this.ownerTank.activeBullets === 'number') {
|
||||
this.ownerTank.activeBullets = Math.max(0, this.ownerTank.activeBullets - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Bullet;
|
||||
Reference in New Issue
Block a user