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 {
|
class GameObject {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
|
this.id = null;
|
||||||
this.isMounted = false;
|
this.isMounted = false;
|
||||||
this.x = config.x || 0;
|
this.x = config.x || 0;
|
||||||
this.y = config.y || 0;
|
this.y = config.y || 0;
|
||||||
@ -9,14 +10,42 @@ class GameObject {
|
|||||||
src: config.src || "/images/characters/people/hero.png",
|
src: config.src || "/images/characters/people/hero.png",
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.behaviorLoop = config.behaviorLoop || [];
|
||||||
|
this.behaviorLoopIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mount(map) {
|
mount(map) {
|
||||||
this.isMounted = true;
|
this.isMounted = true;
|
||||||
map.addWall(this.x, this.y);
|
map.addWall(this.x, this.y);
|
||||||
|
|
||||||
|
// when behavior kick off after delay
|
||||||
|
setTimeout(() => {
|
||||||
|
this.doBehaviorEvent(map);
|
||||||
|
}, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
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);
|
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);
|
object.sprite.draw(this.ctx, cameraPerson);
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -43,5 +45,12 @@ class Overworld {
|
|||||||
this.directionInput.init();
|
this.directionInput.init();
|
||||||
|
|
||||||
this.startGameLoop();
|
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 = new Image();
|
||||||
this.upperImage.src = config.upperSrc;
|
this.upperImage.src = config.upperSrc;
|
||||||
|
|
||||||
|
this.isCutscenePlaying = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
drawLowerImage(ctx, cameraPerson) {
|
drawLowerImage(ctx, cameraPerson) {
|
||||||
@ -24,13 +26,29 @@ class OverworldMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mountObjects() {
|
mountObjects() {
|
||||||
Object.values(this.gameObjects).forEach(o => {
|
Object.keys(this.gameObjects).forEach(key => {
|
||||||
// todoL determine if this object should actually mount
|
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) {
|
addWall(x, y) {
|
||||||
this.walls[`${x},${y}`] = true;
|
this.walls[`${x},${y}`] = true;
|
||||||
}
|
}
|
||||||
@ -56,10 +74,27 @@ window.OverworldMaps = {
|
|||||||
x: utils.withGrid(8),
|
x: utils.withGrid(8),
|
||||||
y: utils.withGrid(2),
|
y: utils.withGrid(2),
|
||||||
}),
|
}),
|
||||||
// npc1: new Person({
|
npc1: new Person({
|
||||||
// x: utils.withGrid(6),
|
x: utils.withGrid(6),
|
||||||
// y: utils.withGrid(7),
|
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: {
|
walls: {
|
||||||
// "16,16": true
|
// "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
|
// more cases for starting to walk come here
|
||||||
|
|
||||||
// case: keyboard ready and arrow pressed
|
// case: keyboard ready and arrow pressed
|
||||||
if (this.isPlayerControlled && state.arrow) {
|
if (state.map.isCutscenePlaying == false && this.isPlayerControlled && state.arrow) {
|
||||||
this.startBehavior(state, {
|
this.startBehavior(state, {
|
||||||
type: "walk",
|
type: "walk",
|
||||||
direction: state.arrow
|
direction: state.arrow
|
||||||
@ -37,12 +37,24 @@ class Person extends GameObject {
|
|||||||
if (behavior.type === "walk") {
|
if (behavior.type === "walk") {
|
||||||
// stop if space is not free
|
// stop if space is not free
|
||||||
if (state.map.isSpaceTaken(this.x, this.y, this.direction)) {
|
if (state.map.isSpaceTaken(this.x, this.y, this.direction)) {
|
||||||
|
behavior.retry && setTimeout(() => {
|
||||||
|
this.startBehavior(state, behavior);
|
||||||
|
}, 10);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ready to walk
|
// ready to walk
|
||||||
state.map.moveWall(this.x, this.y, this.direction);
|
state.map.moveWall(this.x, this.y, this.direction);
|
||||||
this.movementProgressRemaining = 16;
|
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];
|
const [property, change] = this.directionUpdate[this.direction];
|
||||||
this[property] += change;
|
this[property] += change;
|
||||||
this.movementProgressRemaining -= 1;
|
this.movementProgressRemaining -= 1;
|
||||||
|
|
||||||
|
if (this.movementProgressRemaining === 0) {
|
||||||
|
utils.emitEvent("PersonWalkingComplete", {
|
||||||
|
whoId: this.id
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSprite() {
|
updateSprite() {
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
<script src="/Person.js"></script>
|
<script src="/Person.js"></script>
|
||||||
<script src="/Sprite.js"></script>
|
<script src="/Sprite.js"></script>
|
||||||
<script src="/OverworldMap.js"></script>
|
<script src="/OverworldMap.js"></script>
|
||||||
|
<script src="/OverworldEvent.js"></script>
|
||||||
<script src="/init.js"></script>
|
<script src="/init.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue
Block a user