added cutscene behaviors
added changing maps all done like this https://www.youtube.com/watch?v=U7fYOnedjzs&list=PLcjhmZ8oLT0r9dSiIK6RB_PuBWlG1KSq_&index=9
This commit is contained in:
		
							parent
							
								
									b42eb143f0
								
							
						
					
					
						commit
						90ff4fe2ff
					
				| @ -13,6 +13,8 @@ class GameObject { | |||||||
| 
 | 
 | ||||||
| 		this.behaviorLoop = config.behaviorLoop || []; | 		this.behaviorLoop = config.behaviorLoop || []; | ||||||
| 		this.behaviorLoopIndex = 0; | 		this.behaviorLoopIndex = 0; | ||||||
|  | 
 | ||||||
|  | 		this.talking = config.talking || []; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	mount(map) { | 	mount(map) { | ||||||
|  | |||||||
							
								
								
									
										26
									
								
								KeyPressListener.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								KeyPressListener.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | class KeyPressListener { | ||||||
|  | 	constructor(keyCode, callback) { | ||||||
|  | 		let keySafe = true; | ||||||
|  | 		this.keydownFunction = function(event) { | ||||||
|  | 			if (event.code === keyCode) { | ||||||
|  | 				if (keySafe) { | ||||||
|  | 					keySafe = false; | ||||||
|  | 					callback(); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}; | ||||||
|  | 		this.keyupFunction = function(event) { | ||||||
|  | 			if (event.code === keyCode) { | ||||||
|  | 				keySafe = true; | ||||||
|  | 			} | ||||||
|  | 		}; | ||||||
|  | 
 | ||||||
|  | 		document.addEventListener("keydown", this.keydownFunction); | ||||||
|  | 		document.addEventListener("keyup", this.keyupFunction); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	unbind() { | ||||||
|  | 		document.removeEventListener("keydown", this.keydownFunction); | ||||||
|  | 		document.removeEventListener("keyup", this.keyupFunction); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								Overworld.js
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								Overworld.js
									
									
									
									
									
								
							| @ -37,9 +37,33 @@ class Overworld { | |||||||
| 		step(); | 		step(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	init() { | 	bindActionInput() { | ||||||
| 		this.map = new OverworldMap(window.OverworldMaps.DemoRoom); | 		new KeyPressListener("Enter", () => { | ||||||
|  | 			// check if there is a person to talk to
 | ||||||
|  | 			this.map.checkForActionCutscene(); | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bindHeroPositionCheck() { | ||||||
|  | 		document.addEventListener("PersonWalkingComplete", e => { | ||||||
|  | 			if (e.detail.whoId === "hero") { | ||||||
|  | 				// heros position changed
 | ||||||
|  | 				this.map.checkForFootstepCutscene() | ||||||
|  | 			} | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	startMap(mapConfig) { | ||||||
|  | 		this.map = new OverworldMap(mapConfig); | ||||||
|  | 		this.map.overworld = this; | ||||||
| 		this.map.mountObjects(); | 		this.map.mountObjects(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	init() { | ||||||
|  | 		this.startMap(window.OverworldMaps.DemoRoom); | ||||||
|  | 
 | ||||||
|  | 		this.bindActionInput(); | ||||||
|  | 		this.bindHeroPositionCheck(); | ||||||
| 
 | 
 | ||||||
| 		this.directionInput = new DirectionInput(); | 		this.directionInput = new DirectionInput(); | ||||||
| 		this.directionInput.init(); | 		this.directionInput.init(); | ||||||
| @ -51,6 +75,8 @@ class Overworld { | |||||||
| 			{ who: "hero", type: "walk", direction: "down" }, | 			{ who: "hero", type: "walk", direction: "down" }, | ||||||
| 			{ who: "hero", type: "walk", direction: "down" }, | 			{ who: "hero", type: "walk", direction: "down" }, | ||||||
| 			{ who: "npc1", type: "walk", direction: "right" }, | 			{ who: "npc1", type: "walk", direction: "right" }, | ||||||
|  | 			{ who: "hero", type: "stand", direction: "left", time: 200 }, | ||||||
|  | 			{ type: "textMessage", text: "Hi!" }, | ||||||
| 		]) | 		]) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -46,6 +46,24 @@ class OverworldEvent { | |||||||
| 		document.addEventListener("PersonWalkingComplete", completeHandler) | 		document.addEventListener("PersonWalkingComplete", completeHandler) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	textMessage(resolve) { | ||||||
|  | 		if (this.event.faceHero) { | ||||||
|  | 			const obj = this.map.gameObjects[this.event.faceHero]; | ||||||
|  | 			obj.direction = utils.oppositeDirection(this.map.gameObjects["hero"].direction); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		const message = new TextMessage({ | ||||||
|  | 			text: this.event.text, | ||||||
|  | 			onComplete: () => resolve() | ||||||
|  | 		}) | ||||||
|  | 		message.init( document.querySelector(".game-container") ) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	changeMap(resolve) { | ||||||
|  | 		this.map.overworld.startMap(window.OverworldMaps[this.event.map]); | ||||||
|  | 		resolve(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	init() { | 	init() { | ||||||
| 		return new Promise(resolve => { | 		return new Promise(resolve => { | ||||||
| 			this[this.event.type](resolve) | 			this[this.event.type](resolve) | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| class OverworldMap { | class OverworldMap { | ||||||
| 	constructor(config) { | 	constructor(config) { | ||||||
|  | 		this.overworld = null; | ||||||
| 		this.gameObjects = config.gameObjects; | 		this.gameObjects = config.gameObjects; | ||||||
|  | 		this.cutsceneSpaces = config.cutsceneSpaces || {}; | ||||||
| 		this.walls = config.walls || {}; | 		this.walls = config.walls || {}; | ||||||
| 
 | 
 | ||||||
| 		this.lowerImage = new Image(); | 		this.lowerImage = new Image(); | ||||||
| @ -52,6 +54,25 @@ class OverworldMap { | |||||||
| 		Object.values(this.gameObjects).forEach(object => object.doBehaviorEvent(this)) | 		Object.values(this.gameObjects).forEach(object => object.doBehaviorEvent(this)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	checkForActionCutscene() { | ||||||
|  | 		const hero = this.gameObjects["hero"]; | ||||||
|  | 		const nextCoords = utils.nextPosition(hero.x, hero.y, hero.direction); | ||||||
|  | 		const match = Object.values(this.gameObjects).find(object => { | ||||||
|  | 			return `${object.x},${object.y}` === `${nextCoords.x},${nextCoords.y}` | ||||||
|  | 		}); | ||||||
|  | 		if (!this.isCutscenePlaying && match && match.talking.length) { | ||||||
|  | 			this.startCutscene(match.talking[0].events); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	checkForFootstepCutscene() { | ||||||
|  | 		const hero = this.gameObjects["hero"]; | ||||||
|  | 		const match = this.cutsceneSpaces[ `${hero.x},${hero.y}`]; | ||||||
|  | 		if (!this.isCutscenePlaying && match) { | ||||||
|  | 			this.startCutscene(match[0].events); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	addWall(x, y) { | 	addWall(x, y) { | ||||||
| 		this.walls[`${x},${y}`] = true; | 		this.walls[`${x},${y}`] = true; | ||||||
| 	} | 	} | ||||||
| @ -85,17 +106,31 @@ window.OverworldMaps = { | |||||||
| 					{ type: "stand", direction: "right", time: 300 }, | 					{ type: "stand", direction: "right", time: 300 }, | ||||||
| 					{ type: "stand", direction: "down", time: 400 }, | 					{ type: "stand", direction: "down", time: 400 }, | ||||||
| 					{ type: "stand", direction: "up", time: 700 }, | 					{ type: "stand", direction: "up", time: 700 }, | ||||||
|  | 				], | ||||||
|  | 				talking: [ | ||||||
|  | 					{ | ||||||
|  | 						events: [ | ||||||
|  | 							{ type: "textMessage", text: "Schau dich ruhig um.", faceHero: "npc1" }, | ||||||
|  | 							{ type: "textMessage", text: "Vielleicht findest du etwas interessantes ..." }, | ||||||
|  | 						] | ||||||
|  | 					} | ||||||
| 				] | 				] | ||||||
| 			}), | 			}), | ||||||
| 			npc2: new Person({ | 			npc2: new Person({ | ||||||
| 				x: utils.withGrid(8), | 				x: utils.withGrid(2), | ||||||
| 				y: utils.withGrid(9), | 				y: utils.withGrid(5), | ||||||
| 				behaviorLoop: [ | 				behaviorLoop: [ | ||||||
| 					{ type: "walk", direction: "left" }, | 					{ type: "stand", direction: "right", time: 300 }, | ||||||
| 					{ type: "stand", direction: "up", time: 800 }, | 					// { type: "stand", direction: "down", time: 300 },
 | ||||||
| 					{ type: "walk", direction: "up" }, | 				], | ||||||
| 					{ type: "walk", direction: "right" }, | 				talking: [ | ||||||
| 					{ type: "walk", direction: "down" }, | 					{ | ||||||
|  | 						events: [ | ||||||
|  | 							{ type: "textMessage", text: "Dieser Raum darf nicht betreten werden.", faceHero: "npc2" }, | ||||||
|  | 							{ type: "textMessage", text: "Geh weg!" }, | ||||||
|  | 							{ who: "hero", type: "walk", direction: "right" }, | ||||||
|  | 						] | ||||||
|  | 					} | ||||||
| 				] | 				] | ||||||
| 			}) | 			}) | ||||||
| 		}, | 		}, | ||||||
| @ -141,20 +176,51 @@ window.OverworldMaps = { | |||||||
| 			[utils.asGridCoord(8,1)] : true, | 			[utils.asGridCoord(8,1)] : true, | ||||||
| 			[utils.asGridCoord(7,1)] : true, | 			[utils.asGridCoord(7,1)] : true, | ||||||
| 			[utils.asGridCoord(6,1)] : true, | 			[utils.asGridCoord(6,1)] : true, | ||||||
|  | 		}, | ||||||
|  | 		cutsceneSpaces: { | ||||||
|  | 			[utils.asGridCoord(1,6)]: [ | ||||||
|  | 				{ | ||||||
|  | 					events: [ | ||||||
|  | 						{ who: "npc2", type: "walk", direction: "down" }, | ||||||
|  | 						{ who: "npc2", type: "stand", direction: "left" }, | ||||||
|  | 						{ who: "hero", type: "stand", direction: "right", time: 300 }, | ||||||
|  | 						{ type: "textMessage", text: "Du kannst hier nicht rein!" }, | ||||||
|  | 						{ who: "npc2", type: "walk", direction: "up" }, | ||||||
|  | 						{ who: "npc2", type: "stand", direction: "right" }, | ||||||
|  | 						{ who: "hero", type: "walk", direction: "right" }, | ||||||
|  | 						{ who: "hero", type: "walk", direction: "right" }, | ||||||
|  | 					] | ||||||
|  | 				} | ||||||
|  | 			], | ||||||
|  | 			[utils.asGridCoord(11,5)]: [ | ||||||
|  | 				{ | ||||||
|  | 					events: [ | ||||||
|  | 						{ type: "changeMap", map: "Kitchen" } | ||||||
|  | 					] | ||||||
|  | 				} | ||||||
|  | 			], | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
| 	Kitchen: { | 	Kitchen: { | ||||||
| 		lowerSrc: "/images/maps/room-builder.png", | 		lowerSrc: "/images/maps/room-builder.png", | ||||||
| 		upperSrc: "/images/maps/room-builder.png", | 		upperSrc: "/images/maps/room-builder.png", | ||||||
| 		gameObjects: { | 		gameObjects: { | ||||||
| 			hero: new GameObject({ | 			hero: new Person({ | ||||||
| 				x: 2, | 				isPlayerControlled: true, | ||||||
| 				y: 3, | 				x: utils.withGrid(2), | ||||||
|  | 				y: utils.withGrid(3), | ||||||
| 			}), | 			}), | ||||||
| 			npc1: new GameObject({ | 			npc1: new Person({ | ||||||
| 				x: 3, | 				x: utils.withGrid(3), | ||||||
| 				y: 6, | 				y: utils.withGrid(6), | ||||||
| 				src: "/images/characters/people/hero-run.png" | 				// src: "/images/characters/people/hero-run.png",
 | ||||||
|  | 				talking: [ | ||||||
|  | 					{ | ||||||
|  | 						events: [ | ||||||
|  | 							{ type: "textMessage", text: "You made it!", faceHero: "npc1" }, | ||||||
|  | 						] | ||||||
|  | 					} | ||||||
|  | 				] | ||||||
| 			}) | 			}) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
							
								
								
									
										36
									
								
								TextMessage.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								TextMessage.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | |||||||
|  | class TextMessage { | ||||||
|  | 	constructor({ text, onComplete }) { | ||||||
|  | 		this.text = text; | ||||||
|  | 		this.onComplete = onComplete; | ||||||
|  | 		this.element = null; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	createElement() { | ||||||
|  | 		this.element = document.createElement("div"); | ||||||
|  | 		this.element.classList.add("TextMessage"); | ||||||
|  | 
 | ||||||
|  | 		this.element.innerHTML = (` | ||||||
|  | 			<p class="TextMessage_p">${this.text}</p> | ||||||
|  | 			<button class="TextMessage_button">Next</button> | ||||||
|  | 		`);
 | ||||||
|  | 
 | ||||||
|  | 		this.element.querySelector("button").addEventListener("click", () => { | ||||||
|  | 			this.done(); | ||||||
|  | 		}); | ||||||
|  | 
 | ||||||
|  | 		this.actionListener = new KeyPressListener("Enter", () => { | ||||||
|  | 			this.actionListener.unbind(); | ||||||
|  | 			this.done(); | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	done() { | ||||||
|  | 		this.element.remove(); | ||||||
|  | 		this.onComplete(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	init(container) { | ||||||
|  | 		this.createElement(); | ||||||
|  | 		container.appendChild(this.element); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -3,7 +3,8 @@ | |||||||
| <head> | <head> | ||||||
| 	<meta charset="UTF-8"> | 	<meta charset="UTF-8"> | ||||||
| 	<meta name="viewport" content="width=device-width, initial-scale=1.0"> | 	<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
| 	<link rel="stylesheet" href="style.css"> | 	<link rel="stylesheet" href="styles/global.css"> | ||||||
|  | 	<link rel="stylesheet" href="styles/TextMessage.css"> | ||||||
| 	<title>witchday</title> | 	<title>witchday</title> | ||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
| @ -19,6 +20,8 @@ | |||||||
| 	<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="/OverworldEvent.js"></script> | ||||||
|  | 	<script src="/TextMessage.js"></script> | ||||||
|  | 	<script src="/KeyPressListener.js"></script> | ||||||
| 	<script src="/init.js"></script> | 	<script src="/init.js"></script> | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
							
								
								
									
										32
									
								
								styles/TextMessage.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								styles/TextMessage.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | .TextMessage { | ||||||
|  | 	position: absolute; | ||||||
|  | 	left: 0; | ||||||
|  | 	right: 0; | ||||||
|  | 	bottom: 0; | ||||||
|  | 	height: 36px; | ||||||
|  | 	font-size: 12px; | ||||||
|  | 	padding: 4px; | ||||||
|  | 	background: var(--menu-background); | ||||||
|  | 	border-top: 1px solid var(--menu-border-color); | ||||||
|  | 	color: var(--menu-font-color); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .TextMessage_p { | ||||||
|  | 	margin: 0; | ||||||
|  | 	font-size: 12px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .TextMessage_button { | ||||||
|  | 	margin: 0; | ||||||
|  | 	font-size: 12px; | ||||||
|  | 	padding: 0; | ||||||
|  | 	-webkit-appearance: none; | ||||||
|  | 	background: none; | ||||||
|  | 	border: 0; | ||||||
|  | 	font-family: inherit; | ||||||
|  | 	cursor: pointer; | ||||||
|  | 
 | ||||||
|  | 	position: absolute; | ||||||
|  | 	right: 2px; | ||||||
|  | 	bottom: 0; | ||||||
|  | } | ||||||
| @ -1,3 +1,13 @@ | |||||||
|  | :root { | ||||||
|  | 	--border-color: #000; | ||||||
|  | 	--dialog-background: #fff; | ||||||
|  | 
 | ||||||
|  | 	--menu-background: #fff; | ||||||
|  | 	--menu-border-color: #aaa; | ||||||
|  | 	--menu-font-color: #000; | ||||||
|  | 	--menu-selected-background: #ddd; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| * { | * { | ||||||
| 	box-sizing: border-box; | 	box-sizing: border-box; | ||||||
| } | } | ||||||
							
								
								
									
										7
									
								
								utils.js
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								utils.js
									
									
									
									
									
								
							| @ -22,6 +22,13 @@ const utils = { | |||||||
| 
 | 
 | ||||||
| 		return {x, y}; | 		return {x, y}; | ||||||
| 	}, | 	}, | ||||||
|  | 	oppositeDirection(direction) { | ||||||
|  | 		if (direction === "left") { return "right" } | ||||||
|  | 		if (direction === "right") { return "left" } | ||||||
|  | 		if (direction === "up") { return "down" } | ||||||
|  | 		return "up"; | ||||||
|  | 	}, | ||||||
|  | 
 | ||||||
| 	emitEvent(name, detail) { | 	emitEvent(name, detail) { | ||||||
| 		const event = new CustomEvent(name, { | 		const event = new CustomEvent(name, { | ||||||
| 			detail | 			detail | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user