Basic map editor!
This commit is contained in:
		
							
								
								
									
										1
									
								
								carts/tmp/maptest.fx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								carts/tmp/maptest.fx
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -9,6 +9,7 @@ import { inRect } from "./util.ts"; | |||||||
| import { sheetsIcon, trashIcon } from "./icons.ts"; | import { sheetsIcon, trashIcon } from "./icons.ts"; | ||||||
| import { SheetType, setSheet } from "./sheet.ts"; | import { SheetType, setSheet } from "./sheet.ts"; | ||||||
| import { nonetab } from "./nonetab.ts"; | import { nonetab } from "./nonetab.ts"; | ||||||
|  | import { maptab } from "./maptab.ts"; | ||||||
|  |  | ||||||
| type TabName = SheetType; // "code" | "sprite" | "map" | "sfx" | "music" | "sheet"; | type TabName = SheetType; // "code" | "sprite" | "map" | "sfx" | "music" | "sheet"; | ||||||
|  |  | ||||||
| @@ -61,6 +62,8 @@ const update = () => { | |||||||
| 		codetab.update(); | 		codetab.update(); | ||||||
| 	} else if (page.tab === "spritesheet") { | 	} else if (page.tab === "spritesheet") { | ||||||
| 		spritetab.update(); | 		spritetab.update(); | ||||||
|  | 	} else if (page.tab === "map") { | ||||||
|  | 		maptab.update(); | ||||||
| 	} else if (page.tab === "sheet") { | 	} else if (page.tab === "sheet") { | ||||||
| 		viewsheets.update(); | 		viewsheets.update(); | ||||||
| 	} else if (page.tab === "none") { | 	} else if (page.tab === "none") { | ||||||
| @@ -74,6 +77,8 @@ const draw = () => { | |||||||
| 		codetab.draw(); | 		codetab.draw(); | ||||||
| 	} else if (page.tab === "spritesheet") { | 	} else if (page.tab === "spritesheet") { | ||||||
| 		spritetab.draw(); | 		spritetab.draw(); | ||||||
|  | 	} else if (page.tab === "map") { | ||||||
|  | 		maptab.draw(); | ||||||
| 	} else if (page.tab === "sheet") { | 	} else if (page.tab === "sheet") { | ||||||
| 		viewsheets.draw(); | 		viewsheets.draw(); | ||||||
| 	} else if (page.tab === "none") { | 	} else if (page.tab === "none") { | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								icons.ts
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								icons.ts
									
									
									
									
									
								
							| @@ -20,6 +20,17 @@ export const spriteIcon = [ | |||||||
| 	0, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
| ]; | ]; | ||||||
|  |  | ||||||
|  | export const mapIcon = [ | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 	0, 1, 1, 1, 1, 1, 1, 0, | ||||||
|  | 	0, 1, 0, 1, 0, 0, 1, 0, | ||||||
|  | 	0, 1, 0, 1, 1, 1, 1, 0, | ||||||
|  | 	0, 1, 1, 1, 0, 0, 1, 0, | ||||||
|  | 	0, 1, 0, 1, 0, 0, 1, 0, | ||||||
|  | 	0, 1, 1, 1, 1, 1, 1, 0, | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | ]; | ||||||
|  |  | ||||||
| export const sheetsIcon = [ | export const sheetsIcon = [ | ||||||
| 	0, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 	0, 1, 1, 0, 0, 1, 1, 0, | 	0, 1, 1, 0, 0, 1, 1, 0, | ||||||
|   | |||||||
							
								
								
									
										162
									
								
								maptab.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								maptab.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | |||||||
|  | import { clearScreen, fillRect } from "./window.ts"; | ||||||
|  | import { drawSprite, drawText } from "./builtins.ts"; | ||||||
|  | import { COLOR } from "./colors.ts"; | ||||||
|  | import { getMapSheet, getSheet, getSpriteSheet, setSheet } from "./sheet.ts"; | ||||||
|  | import { mouseHeld, mousePos } from "./mouse.ts"; | ||||||
|  | import { inRect, reGrid } from "./util.ts"; | ||||||
|  | import { page } from "./viewsheets.ts"; | ||||||
|  | import { useSpritesheet } from "./builtins.ts"; | ||||||
|  |  | ||||||
|  | const state = { | ||||||
|  | 	selectedSpriteSheet: 2, | ||||||
|  | 	selectedSprite: 0, | ||||||
|  | 	selectedPatch: 0, | ||||||
|  | 	get map() { | ||||||
|  | 		return getMapSheet(page.activeSheet); | ||||||
|  | 	}, | ||||||
|  | 	set map(val) { | ||||||
|  | 		setSheet(page.activeSheet, "map", val); | ||||||
|  | 	}, | ||||||
|  | 	setInPatch(i: number, sprsheet: number, sprite: number) { | ||||||
|  | 		const xx = this.selectedPatch%overviewW; | ||||||
|  | 		const yy = Math.floor(this.selectedPatch/overviewW); | ||||||
|  | 		const cell = (yy+patchH*Math.floor(i/patchW))*overviewW*patchW+xx*patchW+i%patchW; | ||||||
|  | 		console.log({i, cell, xx, yy}); | ||||||
|  | 		this.map[cell] = [sprsheet, sprite]; | ||||||
|  | 	}, | ||||||
|  | 	get patch() { | ||||||
|  | 		const xx = this.selectedPatch%overviewW; | ||||||
|  | 		const yy = Math.floor(this.selectedPatch/overviewW); | ||||||
|  | 		return Array(overviewH).fill(0).flatMap((_, i) => { | ||||||
|  | 			const start = (yy+patchH*i)*overviewW*patchW+xx*patchW; | ||||||
|  | 			return this.map.slice(start, start+patchW); | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const overviewX = 88; | ||||||
|  | const overviewY = 12; | ||||||
|  | const miniPatchW = 4; | ||||||
|  | const miniPatchH = 4; | ||||||
|  | const overviewW = 8; | ||||||
|  | const overviewH = 8; | ||||||
|  |  | ||||||
|  | const patchX = 8; | ||||||
|  | const patchY = 12; | ||||||
|  | const patchW = 8; | ||||||
|  | const patchH = 8; | ||||||
|  |  | ||||||
|  | const spriteW = 8; | ||||||
|  | const spriteH = 8; | ||||||
|  |  | ||||||
|  | const spriteSheetX = 0; | ||||||
|  | const spriteSheetY = 88; | ||||||
|  | const spriteSheetW = 16; | ||||||
|  | const spriteSheetH = 4; | ||||||
|  |  | ||||||
|  | const spriteSheetPickerX = 0; | ||||||
|  | const spriteSheetPickerY = 79; | ||||||
|  | const spriteSheetPickerW = 16; | ||||||
|  | const spriteSheetPickerH = 1; | ||||||
|  | const spriteSheetPickerTabW = 8; | ||||||
|  | const spriteSheetPickerTabH = 8; | ||||||
|  |  | ||||||
|  | const update = () => { | ||||||
|  | 	if (mouseHeld()) { | ||||||
|  | 		const {x: mouseX, y: mouseY} = mousePos(); | ||||||
|  | 		const inOverview = inRect(mouseX, mouseY, overviewX, overviewY, overviewW*miniPatchW, overviewH*miniPatchH); | ||||||
|  | 		const inPatch = inRect(mouseX, mouseY, patchX, patchY, patchW*spriteW, patchH*spriteH); | ||||||
|  | 		const inSpriteSheetPicker = inRect(mouseX, mouseY, spriteSheetPickerX, spriteSheetPickerY, spriteSheetPickerW*spriteSheetPickerTabW, spriteSheetPickerH*spriteSheetPickerTabH); | ||||||
|  | 		const inSpriteSheet = inRect(mouseX, mouseY, spriteSheetX, spriteSheetY, spriteSheetW*spriteW, spriteSheetH*spriteH); | ||||||
|  | 		if (inOverview) { | ||||||
|  | 			const {x, y} = reGrid(mouseX, mouseY, overviewX, overviewY, miniPatchW, miniPatchH); | ||||||
|  | 			state.selectedPatch = overviewW*y+x; | ||||||
|  | 		} | ||||||
|  | 		if (inPatch) { | ||||||
|  | 			const {x, y} = reGrid(mouseX, mouseY, patchX, patchY, spriteW, spriteH); | ||||||
|  | 			const cellNumber = spriteW*y+x; | ||||||
|  | 			state.setInPatch(cellNumber, state.selectedSpriteSheet, state.selectedSprite); | ||||||
|  | 		} | ||||||
|  | 		if (inSpriteSheetPicker) { | ||||||
|  | 			const {x, y} = reGrid(mouseX, mouseY, spriteSheetPickerX, spriteSheetPickerY, spriteSheetPickerTabW, spriteSheetPickerTabH); | ||||||
|  | 			state.selectedSpriteSheet = spriteSheetPickerW*y+x; | ||||||
|  | 		} | ||||||
|  | 		if (inSpriteSheet) { | ||||||
|  | 			const {x, y} = reGrid(mouseX, mouseY, spriteSheetX, spriteSheetY, spriteW, spriteH); | ||||||
|  | 			state.selectedSprite = spriteSheetW*y+x; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const outlineRect = (x: number, y: number, w: number, h: number, color: number) => { | ||||||
|  | 	fillRect(x, y, w, 1, color); | ||||||
|  | 	fillRect(x, y, 1, h, color); | ||||||
|  | 	fillRect(x+w-1, y, 1, h, color); | ||||||
|  | 	fillRect(x, y+h-1, w, 1, color); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const draw = () => { | ||||||
|  | 	const { | ||||||
|  | 		selectedSpriteSheet, | ||||||
|  | 		selectedSprite, | ||||||
|  | 		selectedPatch | ||||||
|  | 	} = state; | ||||||
|  | 	clearScreen(); | ||||||
|  | 	fillRect(0, 8, 128, 112, COLOR.DARKGRAY); | ||||||
|  |  | ||||||
|  | 	// Draw the overview | ||||||
|  | 	fillRect(overviewX-1, overviewY-1, (overviewW*miniPatchW)+2, (overviewH*miniPatchH)+2, COLOR.BLACK); | ||||||
|  | 	Array(overviewW*overviewH).fill(0).forEach((_, i) => { | ||||||
|  | 		const miniPatchX = overviewX+miniPatchW*(i%overviewW); | ||||||
|  | 		const miniPatchY = overviewY+miniPatchH*Math.floor(i/overviewW); | ||||||
|  | 		if (i === selectedPatch) { | ||||||
|  | 			outlineRect(miniPatchX, miniPatchY, miniPatchW, miniPatchH, COLOR.WHITE); | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	// Draw the current patch | ||||||
|  | 	fillRect(patchX-1, patchY-1, (patchW*spriteW)+2, (patchH*spriteH)+2, COLOR.BLACK); | ||||||
|  | 	state.patch.forEach(([sprsheet, sprite], i) => { | ||||||
|  | 		const spriteX = patchX+spriteW*(i%patchW); | ||||||
|  | 		const spriteY = patchY+spriteH*Math.floor(i/patchW); | ||||||
|  | 		if (getSheet(sprsheet).sheet_type === "spritesheet") { | ||||||
|  | 			useSpritesheet(sprsheet); | ||||||
|  | 			drawSprite(spriteX, spriteY, sprite); | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	// Draw the spritesheet picker | ||||||
|  | 	fillRect(spriteSheetPickerX, spriteSheetPickerY, spriteSheetPickerTabW*spriteSheetPickerW, spriteSheetPickerTabW, COLOR.BLACK); | ||||||
|  | 	Array(spriteSheetPickerW*spriteSheetPickerH).fill(0).forEach((_, i) => { | ||||||
|  | 		const tabX = spriteSheetPickerX+spriteSheetPickerTabW*(i%spriteSheetPickerW); | ||||||
|  | 		const tabY = spriteSheetPickerY+spriteSheetPickerTabH*Math.floor(i/spriteSheetPickerW); | ||||||
|  | 		let color = COLOR.DARKGREEN; | ||||||
|  | 		if (getSheet(i).sheet_type !== "spritesheet") { | ||||||
|  | 			color = COLOR.BROWN; | ||||||
|  | 		} | ||||||
|  | 		if (i === selectedSpriteSheet) { | ||||||
|  | 			color = color === COLOR.BROWN ? COLOR.TAN : COLOR.GREEN; | ||||||
|  | 		} | ||||||
|  | 		fillRect(tabX, tabY, spriteSheetPickerTabW, spriteSheetPickerTabH, color); | ||||||
|  | 		drawText(tabX+2, tabY+1, ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"][i]); | ||||||
|  | 	}); | ||||||
|  | 	 | ||||||
|  | 	// Draw the spritesheet | ||||||
|  | 	fillRect(spriteSheetX, spriteSheetY-1, (spriteSheetW*spriteW), (spriteSheetH*spriteH)+1, COLOR.BLACK); | ||||||
|  | 	if (getSheet(selectedSpriteSheet).sheet_type === "spritesheet") { | ||||||
|  | 		useSpritesheet(selectedSpriteSheet); | ||||||
|  | 		getSpriteSheet(selectedSpriteSheet).forEach((_sprite, i) => { | ||||||
|  | 			const sprX = spriteSheetX+spriteW*(i%spriteSheetW); | ||||||
|  | 			const sprY = spriteSheetY+spriteH*Math.floor(i/spriteSheetW); | ||||||
|  | 			drawSprite(sprX, sprY, i); | ||||||
|  | 			if (i === selectedSprite) { | ||||||
|  | 				outlineRect(sprX, sprY, spriteW, spriteH, COLOR.WHITE); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const maptab = { | ||||||
|  | 	update, | ||||||
|  | 	draw, | ||||||
|  | } | ||||||
| @@ -6,7 +6,7 @@ import { mouseClick, mousePos } from "./mouse.ts"; | |||||||
| import { reGridWithGap } from "./util.ts"; | import { reGridWithGap } from "./util.ts"; | ||||||
| import { page } from "./viewsheets.ts"; | import { page } from "./viewsheets.ts"; | ||||||
| import { useSpritesheet } from "./builtins.ts"; | import { useSpritesheet } from "./builtins.ts"; | ||||||
| import { codeIcon, spriteIcon } from "./icons.ts"; | import { codeIcon, mapIcon, spriteIcon } from "./icons.ts"; | ||||||
|  |  | ||||||
| const gridX = 8; | const gridX = 8; | ||||||
| const gridY = 40; | const gridY = 40; | ||||||
| @@ -15,10 +15,11 @@ const cellH = 8; | |||||||
| const gapX = 8; | const gapX = 8; | ||||||
| const gapY = 8; | const gapY = 8; | ||||||
|  |  | ||||||
| const sheetTypes = ["code", "spritesheet"] as const; | const sheetTypes = ["code", "spritesheet", "map"] as const; | ||||||
| const defaultSheetVal = { | const defaultSheetVal = { | ||||||
| 	code: () => "", | 	code: () => "", | ||||||
| 	spritesheet: () => Array(64).fill(0).map(() => Array(64).fill(0)), | 	spritesheet: () => Array(64).fill(0).map(() => Array(64).fill(0)), | ||||||
|  | 	map: () => Array(64*64).fill(0).map(() => [0, 0]), | ||||||
| 	none: () =>null, | 	none: () =>null, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -49,6 +50,7 @@ const draw = () => { | |||||||
| 		const icon = { | 		const icon = { | ||||||
| 			code: codeIcon, | 			code: codeIcon, | ||||||
| 			spritesheet: spriteIcon, | 			spritesheet: spriteIcon, | ||||||
|  | 			map: mapIcon, | ||||||
| 			none: null, | 			none: null, | ||||||
| 		}[sheetType]; | 		}[sheetType]; | ||||||
| 		drawIcon(sx, sy, icon, COLOR.BLUE); | 		drawIcon(sx, sy, icon, COLOR.BLUE); | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								sheet.ts
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								sheet.ts
									
									
									
									
									
								
							| @@ -8,6 +8,9 @@ export type Sheet = { | |||||||
| } | { | } | { | ||||||
| 	sheet_type: "spritesheet", | 	sheet_type: "spritesheet", | ||||||
| 	value: Array<Array<number>>, | 	value: Array<Array<number>>, | ||||||
|  | } | { | ||||||
|  | 	sheet_type: "map", | ||||||
|  | 	value: Array<[number, number]>, | ||||||
| } | { | } | { | ||||||
| 	sheet_type: "none", | 	sheet_type: "none", | ||||||
| 	value: null, | 	value: null, | ||||||
| @@ -34,7 +37,15 @@ export const getCodeSheet = (sheet: number) => { | |||||||
| export const getSpriteSheet = (sheet: number) => { | export const getSpriteSheet = (sheet: number) => { | ||||||
| 	const {sheet_type, value} = getSheet(sheet); | 	const {sheet_type, value} = getSheet(sheet); | ||||||
| 	if (sheet_type !== "spritesheet") { | 	if (sheet_type !== "spritesheet") { | ||||||
| 		throw "Trying to use a non-sprite sheet as a spritesheet." | 		throw Error("Trying to use a non-sprite sheet as a spritesheet."); | ||||||
|  | 	} | ||||||
|  | 	return value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const getMapSheet = (sheet: number) => { | ||||||
|  | 	const {sheet_type, value} = getSheet(sheet); | ||||||
|  | 	if (sheet_type !== "map") { | ||||||
|  | 		throw "Trying to use a non-map sheet as a map." | ||||||
| 	} | 	} | ||||||
| 	return value; | 	return value; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import { getSheet } from "./sheet.ts"; | |||||||
| import { mouseClick, mousePos } from "./mouse.ts"; | import { mouseClick, mousePos } from "./mouse.ts"; | ||||||
| import { getCart } from "./cart.ts"; | import { getCart } from "./cart.ts"; | ||||||
| import { font } from "./font.ts"; | import { font } from "./font.ts"; | ||||||
| import { codeIcon, spriteIcon } from "./icons.ts"; | import { codeIcon, spriteIcon, mapIcon } from "./icons.ts"; | ||||||
| import { reGridWithGap } from "./util.ts"; | import { reGridWithGap } from "./util.ts"; | ||||||
|  |  | ||||||
| const fontHeight = font.height; | const fontHeight = font.height; | ||||||
| @@ -44,6 +44,7 @@ const draw = () => { | |||||||
| 		const icon = { | 		const icon = { | ||||||
| 			code: codeIcon, | 			code: codeIcon, | ||||||
| 			spritesheet: spriteIcon, | 			spritesheet: spriteIcon, | ||||||
|  | 			map: mapIcon, | ||||||
| 			none: null, | 			none: null, | ||||||
| 		}[sheet.sheet_type]; | 		}[sheet.sheet_type]; | ||||||
| 		if (icon) { | 		if (icon) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 dylan
					dylan