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 { SheetType, setSheet } from "./sheet.ts"; | ||||
| import { nonetab } from "./nonetab.ts"; | ||||
| import { maptab } from "./maptab.ts"; | ||||
|  | ||||
| type TabName = SheetType; // "code" | "sprite" | "map" | "sfx" | "music" | "sheet"; | ||||
|  | ||||
| @@ -61,6 +62,8 @@ const update = () => { | ||||
| 		codetab.update(); | ||||
| 	} else if (page.tab === "spritesheet") { | ||||
| 		spritetab.update(); | ||||
| 	} else if (page.tab === "map") { | ||||
| 		maptab.update(); | ||||
| 	} else if (page.tab === "sheet") { | ||||
| 		viewsheets.update(); | ||||
| 	} else if (page.tab === "none") { | ||||
| @@ -74,6 +77,8 @@ const draw = () => { | ||||
| 		codetab.draw(); | ||||
| 	} else if (page.tab === "spritesheet") { | ||||
| 		spritetab.draw(); | ||||
| 	} else if (page.tab === "map") { | ||||
| 		maptab.draw(); | ||||
| 	} else if (page.tab === "sheet") { | ||||
| 		viewsheets.draw(); | ||||
| 	} 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, | ||||
| ]; | ||||
|  | ||||
| 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 = [ | ||||
| 	0, 0, 0, 0, 0, 0, 0, 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 { page } from "./viewsheets.ts"; | ||||
| import { useSpritesheet } from "./builtins.ts"; | ||||
| import { codeIcon, spriteIcon } from "./icons.ts"; | ||||
| import { codeIcon, mapIcon, spriteIcon } from "./icons.ts"; | ||||
|  | ||||
| const gridX = 8; | ||||
| const gridY = 40; | ||||
| @@ -15,10 +15,11 @@ const cellH = 8; | ||||
| const gapX = 8; | ||||
| const gapY = 8; | ||||
|  | ||||
| const sheetTypes = ["code", "spritesheet"] as const; | ||||
| const sheetTypes = ["code", "spritesheet", "map"] as const; | ||||
| const defaultSheetVal = { | ||||
| 	code: () => "", | ||||
| 	spritesheet: () => Array(64).fill(0).map(() => Array(64).fill(0)), | ||||
| 	map: () => Array(64*64).fill(0).map(() => [0, 0]), | ||||
| 	none: () =>null, | ||||
| } | ||||
|  | ||||
| @@ -49,6 +50,7 @@ const draw = () => { | ||||
| 		const icon = { | ||||
| 			code: codeIcon, | ||||
| 			spritesheet: spriteIcon, | ||||
| 			map: mapIcon, | ||||
| 			none: null, | ||||
| 		}[sheetType]; | ||||
| 		drawIcon(sx, sy, icon, COLOR.BLUE); | ||||
|   | ||||
							
								
								
									
										13
									
								
								sheet.ts
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								sheet.ts
									
									
									
									
									
								
							| @@ -8,6 +8,9 @@ export type Sheet = { | ||||
| } | { | ||||
| 	sheet_type: "spritesheet", | ||||
| 	value: Array<Array<number>>, | ||||
| } | { | ||||
| 	sheet_type: "map", | ||||
| 	value: Array<[number, number]>, | ||||
| } | { | ||||
| 	sheet_type: "none", | ||||
| 	value: null, | ||||
| @@ -34,7 +37,15 @@ export const getCodeSheet = (sheet: number) => { | ||||
| export const getSpriteSheet = (sheet: number) => { | ||||
| 	const {sheet_type, value} = getSheet(sheet); | ||||
| 	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; | ||||
| } | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import { getSheet } from "./sheet.ts"; | ||||
| import { mouseClick, mousePos } from "./mouse.ts"; | ||||
| import { getCart } from "./cart.ts"; | ||||
| import { font } from "./font.ts"; | ||||
| import { codeIcon, spriteIcon } from "./icons.ts"; | ||||
| import { codeIcon, spriteIcon, mapIcon } from "./icons.ts"; | ||||
| import { reGridWithGap } from "./util.ts"; | ||||
|  | ||||
| const fontHeight = font.height; | ||||
| @@ -44,6 +44,7 @@ const draw = () => { | ||||
| 		const icon = { | ||||
| 			code: codeIcon, | ||||
| 			spritesheet: spriteIcon, | ||||
| 			map: mapIcon, | ||||
| 			none: null, | ||||
| 		}[sheet.sheet_type]; | ||||
| 		if (icon) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 dylan
					dylan