-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathactor.js
162 lines (139 loc) · 5.08 KB
/
actor.js
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
class Actor extends Sprite {
constructor(width, height, colour, texture, xzstep, face, hat, pack, outline) {
super(width, height, colour, texture, xzstep);
this.face = face;
this.hat = hat;
this.pack = pack;
this.outline = outline;
this.canvas = this.buildCanvas();
this.elem.classList.add('actor');
}
/**
* Builds the background image canvas for the Actor.
*/
buildCanvas() {
// Create a single canvas to render the sprite sheet for the four directions.
let ctx = $.Util.create2dContext(this.width * 4, this.width * 3 * 3);
// For each direction, render the Actor facing in that direction.
for (let c = 0; c < 3; c++) {
for (let d = 0; d < 4; d++) {
ctx.drawImage(
$.Util.renderPerson(this.width, this.width * 3, d, c, this.face, this.colour, this.hat, this.pack, this.outline),
d * this.width,
c * this.width * 3);
}
}
this.elem.style.backgroundImage = 'url(' + ctx.canvas.toDataURL("image/png") + ')';
return ctx.canvas;
}
/**
* Tells the Actor to stop moving. If fully is not provided, and there are pending destination
* points, then the Actor will start moving to the next point. If fully is set to true then
* all pending destination points are cleared.
*/
stop(fully) {
// Clear the current destination.
this.destX = this.destZ = -1;
this.heading = null;
this.cell = 0;
if (this.destFn) {
this.destFn();
this.destFn = null;
}
// To fully stop, we need to also clear the pending destinations.
if (fully) this.dests = [];
}
/**
* Tells the Actor to move to the given position on the screen.
*/
moveTo(x, z, fn) {
this.dests.push({z: z, x: x, fn: fn});
}
/**
* Tells the Actor to say the given text within a speech bubble of the given width. Will
* execute the given optional next function if provided after the speech bubble is removed.
*/
say(text, width, next) {
$.Game.userInput = false;
let bubble = document.createElement('span');
bubble.className = 'bubble';
bubble.innerHTML = text;
let left;
if (this.x > 800) {
left = -width + 40;
} else if (this.x < 100) {
left = -10;
} else {
left = -(width / 2);
}
bubble.style.width = width + 'px';
bubble.style.left = left + 'px';
let elem = this.elem;
elem.appendChild(bubble);
elem.classList.add('speech');
setTimeout(function() {
elem.classList.remove('speech');
elem.removeChild(bubble);
setTimeout(function() {
if (next) {
next();
} else {
// Re-enable user input if nothing is happening after the speech.
$.Game.userInput = true;
}
}, 500);
}, (text.length / 10) * 1500);
}
/**
* Updates the Actor's position based on its current heading and destination point.
*/
update() {
// Only update the Actor if it is currently on screen.
if (this.elem.style.display != 'none') {
// Mask out left/right/in/out but retain the current jumping directions.
let direction;
if ((this.destX != -1) && (this.destZ != -1)) {
if (this.touching({cx: this.destX, cy: this.cy, z: this.destZ, radius: -this.radius}, 20)) {
// We've reached the destination.
this.stop();
} else {
this.heading = Math.atan2(this.destZ - this.z, this.destX - this.cx);
// Cycle cell
this.cell = ((this.cell + 1) % 30);
}
} else if (this.dests.length > 0) {
// If there is a destination position waiting for ego to move to, pop it now.
let pos = this.dests.shift();
this.destZ = pos.z
this.destX = pos.x;
this.destFn = pos.fn;
}
if (this.heading !== null) {
// Convert the heading to a direction value.
if (Math.abs(this.heading) > 2.356) {
direction |= Sprite.LEFT;
} else if (Math.abs(this.heading) < 0.785) {
direction |= Sprite.RIGHT;
} else if (this.heading > 0) {
direction |= Sprite.OUT;
} else {
direction |= Sprite.IN;
}
}
// Update Ego's direction to what was calculated above.
this.setDirection(direction);
// Move Ego based on it's heading.
if (this.heading !== null) this.move();
}
}
/**
* Invoked when Ego has hit another Sprite.
*
* @param obj The Sprite that Ego has hit.
*/
hit(obj) {
// Reset the position to the last one that isn't touching another Sprite. Resetting
// the position prevents Ego from walking through obstacles.
for (;this.reset() && this.touching(obj););
}
}