initial commit, walkable and idling character, first map with collision
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,7 @@ | |||||||
|  | Thumbs.db* | ||||||
|  | 
 | ||||||
|  | *.afpub* | ||||||
|  | *.zip | ||||||
|  | 
 | ||||||
|  | /tiles-paid | ||||||
|  | /modern-tiles_free | ||||||
							
								
								
									
										37
									
								
								DirectionInput.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,37 @@ | |||||||
|  | class DirectionInput { | ||||||
|  | 	constructor() { | ||||||
|  | 		this.heldDirections = []; | ||||||
|  | 
 | ||||||
|  | 		this.map = { | ||||||
|  | 			"ArrowUp": "up", | ||||||
|  | 			"KeyW": "up", | ||||||
|  | 			"ArrowDown": "down", | ||||||
|  | 			"KeyS": "down", | ||||||
|  | 			"ArrowLeft": "left", | ||||||
|  | 			"KeyA": "left", | ||||||
|  | 			"ArrowRight": "right", | ||||||
|  | 			"KeyD": "right", | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	get direction() { | ||||||
|  | 		return this.heldDirections[0]; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	init() { | ||||||
|  | 		document.addEventListener("keydown", e => { | ||||||
|  | 			const dir = this.map[e.code]; | ||||||
|  | 			if (dir && this.heldDirections.indexOf(dir) === -1) { | ||||||
|  | 				this.heldDirections.unshift(dir); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 
 | ||||||
|  | 		document.addEventListener("keyup", e => { | ||||||
|  | 			const dir = this.map[e.code]; | ||||||
|  | 			const index = this.heldDirections.indexOf(dir); | ||||||
|  | 			if (index > -1) { | ||||||
|  | 				this.heldDirections.splice(index, 1); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								GameObject.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,22 @@ | |||||||
|  | class GameObject { | ||||||
|  | 	constructor(config) { | ||||||
|  | 		this.isMounted = false; | ||||||
|  | 		this.x = config.x || 0; | ||||||
|  | 		this.y = config.y || 0; | ||||||
|  | 		this.direction = config.direction || "down"; | ||||||
|  | 		this.sprite = new Sprite({ | ||||||
|  | 			gameObject: this, | ||||||
|  | 			src: config.src || "/images/characters/people/hero.png", | ||||||
|  | 
 | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mount(map) { | ||||||
|  | 		this.isMounted = true; | ||||||
|  | 		map.addWall(this.x, this.y); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	update() { | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										47
									
								
								Overworld.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,47 @@ | |||||||
|  | class Overworld { | ||||||
|  | 	constructor(config) { | ||||||
|  | 		this.element = config.element; | ||||||
|  | 		this.canvas = this.element.querySelector(".game-canvas"); | ||||||
|  | 		this.ctx = this.canvas.getContext("2d"); | ||||||
|  | 		this.map = null; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	startGameLoop() { | ||||||
|  | 		const step = () => { | ||||||
|  | 			this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); | ||||||
|  | 
 | ||||||
|  | 			const cameraPerson = this.map.gameObjects.hero; | ||||||
|  | 
 | ||||||
|  | 			// update all objects
 | ||||||
|  | 			Object.values(this.map.gameObjects).forEach(object => { | ||||||
|  | 				object.update({ | ||||||
|  | 					arrow: this.directionInput.direction, | ||||||
|  | 					map: this.map, | ||||||
|  | 				}); | ||||||
|  | 			}) | ||||||
|  | 
 | ||||||
|  | 			this.map.drawLowerImage(this.ctx, cameraPerson); | ||||||
|  | 
 | ||||||
|  | 			Object.values(this.map.gameObjects).forEach(object => { | ||||||
|  | 				object.sprite.draw(this.ctx, cameraPerson); | ||||||
|  | 			}) | ||||||
|  | 
 | ||||||
|  | 			this.map.drawUpperImage(this.ctx, cameraPerson); | ||||||
|  | 			 | ||||||
|  | 			requestAnimationFrame(() => { | ||||||
|  | 				step(); | ||||||
|  | 			}) | ||||||
|  | 		} | ||||||
|  | 		step(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	init() { | ||||||
|  | 		this.map = new OverworldMap(window.OverworldMaps.DemoRoom); | ||||||
|  | 		this.map.mountObjects(); | ||||||
|  | 
 | ||||||
|  | 		this.directionInput = new DirectionInput(); | ||||||
|  | 		this.directionInput.init(); | ||||||
|  | 
 | ||||||
|  | 		this.startGameLoop(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										123
									
								
								OverworldMap.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,123 @@ | |||||||
|  | class OverworldMap { | ||||||
|  | 	constructor(config) { | ||||||
|  | 		this.gameObjects = config.gameObjects; | ||||||
|  | 		this.walls = config.walls || {}; | ||||||
|  | 
 | ||||||
|  | 		this.lowerImage = new Image(); | ||||||
|  | 		this.lowerImage.src = config.lowerSrc; | ||||||
|  | 
 | ||||||
|  | 		this.upperImage = new Image(); | ||||||
|  | 		this.upperImage.src = config.upperSrc; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	drawLowerImage(ctx, cameraPerson) { | ||||||
|  | 		ctx.drawImage(this.lowerImage, utils.withGrid(10.5) - cameraPerson.x, utils.withGrid(6) - cameraPerson.y); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	drawUpperImage(ctx, cameraPerson) { | ||||||
|  | 		ctx.drawImage(this.upperImage, utils.withGrid(10.5) - cameraPerson.x, utils.withGrid(6) - cameraPerson.y); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	isSpaceTaken(currentX, currentY, direction) { | ||||||
|  | 		const {x, y} = utils.nextPosition(currentX, currentY, direction); | ||||||
|  | 		return this.walls[`${x},${y}`] || false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mountObjects() { | ||||||
|  | 		Object.values(this.gameObjects).forEach(o => { | ||||||
|  | 			// todoL determine if this object should actually mount
 | ||||||
|  | 
 | ||||||
|  | 			o.mount(this); | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	addWall(x, y) { | ||||||
|  | 		this.walls[`${x},${y}`] = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	removeWall(x, y) { | ||||||
|  | 		delete this.walls[`${x},${y}`]; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	moveWall(wasX, wasY, direction) { | ||||||
|  | 		this.removeWall(wasX, wasY); | ||||||
|  | 		const {x, y} = utils.nextPosition(wasX, wasY, direction); | ||||||
|  | 		this.addWall(x, y); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | window.OverworldMaps = { | ||||||
|  | 	DemoRoom: { | ||||||
|  | 		lowerSrc: "/images/maps/map-room-entrance.png", | ||||||
|  | 		upperSrc: "", | ||||||
|  | 		gameObjects: { | ||||||
|  | 			hero: new Person({ | ||||||
|  | 				isPlayerControlled: true, | ||||||
|  | 				x: utils.withGrid(8), | ||||||
|  | 				y: utils.withGrid(2), | ||||||
|  | 			}), | ||||||
|  | 			// npc1: new Person({
 | ||||||
|  | 			// 	x: utils.withGrid(6),
 | ||||||
|  | 			// 	y: utils.withGrid(7),
 | ||||||
|  | 			// })
 | ||||||
|  | 		}, | ||||||
|  | 		walls: { | ||||||
|  | 			// "16,16": true
 | ||||||
|  | 			[utils.asGridCoord(5,2)] : true, | ||||||
|  | 			[utils.asGridCoord(5,3)] : true, | ||||||
|  | 			[utils.asGridCoord(5,4)] : true, | ||||||
|  | 			[utils.asGridCoord(4,4)] : true, | ||||||
|  | 			[utils.asGridCoord(3,4)] : true, | ||||||
|  | 			[utils.asGridCoord(2,4)] : true, | ||||||
|  | 			[utils.asGridCoord(1,5)] : true, | ||||||
|  | 			[utils.asGridCoord(0,6)] : true, | ||||||
|  | 			[utils.asGridCoord(1,7)] : true, | ||||||
|  | 			[utils.asGridCoord(2,8)] : true, | ||||||
|  | 			[utils.asGridCoord(3,8)] : true, | ||||||
|  | 			[utils.asGridCoord(4,8)] : true, | ||||||
|  | 			[utils.asGridCoord(5,8)] : true, | ||||||
|  | 			[utils.asGridCoord(5,9)] : true, | ||||||
|  | 			[utils.asGridCoord(5,10)] : true, | ||||||
|  | 			[utils.asGridCoord(4,11)] : true, | ||||||
|  | 			[utils.asGridCoord(5,12)] : true, | ||||||
|  | 			[utils.asGridCoord(6,12)] : true, | ||||||
|  | 			[utils.asGridCoord(7,12)] : true, | ||||||
|  | 			[utils.asGridCoord(7,13)] : true, | ||||||
|  | 			[utils.asGridCoord(8,14)] : true, | ||||||
|  | 			[utils.asGridCoord(9,13)] : true, | ||||||
|  | 			[utils.asGridCoord(9,12)] : true, | ||||||
|  | 			[utils.asGridCoord(10,12)] : true, | ||||||
|  | 			[utils.asGridCoord(11,12)] : true, | ||||||
|  | 			[utils.asGridCoord(12,11)] : true, | ||||||
|  | 			[utils.asGridCoord(11,10)] : true, | ||||||
|  | 			[utils.asGridCoord(11,9)] : true, | ||||||
|  | 			[utils.asGridCoord(11,8)] : true, | ||||||
|  | 			[utils.asGridCoord(11,7)] : true, | ||||||
|  | 			[utils.asGridCoord(11,6)] : true, | ||||||
|  | 			[utils.asGridCoord(12,5)] : true, | ||||||
|  | 			[utils.asGridCoord(11,4)] : true, | ||||||
|  | 			[utils.asGridCoord(11,3)] : true, | ||||||
|  | 			[utils.asGridCoord(11,2)] : true, | ||||||
|  | 			[utils.asGridCoord(10,1)] : true, | ||||||
|  | 			[utils.asGridCoord(9,1)] : true, | ||||||
|  | 			[utils.asGridCoord(8,1)] : true, | ||||||
|  | 			[utils.asGridCoord(7,1)] : true, | ||||||
|  | 			[utils.asGridCoord(6,1)] : true, | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	Kitchen: { | ||||||
|  | 		lowerSrc: "/images/maps/room-builder.png", | ||||||
|  | 		upperSrc: "/images/maps/room-builder.png", | ||||||
|  | 		gameObjects: { | ||||||
|  | 			hero: new GameObject({ | ||||||
|  | 				x: 2, | ||||||
|  | 				y: 3, | ||||||
|  | 			}), | ||||||
|  | 			npc1: new GameObject({ | ||||||
|  | 				x: 3, | ||||||
|  | 				y: 6, | ||||||
|  | 				src: "/images/characters/people/hero-run.png" | ||||||
|  | 			}) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										62
									
								
								Person.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,62 @@ | |||||||
|  | class Person extends GameObject { | ||||||
|  | 	constructor(config) { | ||||||
|  | 		super(config); | ||||||
|  | 		this.movementProgressRemaining = 0; | ||||||
|  | 
 | ||||||
|  | 		this.isPlayerControlled = config.isPlayerControlled || false; | ||||||
|  | 
 | ||||||
|  | 		this.directionUpdate = { | ||||||
|  | 			"up": ["y", -1], | ||||||
|  | 			"down": ["y", 1], | ||||||
|  | 			"left": ["x", -1], | ||||||
|  | 			"right": ["x", 1], | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	update(state) { | ||||||
|  | 		if (this.movementProgressRemaining > 0) { | ||||||
|  | 			this.updatePosition(); | ||||||
|  | 		} else { | ||||||
|  | 
 | ||||||
|  | 			// more cases for starting to walk come here
 | ||||||
|  | 
 | ||||||
|  | 			// case: keyboard ready and arrow pressed
 | ||||||
|  | 			if (this.isPlayerControlled && state.arrow) { | ||||||
|  | 				this.startBehavior(state, { | ||||||
|  | 					type: "walk", | ||||||
|  | 					direction: state.arrow | ||||||
|  | 				}) | ||||||
|  | 			} | ||||||
|  | 			this.updateSprite(state); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	startBehavior(state, behavior) { | ||||||
|  | 		// set character direction to behavior
 | ||||||
|  | 		this.direction = behavior.direction; | ||||||
|  | 		if (behavior.type === "walk") { | ||||||
|  | 			// stop if space is not free
 | ||||||
|  | 			if (state.map.isSpaceTaken(this.x, this.y, this.direction)) { | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// ready to walk
 | ||||||
|  | 			state.map.moveWall(this.x, this.y, this.direction); | ||||||
|  | 			this.movementProgressRemaining = 16; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	updatePosition() { | ||||||
|  | 		const [property, change] = this.directionUpdate[this.direction]; | ||||||
|  | 		this[property] += change; | ||||||
|  | 		this.movementProgressRemaining -= 1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	updateSprite() { | ||||||
|  | 		if (this.movementProgressRemaining > 0) { | ||||||
|  | 			this.sprite.setAnimation("walk-" + this.direction); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		this.sprite.setAnimation("idle-" + this.direction); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										102
									
								
								Sprite.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,102 @@ | |||||||
|  | class Sprite { | ||||||
|  | 	constructor(config) { | ||||||
|  | 		// Setup image
 | ||||||
|  | 		this.image = new Image(); | ||||||
|  | 		this.image.src = config.src; | ||||||
|  | 		this.image.onload = () => { | ||||||
|  | 			this.isLoaded = true; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Shadow
 | ||||||
|  | 		this.shadow = new Image(); | ||||||
|  | 		this.useShadow = true; | ||||||
|  | 		if (this.useShadow) { | ||||||
|  | 			this.shadow.src = "/images/characters/shadow.png" | ||||||
|  | 		} | ||||||
|  | 		this.shadow.onload = () => { | ||||||
|  | 			this.isShadowLoaded = true; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Configure animation and initial state
 | ||||||
|  | 		this.animation = config.animation || { | ||||||
|  | 			"idle-up": [ | ||||||
|  | 				[6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1] | ||||||
|  | 			], | ||||||
|  | 			"idle-down": [ | ||||||
|  | 				[18, 1], [19, 1], [20, 1], [21, 1], [22, 1], [23, 1] | ||||||
|  | 			], | ||||||
|  | 			"idle-left": [ | ||||||
|  | 				[12, 1], [13, 1], [14, 1], [15, 1], [16, 1], [17, 1] | ||||||
|  | 			], | ||||||
|  | 			"idle-right": [ | ||||||
|  | 				[0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1] | ||||||
|  | 			], | ||||||
|  | 			"walk-up": [ | ||||||
|  | 				[6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2] | ||||||
|  | 			], | ||||||
|  | 			"walk-down": [ | ||||||
|  | 				[18, 2], [19, 2], [20, 2], [21, 2], [22, 2], [23, 2] | ||||||
|  | 			], | ||||||
|  | 			"walk-left": [ | ||||||
|  | 				[12, 2], [13, 2], [14, 2], [15, 2], [16, 2], [17, 2] | ||||||
|  | 			], | ||||||
|  | 			"walk-right": [ | ||||||
|  | 				[0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2] | ||||||
|  | 			], | ||||||
|  | 		} | ||||||
|  | 		this.currentAnimation = "idle-down"; // config.currentAnimation || "idle-down";
 | ||||||
|  | 		this.currentAnimationFrame = 0; | ||||||
|  | 
 | ||||||
|  | 		this.animationFrameLimit = config.animationFrameLimit || 6; | ||||||
|  | 		this.animationFrameProgress = this.animationFrameLimit; | ||||||
|  | 
 | ||||||
|  | 		// Reference game object
 | ||||||
|  | 		this.gameObject = config.gameObject; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	get frame() { | ||||||
|  | 		return this.animation[this.currentAnimation][this.currentAnimationFrame] | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	setAnimation(key) { | ||||||
|  | 		if (this.currentAnimation !== key) { | ||||||
|  | 			this.currentAnimation = key; | ||||||
|  | 			this.currentAnimationFrame = 0; | ||||||
|  | 			this.animationFrameProgress = this.animationFrameLimit; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	updateAnimationProgress() { | ||||||
|  | 		// downtick frame progress
 | ||||||
|  | 		if (this.animationFrameProgress > 0) { | ||||||
|  | 			this.animationFrameProgress -= 1; | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// reset the counter
 | ||||||
|  | 		this.animationFrameProgress = this.animationFrameLimit; | ||||||
|  | 		this.currentAnimationFrame += 1; | ||||||
|  | 
 | ||||||
|  | 		if (this.frame === undefined) { | ||||||
|  | 			this.currentAnimationFrame = 0; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	draw(ctx, cameraPerson) { | ||||||
|  | 		const x = this.gameObject.x + utils.withGrid(10.5) - cameraPerson.x; | ||||||
|  | 		const y = this.gameObject.y - 4  + utils.withGrid(6) - cameraPerson.y; | ||||||
|  | 
 | ||||||
|  | 		this.isShadowLoaded && ctx.drawImage(this.shadow, x, y); | ||||||
|  | 
 | ||||||
|  | 		const [frameX, frameY] = this.frame; | ||||||
|  | 
 | ||||||
|  | 		this.isLoaded && ctx.drawImage(this.image, | ||||||
|  | 			frameX * 16, frameY * 32, | ||||||
|  | 			16, 32, | ||||||
|  | 			x, y, | ||||||
|  | 			16, 32 | ||||||
|  | 		) | ||||||
|  | 
 | ||||||
|  | 		this.updateAnimationProgress(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								images/characters/people/hero-idle.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/characters/people/hero-run.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/characters/people/hero.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 15 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/characters/shadow.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/maps/floor-test.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 113 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/maps/map-room-entrance.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/maps/room-builder.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 11 KiB | 
							
								
								
									
										23
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,23 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  | 	<meta charset="UTF-8"> | ||||||
|  | 	<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
|  | 	<link rel="stylesheet" href="style.css"> | ||||||
|  | 	<title>witchday</title> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  | 	<div class="game-container"> | ||||||
|  | 		<canvas class="game-canvas" width="352" height="198"></canvas> | ||||||
|  | 	</div> | ||||||
|  | 
 | ||||||
|  | 	<script src="/utils.js"></script> | ||||||
|  | 	<script src="/DirectionInput.js"></script> | ||||||
|  | 	<script src="/Overworld.js"></script> | ||||||
|  | 	<script src="/GameObject.js"></script> | ||||||
|  | 	<script src="/Person.js"></script> | ||||||
|  | 	<script src="/Sprite.js"></script> | ||||||
|  | 	<script src="/OverworldMap.js"></script> | ||||||
|  | 	<script src="/init.js"></script> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										8
									
								
								init.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,8 @@ | |||||||
|  | (function () { | ||||||
|  | 	 | ||||||
|  | 	const overworld = new Overworld({ | ||||||
|  | 		element: document.querySelector(".game-container") | ||||||
|  | 	}); | ||||||
|  | 	overworld.init(); | ||||||
|  | 
 | ||||||
|  | })(); | ||||||
							
								
								
									
										
											BIN
										
									
								
								map-room-entrance.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 113 KiB | 
							
								
								
									
										25
									
								
								style.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,25 @@ | |||||||
|  | * { | ||||||
|  | 	box-sizing: border-box; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | body { | ||||||
|  | 	margin: 0; | ||||||
|  | 	padding: 0; | ||||||
|  | 	overflow: hidden; | ||||||
|  | 	background: #333; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .game-container { | ||||||
|  | 	position: relative; | ||||||
|  | 	width: 352px; | ||||||
|  | 	height: 198px; | ||||||
|  | 	margin: 0 auto; | ||||||
|  | 	margin-top: 20px; | ||||||
|  | 	outline: 1px solid #fff; | ||||||
|  | 
 | ||||||
|  | 	transform: scale(2) translateY(30%); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .game-container canvas { | ||||||
|  | 	image-rendering: pixelated; | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,25 @@ | |||||||
|  | const utils = { | ||||||
|  | 	withGrid(n) { | ||||||
|  | 		return n * 16; | ||||||
|  | 	}, | ||||||
|  | 	asGridCoord(x, y) { | ||||||
|  | 		return `${x*16},${y*16}` | ||||||
|  | 	}, | ||||||
|  | 	nextPosition(initialX, initialY, direction) { | ||||||
|  | 		let x = initialX; | ||||||
|  | 		let y = initialY; | ||||||
|  | 		const size = 16; | ||||||
|  | 
 | ||||||
|  | 		if (direction === "left") { | ||||||
|  | 			x -= size; | ||||||
|  | 		} else if (direction === "right") { | ||||||
|  | 			x += size; | ||||||
|  | 		} else if (direction === "up") { | ||||||
|  | 			y -= size; | ||||||
|  | 		} else if (direction === "down") { | ||||||
|  | 			y += size; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return {x, y}; | ||||||
|  | 	} | ||||||
|  | } | ||||||