tanks/www/tank.mjs

167 lines
4.5 KiB
JavaScript
Raw Normal View History

2024-11-26 15:35:25 -07:00
const craterPoints = 7
const craterAngle = Math.PI / craterPoints
export class Tank {
constructor(ctx, color, sensors) {
this.ctx = ctx
this.color = color
// Do all the yucky math up front
this.maxlen = 0
this.sensors = []
for (let i in sensors) {
let s = sensors[i]
if (! s) {
this.sensors[i] = [0,0,0,0]
} else {
// r, angle, width, turret
this.sensors[i] = [
s[0], // Center angle
s[1] - s[2]/2, // Left border angle
s[1] + s[2]/2, // Right border angle
s[3]?1:0, // On turret?
]
if (s[0] > this.maxlen) {
this.maxlen = s[0]
}
}
}
this.set_state(0, 0, 0, 0, 0)
}
// Set up our state, for later interleaved draw requests
set_state(x, y, rotation, turret, flags, sensor_state) {
this.x = x
this.y = y
this.rotation = rotation
this.turret = turret
if (flags & 1) {
this.fire = 5
}
this.led = flags & 2
this.dead = flags & 4
this.sensor_state = sensor_state
}
draw_crater() {
if (!this.dead) {
return
}
this.ctx.save()
this.ctx.translate(this.x, this.y)
this.ctx.rotate(this.rotation)
if (this.fire == 5) {
this.ctx.save()
this.ctx.rotate(this.turret)
// one frame of cannon fire
this.draw_cannon()
this.fire = 0
this.ctx.restore()
}
this.ctx.lineWidth = 2
this.ctx.strokeStyle = `rgb(from ${this.color} r g b / 50%)`
this.ctx.fillStyle = `rgb(from ${this.color} r g b / 20%)`
this.ctx.beginPath()
this.ctx.moveTo(12, 0)
for (let i = 0; i < craterPoints; i += 1) {
this.ctx.rotate(craterAngle)
this.ctx.lineTo(6, 0)
this.ctx.rotate(craterAngle)
this.ctx.lineTo(12, 0)
}
this.ctx.closePath()
this.ctx.stroke()
this.ctx.fill()
this.ctx.restore()
}
draw_sensors() {
if (this.dead) {
return
}
this.ctx.save()
this.ctx.translate(this.x, this.y)
this.ctx.rotate(this.rotation)
this.ctx.lineWidth = 1
for (let i in this.sensors) {
var s = this.sensors[i]
var adj = this.turret * s[3]
if (this.sensor_state & (1 << i)) {
// Sensor is triggered
this.ctx.strokeStyle = "#000"
} else {
this.ctx.strokeStyle = `rgb(from ${this.color} r g b / 40%)`
}
this.ctx.beginPath()
this.ctx.moveTo(0, 0)
this.ctx.arc(0, 0, s[0], s[1] + adj, s[2] + adj, false)
this.ctx.closePath()
this.ctx.stroke()
}
this.ctx.restore()
}
draw_tank() {
if (this.dead) {
return
}
this.ctx.save()
this.ctx.translate(this.x, this.y)
this.ctx.rotate(this.rotation)
this.ctx.fillStyle = this.color
this.ctx.fillRect(-5, -4, 10, 8)
this.ctx.fillStyle = "#777"
this.ctx.fillRect(-7, -9, 15, 5)
this.ctx.fillRect(-7, 4, 15, 5)
this.ctx.rotate(this.turret)
if (this.fire) {
this.draw_cannon()
this.fire -= 1
} else {
if (this.led) {
this.ctx.fillStyle = "#f00"
} else {
this.ctx.fillStyle = "#000"
}
this.ctx.fillRect(0, -1, 10, 2)
}
this.ctx.restore()
}
draw_cannon() {
this.ctx.fillStyle = ("hsl(0, 100%, 100%, " + this.fire/5 + ")")
this.ctx.fillRect(0, -1, 45, 2)
}
draw_wrap_sensors() {
let width = this.ctx.canvas.width
let height = this.ctx.canvas.height
let orig_x = this.x
let orig_y = this.y
for (let x = this.x - width; x < width + this.maxlen; x += width) {
for (let y = this.y - height; y < height + this.maxlen; y += height) {
if ((-this.maxlen < x) && (x < width + this.maxlen) &&
(-this.maxlen < y) && (y < height + this.maxlen)) {
this.x = x
this.y = y
this.draw_sensors()
}
}
}
this.x = orig_x
this.y = orig_y
}
}