added behaviors and cutscene logic like here: https://www.youtube.com/watch?v=e144CXGy2mc&list=PLcjhmZ8oLT0r9dSiIK6RB_PuBWlG1KSq_&index=9
This commit is contained in:
parent
6361a6c539
commit
d4a7de346d
@ -1,5 +1,6 @@
|
||||
class GameObject {
|
||||
constructor(config) {
|
||||
this.id = null;
|
||||
this.isMounted = false;
|
||||
this.x = config.x || 0;
|
||||
this.y = config.y || 0;
|
||||
@ -9,14 +10,42 @@ class GameObject {
|
||||
src: config.src || "/images/characters/people/hero.png",
|
||||
|
||||
});
|
||||
|
||||
this.behaviorLoop = config.behaviorLoop || [];
|
||||
this.behaviorLoopIndex = 0;
|
||||
}
|
||||
|
||||
mount(map) {
|
||||
this.isMounted = true;
|
||||
map.addWall(this.x, this.y);
|
||||
|
||||
// when behavior kick off after delay
|
||||
setTimeout(() => {
|
||||
this.doBehaviorEvent(map);
|
||||
}, 10);
|
||||
}
|
||||
|
||||
update() {
|
||||
|
||||
}
|
||||
|
||||
async doBehaviorEvent(map) {
|
||||
// stop if cutscene is playing
|
||||
if (map.isCutscenePlaying || this.behaviorLoop.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let eventConfig = this.behaviorLoop[this.behaviorLoopIndex];
|
||||
eventConfig.who = this.id;
|
||||
|
||||
const eventHandler = new OverworldEvent({ map, event: eventConfig });
|
||||
await eventHandler.init();
|
||||
|
||||
this.behaviorLoopIndex += 1;
|
||||
if (this.behaviorLoopIndex === this.behaviorLoop.length) {
|
||||
this.behaviorLoopIndex = 0;
|
||||
}
|
||||
|
||||
this.doBehaviorEvent(map);
|
||||
}
|
||||
}
|
11
Overworld.js
11
Overworld.js
@ -22,7 +22,9 @@ class Overworld {
|
||||
|
||||
this.map.drawLowerImage(this.ctx, cameraPerson);
|
||||
|
||||
Object.values(this.map.gameObjects).forEach(object => {
|
||||
Object.values(this.map.gameObjects).sort((a,b) => {
|
||||
return a.y - b.y;
|
||||
}).forEach(object => {
|
||||
object.sprite.draw(this.ctx, cameraPerson);
|
||||
})
|
||||
|
||||
@ -43,5 +45,12 @@ class Overworld {
|
||||
this.directionInput.init();
|
||||
|
||||
this.startGameLoop();
|
||||
|
||||
this.map.startCutscene([
|
||||
{ who: "hero", type: "walk", direction: "down" },
|
||||
{ who: "hero", type: "walk", direction: "down" },
|
||||
{ who: "hero", type: "walk", direction: "down" },
|
||||
{ who: "npc1", type: "walk", direction: "right" },
|
||||
])
|
||||
}
|
||||
}
|
54
OverworldEvent.js
Normal file
54
OverworldEvent.js
Normal file
@ -0,0 +1,54 @@
|
||||
class OverworldEvent {
|
||||
constructor({map, event}) {
|
||||
this.map = map;
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
stand(resolve) {
|
||||
const who = this.map.gameObjects[ this.event.who ];
|
||||
who.startBehavior({
|
||||
map: this.map
|
||||
}, {
|
||||
type: "stand",
|
||||
direction: this.event.direction,
|
||||
time: this.event.time
|
||||
})
|
||||
|
||||
// handler to complete when correct person is done walking
|
||||
const completeHandler = e => {
|
||||
if (e.detail.whoId === this.event.who) {
|
||||
document.removeEventListener("PersonStandComplete", completeHandler);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("PersonStandComplete", completeHandler)
|
||||
}
|
||||
|
||||
walk(resolve) {
|
||||
const who = this.map.gameObjects[ this.event.who ];
|
||||
who.startBehavior({
|
||||
map: this.map
|
||||
}, {
|
||||
type: "walk",
|
||||
direction: this.event.direction,
|
||||
retry: true
|
||||
})
|
||||
|
||||
// handler to complete when correct person is done walking
|
||||
const completeHandler = e => {
|
||||
if (e.detail.whoId === this.event.who) {
|
||||
document.removeEventListener("PersonWalkingComplete", completeHandler);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("PersonWalkingComplete", completeHandler)
|
||||
}
|
||||
|
||||
init() {
|
||||
return new Promise(resolve => {
|
||||
this[this.event.type](resolve)
|
||||
})
|
||||
}
|
||||
}
|
@ -8,6 +8,8 @@ class OverworldMap {
|
||||
|
||||
this.upperImage = new Image();
|
||||
this.upperImage.src = config.upperSrc;
|
||||
|
||||
this.isCutscenePlaying = false;
|
||||
}
|
||||
|
||||
drawLowerImage(ctx, cameraPerson) {
|
||||
@ -24,13 +26,29 @@ class OverworldMap {
|
||||
}
|
||||
|
||||
mountObjects() {
|
||||
Object.values(this.gameObjects).forEach(o => {
|
||||
// todoL determine if this object should actually mount
|
||||
Object.keys(this.gameObjects).forEach(key => {
|
||||
let object = this.gameObjects[key];
|
||||
object.id = key;
|
||||
|
||||
o.mount(this);
|
||||
|
||||
object.mount(this);
|
||||
})
|
||||
}
|
||||
|
||||
async startCutscene(events) {
|
||||
this.isCutscenePlaying = true;
|
||||
|
||||
for (let i = 0; i < events.length; i++) {
|
||||
const eventHandler = new OverworldEvent({
|
||||
event: events[i],
|
||||
map: this,
|
||||
})
|
||||
await eventHandler.init();
|
||||
}
|
||||
|
||||
this.isCutscenePlaying = false;
|
||||
}
|
||||
|
||||
addWall(x, y) {
|
||||
this.walls[`${x},${y}`] = true;
|
||||
}
|
||||
@ -56,10 +74,27 @@ window.OverworldMaps = {
|
||||
x: utils.withGrid(8),
|
||||
y: utils.withGrid(2),
|
||||
}),
|
||||
// npc1: new Person({
|
||||
// x: utils.withGrid(6),
|
||||
// y: utils.withGrid(7),
|
||||
// })
|
||||
npc1: new Person({
|
||||
x: utils.withGrid(6),
|
||||
y: utils.withGrid(5),
|
||||
behaviorLoop: [
|
||||
{ type: "stand", direction: "down", time: 800 },
|
||||
{ type: "stand", direction: "right", time: 300 },
|
||||
{ type: "stand", direction: "down", time: 400 },
|
||||
{ type: "stand", direction: "up", time: 700 },
|
||||
]
|
||||
}),
|
||||
npc2: new Person({
|
||||
x: utils.withGrid(8),
|
||||
y: utils.withGrid(9),
|
||||
behaviorLoop: [
|
||||
{ type: "walk", direction: "left" },
|
||||
{ type: "stand", direction: "up", time: 800 },
|
||||
{ type: "walk", direction: "up" },
|
||||
{ type: "walk", direction: "right" },
|
||||
{ type: "walk", direction: "down" },
|
||||
]
|
||||
})
|
||||
},
|
||||
walls: {
|
||||
// "16,16": true
|
||||
|
20
Person.js
20
Person.js
@ -21,7 +21,7 @@ class Person extends GameObject {
|
||||
// more cases for starting to walk come here
|
||||
|
||||
// case: keyboard ready and arrow pressed
|
||||
if (this.isPlayerControlled && state.arrow) {
|
||||
if (state.map.isCutscenePlaying == false && this.isPlayerControlled && state.arrow) {
|
||||
this.startBehavior(state, {
|
||||
type: "walk",
|
||||
direction: state.arrow
|
||||
@ -37,12 +37,24 @@ class Person extends GameObject {
|
||||
if (behavior.type === "walk") {
|
||||
// stop if space is not free
|
||||
if (state.map.isSpaceTaken(this.x, this.y, this.direction)) {
|
||||
behavior.retry && setTimeout(() => {
|
||||
this.startBehavior(state, behavior);
|
||||
}, 10);
|
||||
return;
|
||||
}
|
||||
|
||||
// ready to walk
|
||||
state.map.moveWall(this.x, this.y, this.direction);
|
||||
this.movementProgressRemaining = 16;
|
||||
this.updateSprite(state);
|
||||
}
|
||||
|
||||
if (behavior.type = "stand") {
|
||||
setTimeout(() => {
|
||||
utils.emitEvent("PersonStandComplete", {
|
||||
whoId: this.id
|
||||
})
|
||||
}, behavior.time);
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,6 +62,12 @@ class Person extends GameObject {
|
||||
const [property, change] = this.directionUpdate[this.direction];
|
||||
this[property] += change;
|
||||
this.movementProgressRemaining -= 1;
|
||||
|
||||
if (this.movementProgressRemaining === 0) {
|
||||
utils.emitEvent("PersonWalkingComplete", {
|
||||
whoId: this.id
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
updateSprite() {
|
||||
|
@ -18,6 +18,7 @@
|
||||
<script src="/Person.js"></script>
|
||||
<script src="/Sprite.js"></script>
|
||||
<script src="/OverworldMap.js"></script>
|
||||
<script src="/OverworldEvent.js"></script>
|
||||
<script src="/init.js"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user