mirror of
				https://github.com/tobspr/shapez.io.git
				synced 2025-06-13 13:04:03 +00:00 
			
		
		
		
	
		
			
	
	
		
			174 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			174 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | /** | ||
|  |  * | ||
|  |  * Run `yarn global add canvas` first | ||
|  |  */ | ||
|  | 
 | ||
|  | const { createCanvas, loadImage } = require("canvas"); | ||
|  | const fs = require("fs"); | ||
|  | const path = require("path"); | ||
|  | const { fileURLToPath } = require("url"); | ||
|  | 
 | ||
|  | async function run() { | ||
|  |     console.log("Running"); | ||
|  | 
 | ||
|  |     const fps = 28; | ||
|  |     const dimensions = 126; | ||
|  |     const beltBorder = 15.5; | ||
|  | 
 | ||
|  |     const borderColor = "#91949e"; | ||
|  |     const fillColor = "#d2d4d9"; | ||
|  |     const arrowColor = "#c0c2c7"; | ||
|  | 
 | ||
|  |     // Generate arrow sprite
 | ||
|  | 
 | ||
|  |     const arrowW = 40; | ||
|  |     const arrowH = 20; | ||
|  |     /** @type {HTMLCanvasElement} */ | ||
|  |     const arrowSprite = createCanvas(arrowW, arrowH); | ||
|  |     const arrowContext = arrowSprite.getContext("2d"); | ||
|  | 
 | ||
|  |     arrowContext.quality = "best"; | ||
|  |     arrowContext.fillStyle = arrowColor; | ||
|  |     arrowContext.clearRect(0, 0, arrowW, arrowH); | ||
|  |     arrowContext.beginPath(); | ||
|  |     arrowContext.moveTo(0, arrowH); | ||
|  |     arrowContext.lineTo(arrowW / 2, 0); | ||
|  |     arrowContext.lineTo(arrowW, arrowH); | ||
|  |     arrowContext.closePath(); | ||
|  |     arrowContext.fill(); | ||
|  | 
 | ||
|  |     // First, generate the forward belt
 | ||
|  |     for (let i = 0; i < fps; ++i) { | ||
|  |         /** @type {HTMLCanvasElement} */ | ||
|  |         const canvas = createCanvas(dimensions, dimensions); | ||
|  |         const context = canvas.getContext("2d"); | ||
|  |         context.quality = "best"; | ||
|  | 
 | ||
|  |         const procentual = i / fps; | ||
|  |         context.clearRect(0, 0, dimensions, dimensions); | ||
|  | 
 | ||
|  |         context.fillStyle = fillColor; | ||
|  |         context.strokeStyle = borderColor; | ||
|  |         context.lineWidth = 3; | ||
|  | 
 | ||
|  |         context.beginPath(); | ||
|  |         context.rect(beltBorder, -10, dimensions - 2 * beltBorder, dimensions + 20); | ||
|  |         context.fill(); | ||
|  |         context.stroke(); | ||
|  | 
 | ||
|  |         const spacingBetweenArrows = (dimensions - 3 * arrowH) / 3; | ||
|  |         const spacingTotal = spacingBetweenArrows + arrowH; | ||
|  | 
 | ||
|  |         for (let k = 0; k < 5; ++k) { | ||
|  |             let y = dimensions - arrowH - (k - 1) * spacingTotal - procentual * spacingTotal; | ||
|  |             context.drawImage(arrowSprite, dimensions / 2 - arrowW / 2, y); | ||
|  |         } | ||
|  | 
 | ||
|  |         const out = fs.createWriteStream(path.join(__dirname, "forward_" + i + ".png")); | ||
|  |         const stream = canvas.createPNGStream(); | ||
|  |         stream.pipe(out); | ||
|  |     } | ||
|  | 
 | ||
|  |     // Generate left and right side belt
 | ||
|  |     for (let i = 0; i < fps; ++i) { | ||
|  |         /** @type {HTMLCanvasElement} */ | ||
|  |         const canvas = createCanvas(dimensions, dimensions); | ||
|  |         const context = canvas.getContext("2d"); | ||
|  |         context.quality = "best"; | ||
|  | 
 | ||
|  |         const procentual = i / fps; | ||
|  |         const innerRadius = beltBorder; | ||
|  |         context.clearRect(0, 0, dimensions, dimensions); | ||
|  | 
 | ||
|  |         context.fillStyle = fillColor; | ||
|  |         context.strokeStyle = borderColor; | ||
|  |         context.lineWidth = 3; | ||
|  | 
 | ||
|  |         context.beginPath(); | ||
|  |         context.moveTo(beltBorder, dimensions + 10); | ||
|  |         context.lineTo(beltBorder, dimensions - innerRadius); | ||
|  | 
 | ||
|  |         const steps = 256; | ||
|  | 
 | ||
|  |         const outerRadius = dimensions - 2 * beltBorder; | ||
|  | 
 | ||
|  |         const originX = dimensions - innerRadius; | ||
|  |         const originY = dimensions - innerRadius; | ||
|  | 
 | ||
|  |         const sqrt = x => Math.pow(Math.abs(x), 0.975) * Math.sign(x); | ||
|  | 
 | ||
|  |         for (let k = 0; k <= steps; ++k) { | ||
|  |             const pct = k / steps; | ||
|  |             const angleRad = Math.PI + pct * Math.PI * 0.5; | ||
|  |             const offX = originX + sqrt(Math.cos(angleRad)) * outerRadius; | ||
|  |             const offY = originY + sqrt(Math.sin(angleRad)) * outerRadius; | ||
|  | 
 | ||
|  |             context.lineTo(offX, offY); | ||
|  |         } | ||
|  | 
 | ||
|  |         context.lineTo(dimensions + 10, beltBorder); | ||
|  |         context.lineTo(dimensions + 10, dimensions - beltBorder); | ||
|  |         context.lineTo(dimensions, dimensions - beltBorder); | ||
|  | 
 | ||
|  |         for (let k = 0; k <= steps; ++k) { | ||
|  |             const pct = 1 - k / steps; | ||
|  |             const angleRad = Math.PI + pct * Math.PI * 0.5; | ||
|  |             const offX = dimensions + Math.cos(angleRad) * innerRadius; | ||
|  |             const offY = dimensions + Math.sin(angleRad) * innerRadius; | ||
|  | 
 | ||
|  |             context.lineTo(offX, offY); | ||
|  |         } | ||
|  | 
 | ||
|  |         context.lineTo(dimensions - beltBorder, dimensions + 10); | ||
|  | 
 | ||
|  |         context.closePath(); | ||
|  |         context.fill(); | ||
|  |         context.stroke(); | ||
|  | 
 | ||
|  |         // Arrows
 | ||
|  |         const rotationalRadius = dimensions / 2 - arrowH / 2 + 0.5; | ||
|  | 
 | ||
|  |         const circumfence = (rotationalRadius * Math.PI * 2) / 4; | ||
|  |         console.log("Circumfence:", circumfence, "px"); | ||
|  | 
 | ||
|  |         const remainingSpace = circumfence - 3 * arrowH + arrowH; | ||
|  |         console.log("Remainig:", remainingSpace); | ||
|  |         const spacing = remainingSpace / 3 + arrowH; | ||
|  | 
 | ||
|  |         console.log("Spacing: ", spacing); | ||
|  |         const angleSpacing = ((spacing / circumfence) * Math.PI) / 2; | ||
|  | 
 | ||
|  |         for (let i = 0; i < 5; ++i) { | ||
|  |             let angleRad = Math.PI + procentual * angleSpacing + (i - 1) * angleSpacing; | ||
|  |             const offX = dimensions - arrowH / 2 + Math.cos(angleRad * 0.995) * rotationalRadius; | ||
|  |             const offY = dimensions - arrowH / 2 + Math.sin(angleRad * 0.995) * rotationalRadius; | ||
|  | 
 | ||
|  |             angleRad = Math.max(Math.PI, Math.min(1.5 * Math.PI, angleRad)); | ||
|  | 
 | ||
|  |             context.save(); | ||
|  |             context.translate(offX, offY); | ||
|  |             context.rotate(angleRad + Math.PI); | ||
|  |             context.drawImage(arrowSprite, -arrowW / 2, -arrowH / 2); | ||
|  |             context.restore(); | ||
|  |         } | ||
|  | 
 | ||
|  |         /** @type {HTMLCanvasElement} */ | ||
|  |         const flippedCanvas = createCanvas(dimensions, dimensions); | ||
|  |         const flippedContext = flippedCanvas.getContext("2d"); | ||
|  |         flippedContext.quality = "best"; | ||
|  |         flippedContext.clearRect(0, 0, dimensions, dimensions); | ||
|  |         flippedContext.scale(-1, 1); | ||
|  |         flippedContext.drawImage(canvas, -dimensions, 0, dimensions, dimensions); | ||
|  | 
 | ||
|  |         const out = fs.createWriteStream(path.join(__dirname, "right_" + i + ".png")); | ||
|  |         const stream = canvas.createPNGStream(); | ||
|  |         stream.pipe(out); | ||
|  | 
 | ||
|  |         const outLeft = fs.createWriteStream(path.join(__dirname, "left_" + i + ".png")); | ||
|  |         const streamLeft = flippedCanvas.createPNGStream(); | ||
|  |         streamLeft.pipe(outLeft); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | run(); |