import * as Controls from 'controls' import * as Vec2 from 'model/vec2' import * as Size from 'model/size' import * as Number from 'util/number' import * as Colors from 'view/colors' import * as Physics from 'util/physics' export const missileWidth: number = 10 export const missileHeight: number = 5 export interface State { speed: Vec2.Vec2, pos: Vec2.Vec2, radius: number, missiles: Array, lastFired: number, } export function init(windowSize: Size.Size): State { return { speed: { x: 0, y: 0 }, pos: { x: windowSize.width / 6, y: windowSize.height / 2, }, radius: Size.diagonal(windowSize) / 30, missiles: [], lastFired: 0, } } export function update( state: State, dt: number, windowSize: Size.Size ) { move(state, dt, windowSize) updateMissiles(state, dt, windowSize) } function move(state: State, dt: number, windowSize: Size.Size) { const dir = controlsDir(Controls.current) const unitDt = 0.5 const steps = Math.round(dt / unitDt) const acc = Physics.acc({ dt, speed: state.speed, dir }) Array(steps).fill(1).forEach(_ => { state.speed = Physics.speed({ dt: unitDt, acc, speed: state.speed }) state.pos = Physics.pos({ dt: unitDt, acc, speed: state.speed, pos: state.pos }) }) state.pos = Vec2.clamp( state.pos, { x: state.radius, y: state.radius }, { x: windowSize.width - state.radius, y: windowSize.height - state.radius } ) } function controlsDir(c: Controls.Controls): Vec2.Vec2 { let dir = { x: 0, y: 0 } if (c.up && !c.down) dir.y = -1 else if (c.down && !c.up) dir.y = 1 if (c.right && !c.left) dir.x = 1 else if (c.left && !c.right) dir.x = -1 return Vec2.normalize(dir) } function updateMissiles(state: State, dt: number, windowSize: Size.Size) { if (Controls.current.spaceCount > state.lastFired) { state.missiles.push({x: state.pos.x + state.radius, y: state.pos.y}) state.lastFired = Controls.current.spaceCount } state.missiles = state.missiles .map(missile => ({ ...missile, x: missile.x + dt})) .filter(missile => missile.x < windowSize.width) } export function project(state: State, from: Size.Size, to: Size.Size) { state.pos = Vec2.project(from, to, state.pos) state.radius = state.radius / Size.diagonal(from) * Size.diagonal(to) } export function view(context: CanvasRenderingContext2D, state: State) { context.fillStyle = Colors.colors.red context.beginPath() context.moveTo(state.pos.x - state.radius, state.pos.y - state.radius) context.lineTo(state.pos.x + state.radius, state.pos.y) context.lineTo(state.pos.x - state.radius, state.pos.y + state.radius) context.closePath() context.fill() state.missiles.forEach(({x, y}) => { context.fillStyle = Colors.colors.red context.beginPath() context.rect( x - missileWidth / 2, y - missileHeight / 2, missileWidth, missileHeight ) context.fill() }) }