1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
import * as Controls from 'controls'
import * as Vec2 from 'model/vec2'
import * as Number from 'util/number'
import * as Screen from 'screen'
import * as Colors from 'view/colors'
export const radius: number = 30
export const fireDelay: number = 200
export const missileWidth: number = 10
export const missileHeight: number = 5
export interface State {
pos: Vec2.Vec2,
missiles: Array<Vec2.Vec2>,
lastFired: number,
}
export function init(): State {
return {
pos: {
x: Screen.width / 6,
y: Screen.height / 2,
},
missiles: [],
lastFired: 0,
}
}
export function update(state: State, timestamp: number, delta: number) {
move(state, delta)
updateMissiles(state, timestamp, delta)
}
function move(state: State, delta: number) {
let dir = controlsDir(Controls.current)
if (!Vec2.equals(dir, Vec2.zero())) {
let teta = Math.atan2(dir.y, dir.x)
state.pos.x += Math.cos(teta) * delta / 3
state.pos.y += Math.sin(teta) * delta / 3
}
state.pos.x = Number.clamp(state.pos.x, radius, Screen.width - radius)
state.pos.y = Number.clamp(state.pos.y, radius, Screen.height - radius)
}
function controlsDir(c: Controls.Controls): Vec2.Vec2 {
let dir = Vec2.zero()
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 dir
}
function updateMissiles(state: State, timestamp: number, delta: number) {
if (Controls.current.space && state.lastFired + fireDelay < timestamp) {
state.missiles.push({x: state.pos.x + radius, y: state.pos.y})
state.lastFired = timestamp
}
state.missiles = state.missiles
.map(missile => ({ ...missile, x: missile.x + delta}))
.filter(missile => missile.x < Screen.width)
}
export function view(context: CanvasRenderingContext2D, state: State) {
context.fillStyle = Colors.colors.red
context.beginPath()
context.moveTo(state.pos.x - radius, state.pos.y - radius)
context.lineTo(state.pos.x + radius, state.pos.y)
context.lineTo(state.pos.x - radius, state.pos.y + 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()
})
}
|