From cc3a007251f4329708c21563df6312ff476a500a Mon Sep 17 00:00:00 2001 From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com> Date: Tue, 19 Nov 2024 11:38:43 +0000 Subject: [PATCH 01/10] Add files via upload --- .../Cool_skratcher/abbreviations.js | 318 ++++++++++++++++++ static/extensions/Cool_skratcher/noise.js | 185 ++++++++++ static/extensions/Cool_skratcher/vectors.js | 305 +++++++++++++++++ 3 files changed, 808 insertions(+) create mode 100644 static/extensions/Cool_skratcher/abbreviations.js create mode 100644 static/extensions/Cool_skratcher/noise.js create mode 100644 static/extensions/Cool_skratcher/vectors.js diff --git a/static/extensions/Cool_skratcher/abbreviations.js b/static/extensions/Cool_skratcher/abbreviations.js new file mode 100644 index 00000000..ef542672 --- /dev/null +++ b/static/extensions/Cool_skratcher/abbreviations.js @@ -0,0 +1,318 @@ +// Name: Number Abbiviation! +// ID: abbreviate +// Description: Adds blocks to convert any big number to way less text like: 1200000 -> 1.2M. +// By: cool_skratcher +// License: MIT + +(function (Scratch) { + "use strict"; + + class Abbreviation { + getInfo() { + return { + id: "abbreviate", + name: "Abbreviation!", + color1: "#9dd13d", + color2: "#8fbe37", + blocks: [ + { + opcode: "abbriviate", + blockType: Scratch.BlockType.REPORTER, + text: "abbreviate: [NUM]", + arguments: { + NUM: { + type: Scratch.ArgumentType.NUMBER, + }, + }, + }, + { + opcode: "unabbriviate", + blockType: Scratch.BlockType.REPORTER, + text: "un-abbreviate: [NUM]", + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + }, + }, + }, + { + opcode: "addabbriviated", + blockType: Scratch.BlockType.REPORTER, + text: "add abbreviated [NUM1] + [NUM2]", + arguments: { + NUM1: { + type: Scratch.ArgumentType.STRING, + }, + NUM2: { + type: Scratch.ArgumentType.STRING, + }, + }, + }, + { + opcode: "subabbriviated", + blockType: Scratch.BlockType.REPORTER, + text: "subtract abbreviated [NUM1] - [NUM2]", + arguments: { + NUM1: { + type: Scratch.ArgumentType.STRING, + }, + NUM2: { + type: Scratch.ArgumentType.STRING, + }, + }, + }, + { + opcode: "multiabbriviated", + blockType: Scratch.BlockType.REPORTER, + text: "multiply abbreviated [NUM1] * [NUM2]", + arguments: { + NUM1: { + type: Scratch.ArgumentType.STRING, + }, + NUM2: { + type: Scratch.ArgumentType.STRING, + }, + }, + }, + { + opcode: "divabbriviated", + blockType: Scratch.BlockType.REPORTER, + text: "divide abbreviated [NUM1] / [NUM2]", + arguments: { + NUM1: { + type: Scratch.ArgumentType.STRING, + }, + NUM2: { + type: Scratch.ArgumentType.STRING, + }, + }, + }, + { + opcode: "equalabbriviated", + blockType: Scratch.BlockType.BOOLEAN, + text: "is equal abbreviated [NUM1] = [NUM2]", + arguments: { + NUM1: { + type: Scratch.ArgumentType.STRING, + }, + NUM2: { + type: Scratch.ArgumentType.STRING, + }, + }, + }, + { + opcode: "moreabbriviated", + blockType: Scratch.BlockType.BOOLEAN, + text: "is greater abbreviated [NUM1] > [NUM2]", + arguments: { + NUM1: { + type: Scratch.ArgumentType.STRING, + }, + NUM2: { + type: Scratch.ArgumentType.STRING, + }, + }, + }, + { + opcode: "lessabbriviated", + blockType: Scratch.BlockType.BOOLEAN, + text: "is less abbreviated [NUM1] < [NUM2]", + arguments: { + NUM1: { + type: Scratch.ArgumentType.STRING, + }, + NUM2: { + type: Scratch.ArgumentType.STRING, + }, + }, + }, + ], + }; + } + abbriviate(args) { + return abbreviateNumber(args.NUM); + } + unabbriviate(args) { + return unAbbreviateNumber(args.NUM); + } + addabbriviated(args) { + return addAbbreviated(args.NUM1, args.NUM2); + } + subabbriviated(args) { + return subtractAbbreviated(args.NUM1, args.NUM2); + } + multiabbriviated(args) { + return multiplyAbbreviated(args.NUM1, args.NUM2); + } + divabbriviated(args) { + return divideAbbreviated(args.NUM1, args.NUM2); + } + equalabbriviated(args) { + if (compareAbbreviated(args.NUM1, args.NUM2) === 0) { + return true; + } else { + return false; + } + } + moreabbriviated(args) { + if (compareAbbreviated(args.NUM1, args.NUM2) === 1) { + return true; + } else { + return false; + } + } + lessabbriviated(args) { + if (compareAbbreviated(args.NUM1, args.NUM2) === -1) { + return true; + } else { + return false; + } + } + } + + function abbreviateNumber(number) { + const suffixes = [ + "", + "K", + "M", + "B", + "T", + "Q", + "Qi", + "Sx", + "Sp", + "Oc", + "Nn", + "Dc", + "Ud", + "Dd", + "Td", + "Qd", + "Qid", + "Sxd", + "Spd", + "Ocd", + "Nnd", + "Vg", + "Uvg", + "Dvg", + "Tvg", + "Qvg", + "Qivg", + "Sxvg", + "Spvg", + "Ocvg", + "Nnvg", + "Ce", + ]; + + if (Math.abs(number) < 1000) return number.toString(); + + const suffixIndex = Math.floor(Math.log10(Math.abs(number)) / 3); + if (suffixIndex >= suffixes.length) { + return number.toExponential(1); + } + + const abbreviatedNumber = (number / Math.pow(1000, suffixIndex)).toFixed(1); + return `${abbreviatedNumber}${suffixes[suffixIndex]}`; + } + + function unAbbreviateNumber(abbreviated) { + const suffixes = { + K: 1e3, + M: 1e6, + B: 1e9, + T: 1e12, + Q: 1e15, + QI: 1e18, + SX: 1e21, + SP: 1e24, + OC: 1e27, + NN: 1e30, + DC: 1e33, + UD: 1e36, + DD: 1e39, + TD: 1e42, + QD: 1e45, + QID: 1e48, + SXD: 1e51, + SPD: 1e54, + OCD: 1e57, + NND: 1e60, + VG: 1e63, + UVG: 1e66, + DVG: 1e69, + TVG: 1e72, + QVG: 1e75, + QIVG: 1e78, + SXVG: 1e81, + SPVG: 1e84, + OCVG: 1e87, + NNVG: 1e90, + CE: 1e303, + }; + + const regex = /^(-?\d+(\.\d+)?)([a-zA-Z]*)$/; + const match = abbreviated.match(regex); + + if (!match) return NaN; + + const numberPart = parseFloat(match[1]); + const suffix = match[3].toUpperCase(); + + if (!suffix) return numberPart; + + const multiplier = suffixes[suffix]; + if (!multiplier) return NaN; + + return numberPart * multiplier; + } + + function addAbbreviated(a, b) { + const num1 = unAbbreviateNumber(a); + const num2 = unAbbreviateNumber(b); + if (isNaN(num1) || isNaN(num2)) return NaN; + + const sum = num1 + num2; + return abbreviateNumber(sum); + } + + function subtractAbbreviated(a, b) { + const num1 = unAbbreviateNumber(a); + const num2 = unAbbreviateNumber(b); + if (isNaN(num1) || isNaN(num2)) return NaN; + + const difference = num1 - num2; + return abbreviateNumber(difference); + } + + function multiplyAbbreviated(a, b) { + const num1 = unAbbreviateNumber(a); + const num2 = unAbbreviateNumber(b); + if (isNaN(num1) || isNaN(num2)) return NaN; + + const product = num1 * num2; + return abbreviateNumber(product); + } + + function divideAbbreviated(a, b) { + const num1 = unAbbreviateNumber(a); + const num2 = unAbbreviateNumber(b); + if (isNaN(num1) || isNaN(num2) || num2 === 0) return NaN; + + const quotient = num1 / num2; + return abbreviateNumber(quotient); + } + + function compareAbbreviated(a, b) { + const num1 = unAbbreviateNumber(a); + const num2 = unAbbreviateNumber(b); + if (isNaN(num1) || isNaN(num2)) return NaN; + + if (num1 > num2) return 1; + if (num1 < num2) return -1; + return 0; + } + + Scratch.extensions.register(new Abbreviation()); +})(Scratch); diff --git a/static/extensions/Cool_skratcher/noise.js b/static/extensions/Cool_skratcher/noise.js new file mode 100644 index 00000000..7e2846e1 --- /dev/null +++ b/static/extensions/Cool_skratcher/noise.js @@ -0,0 +1,185 @@ +(function(Scratch) { + 'use strict'; + + // Perlin Noise algorithm from Noise.js + const Perlin = { + perm: new Array(512), + gradP: new Array(512), + grad3: [ + [1, 1, 0], [-1, 1, 0], [1, -1, 0], [-1, -1, 0], + [1, 0, 1], [-1, 0, 1], [1, 0, -1], [-1, 0, -1], + [0, 1, 1], [0, -1, 1], [0, 1, -1], [0, -1, -1] + ], + seed(seed) { + let p = []; + for (let i = 0; i < 256; i++) { + p[i] = i; + } + let n, q; + for (let i = 255; i > 0; i--) { + n = Math.floor(seed * (i + 1)) % 256; + q = p[i]; + p[i] = p[n]; + p[n] = q; + } + for (let i = 0; i < 512; i++) { + this.perm[i] = p[i & 255]; + this.gradP[i] = this.grad3[this.perm[i] % 12]; + } + }, + fade(t) { + return t * t * t * (t * (t * 6 - 15) + 10); + }, + lerp(t, a, b) { + return a + t * (b - a); + }, + dot(g, x, y) { + return g[0] * x + g[1] * y; + }, + noise(x, y) { + const X = Math.floor(x) & 255; + const Y = Math.floor(y) & 255; + x = x - Math.floor(x); + y = y - Math.floor(y); + + const u = this.fade(x); + const v = this.fade(y); + + const grad00 = this.gradP[X + this.perm[Y]]; + const grad01 = this.gradP[X + this.perm[Y + 1]]; + const grad10 = this.gradP[X + 1 + this.perm[Y]]; + const grad11 = this.gradP[X + 1 + this.perm[Y + 1]]; + + const n00 = this.dot(grad00, x, y); + const n10 = this.dot(grad10, x - 1, y); + const n01 = this.dot(grad01, x, y - 1); + const n11 = this.dot(grad11, x - 1, y - 1); + + const nx0 = this.lerp(u, n00, n10); + const nx1 = this.lerp(u, n01, n11); + + return this.lerp(v, nx0, nx1); + } + }; + + class PerlinNoiseExtension { + constructor() { + this.noiseMap = {}; + } + + // Pre-generate Perlin noise based on seed and store it + generateNoise(seed, octaves) { + Perlin.seed(seed); + this.noiseMap[seed] = { octaves }; + } + + // Get pre-generated noise at X, Y + getNoiseAt({ seed, x, y }) { + const noiseData = this.noiseMap[seed]; + if (!noiseData) { + return 0; // Return 0 if noise is not pre-generated + } + + const { octaves } = noiseData; + let total = 0; + let frequency = 1; + let amplitude = 1; + let maxValue = 0; + + for (let i = 0; i < octaves; i++) { + total += Perlin.noise(x * frequency, y * frequency) * amplitude; + maxValue += amplitude; + amplitude /= 2; + frequency *= 2; + } + + return total / maxValue; // Normalize the result + } + + // Get Perlin noise directly without pre-generation + getDirectNoise({ seed, x, y, octaves }) { + Perlin.seed(seed); + let total = 0; + let frequency = 1; + let amplitude = 1; + let maxValue = 0; + + for (let i = 0; i < octaves; i++) { + total += Perlin.noise(x * frequency, y * frequency) * amplitude; + maxValue += amplitude; + amplitude /= 2; + frequency *= 2; + } + + return total / maxValue; // Normalize the result + } + + getInfo() { + return { + id: 'perlinNoise', + name: 'Perlin Noise', + blocks: [ + { + opcode: 'generateNoise', + blockType: Scratch.BlockType.COMMAND, + text: 'pre-generate perlin noise Seed: [SEED] Octave: [OCTAVE]', + arguments: { + SEED: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1234, + }, + OCTAVE: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 4, + }, + }, + }, + { + opcode: 'getNoiseAt', + blockType: Scratch.BlockType.REPORTER, + text: 'get pre-generated perlin noise Seed: [SEED] at X: [X] Y: [Y]', + arguments: { + SEED: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1234, + }, + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + }, + }, + { + opcode: 'getDirectNoise', + blockType: Scratch.BlockType.REPORTER, + text: 'get direct perlin noise Seed: [SEED] X: [X] Y: [Y] Octave: [OCTAVE]', + arguments: { + SEED: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1234, + }, + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + OCTAVE: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 4, + }, + }, + } + ], + }; + } + } + + Scratch.extensions.register(new PerlinNoiseExtension()); +})(Scratch); \ No newline at end of file diff --git a/static/extensions/Cool_skratcher/vectors.js b/static/extensions/Cool_skratcher/vectors.js new file mode 100644 index 00000000..230d3362 --- /dev/null +++ b/static/extensions/Cool_skratcher/vectors.js @@ -0,0 +1,305 @@ +// Name: Vectors! +// ID: vectors +// Description: Adds a set of blocks for vector operations in 2D and 3D space. +// By: cool_skratcher +// License: MIT + +(function(Scratch) { + 'use strict'; + + class VecMath3D { + constructor() { + this.camera = { pos: { x: 0, y: 0, z: 0 }, rot: { yaw: 0, pitch: 0, roll: 0 }, fov: 100 }; + } + + getInfo() { + return { + id: 'vectors', + name: 'Vectors', + color1: "#57a3e5", + color2: "#0063ba", + blocks: [ + "---", + { text: 'Vector Operations', blockType: Scratch.BlockType.LABEL}, + { opcode: 'vec2', blockType: Scratch.BlockType.REPORTER, text: 'vec2 [x] [y]', arguments: { x: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 } }}, + { opcode: 'vec3', blockType: Scratch.BlockType.REPORTER, text: 'vec3 [x] [y] [z]', arguments: { x: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, z: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }}}, + { opcode: 'getComponent', blockType: Scratch.BlockType.REPORTER, text: '[component] of [v]', arguments: { component: { type: Scratch.ArgumentType.STRING, menu: 'components' }, v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}}, + { opcode: 'add', blockType: Scratch.BlockType.REPORTER, text: 'add [v1] [v2]', arguments: { v1: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, v2: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}}, + { opcode: 'sub', blockType: Scratch.BlockType.REPORTER, text: 'sub [v1] [v2]', arguments: { v1: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, v2: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}}, + { opcode: 'mul', blockType: Scratch.BlockType.REPORTER, text: 'mul [v] by [scalar]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, scalar: { type: Scratch.ArgumentType.NUMBER, defaultValue: 1 }}}, + { opcode: 'div', blockType: Scratch.BlockType.REPORTER, text: 'div [v] by [scalar]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, scalar: { type: Scratch.ArgumentType.NUMBER, defaultValue: 1 }}}, + { opcode: 'mag', blockType: Scratch.BlockType.REPORTER, text: 'mag [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}}, + { opcode: 'dot', blockType: Scratch.BlockType.REPORTER, text: 'dot [v1] [v2]', arguments: { v1: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, v2: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}}, + { opcode: 'cross', blockType: Scratch.BlockType.REPORTER, text: 'cross [v1] [v2]', arguments: { v1: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, v2: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}}, + { opcode: 'rotateVec3', blockType: Scratch.BlockType.REPORTER, text: 'rotate [v] by x: [rx] y: [ry] z: [rz]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, rx: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, ry: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, rz: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }}}, + { opcode: 'rotateAroundOrigin', blockType: Scratch.BlockType.REPORTER, text: 'rotate [v] around [origin] by x: [rx] y: [ry] z: [rz]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, origin: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, rx: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, ry: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, rz: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }}}, + "---", + { text: 'Culling', blockType: Scratch.BlockType.LABEL}, + { opcode: 'isCulled', blockType: Scratch.BlockType.BOOLEAN, text: 'is [v] culled', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}}, + { opcode: 'cullAgainstPlane', blockType: Scratch.BlockType.BOOLEAN, text: 'is [v] culled against plane [plane]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, plane: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,1' }}}, + { opcode: 'frustumCull', blockType: Scratch.BlockType.BOOLEAN, text: 'is [v] inside frustum with near: [near] far: [far]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, near: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0.1 }, far: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 }}}, + { opcode: 'backFaceCull', blockType: Scratch.BlockType.BOOLEAN, text: 'is face [v1] [v2] [v3] culled', arguments: { v1: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }, v2: { type: Scratch.ArgumentType.STRING, defaultValue: '1,0,0' }, v3: { type: Scratch.ArgumentType.STRING, defaultValue: '0,1,0' }}}, + "---", + { text: 'Projection and Camera', blockType: Scratch.BlockType.LABEL}, + { opcode: 'project', blockType: Scratch.BlockType.REPORTER, text: 'project [v] to screen', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}}, + { opcode: 'setCamPos', blockType: Scratch.BlockType.COMMAND, text: 'set camera pos to [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}}, + { opcode: 'changeCamPos', blockType: Scratch.BlockType.COMMAND, text: 'change camera pos by [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}}, + { opcode: 'changeCamComponent', blockType: Scratch.BlockType.COMMAND, text: 'change camera [component] by [val]', arguments: { component: { type: Scratch.ArgumentType.STRING, menu: 'components' }, val: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }}}, + { opcode: 'getCamPos', blockType: Scratch.BlockType.REPORTER, text: 'camera pos' }, + + { opcode: 'setCamRot', blockType: Scratch.BlockType.COMMAND, text: 'set camera rotation to [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}}, + { opcode: 'changeCamRot', blockType: Scratch.BlockType.COMMAND, text: 'change camera rotation by [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0,0' }}}, + { opcode: 'changeCamAngle', blockType: Scratch.BlockType.COMMAND, text: 'change camera [angle] by [val]', arguments: { angle: { type: Scratch.ArgumentType.STRING, menu: 'angles' }, val: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }}}, + { opcode: 'getCamRot', blockType: Scratch.BlockType.REPORTER, text: 'camera rotation' }, + + { opcode: 'setFOV', blockType: Scratch.BlockType.COMMAND, text: 'set FOV to [val]', arguments: { val: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 }}}, + { opcode: 'changeFOV', blockType: Scratch.BlockType.COMMAND, text: 'change FOV by [val]', arguments: { val: { type: Scratch.ArgumentType.NUMBER, defaultValue: 10 }}}, + { opcode: 'getFOV', blockType: Scratch.BlockType.REPORTER, text: 'FOV' }, + "---", + { text: 'Sprite Movement', blockType: Scratch.BlockType.LABEL }, + { opcode: 'moveByVec2', blockType: Scratch.BlockType.COMMAND, text: 'change pos by vec2 [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }}}, + { opcode: 'goToVec2', blockType: Scratch.BlockType.COMMAND, text: 'go to vec2 [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }}}, + { opcode: 'getPosVec2', blockType: Scratch.BlockType.REPORTER, text: 'get position as vec2' }, + { opcode: 'getSizeVec2', blockType: Scratch.BlockType.REPORTER, text: 'get size as vec2' }, + ], + menus: { + components: { items: ['x', 'y', 'z'] }, + angles: { items: ['yaw', 'pitch', 'roll'] }, + } + }; + } + + // Vector creation + vec2(args) { return `${args.x},${args.y},0`; } + vec3(args) { return `${args.x},${args.y},${args.z}`; } + + // Vector component access + getComponent(args) { + const [x, y, z = 0] = args.v.split(',').map(Number); + return args.component === 'x' ? x : args.component === 'y' ? y : z; + } + + // Basic vector math + add(args) { return this._vectorOp(args.v1, args.v2, (a, b) => a + b); } + sub(args) { return this._vectorOp(args.v1, args.v2, (a, b) => a - b); } + mul(args) { return this._scalarOp(args.v, args.scalar, (a, b) => a * b); } + div(args) { return this._scalarOp(args.v, args.scalar, (a, b) => a / b); } + mag(args) { return Math.hypot(...args.v.split(',').map(Number)); } + dot(args) { + const [x1, y1, z1] = args.v1.split(',').map(Number); + const [x2, y2, z2] = args.v2.split(',').map(Number); + return x1 * x2 + y1 * y2 + z1 * z2; + } + cross(args) { + const [x1, y1, z1] = args.v1.split(',').map(Number); + const [x2, y2, z2] = args.v2.split(',').map(Number); + return `${y1 * z2 - z1 * y2},${z1 * x2 - x1 * z2},${x1 * y2 - y1 * x2}`; + } + + rotateVec3(args) { + const [x, y, z] = args.v.split(',').map(Number); + return this._rotate3D({ x, y, z }, args.rx, args.ry, args.rz); + } + + // Camera Controls + setCamPos(args) { this._setVec(this.camera.pos, args.v); } + changeCamPos(args) { this._addVec(this.camera.pos, args.v); } + changeCamComponent(args) { this.camera.pos[args.component] += args.val; } + getCamPos() { return `${this.camera.pos.x},${this.camera.pos.y},${this.camera.pos.z}`; } + + setCamRot(args) { this._setRot(this.camera.rot, args.v); } + changeCamRot(args) { this._addRot(this.camera.rot, args.v); } + changeCamAngle(args) { this.camera.rot[args.angle] += args.val; } + getCamRot() { return `${this.camera.rot.yaw},${this.camera.rot.pitch},${this.camera.rot.roll}`; } + + setFOV(args) { this.camera.fov = args.val; } + changeFOV(args) { this.camera.fov += args.val; } + getFOV() { return this.camera.fov; } + + // Projection + project(args) { + const [x, y, z] = args.v.split(',').map(Number); + const cam = this.camera; + const dx = x - cam.pos.x, dy = y - cam.pos.y, dz = z - cam.pos.z; + + // Apply yaw rotation + const camZ = dz * Math.cos(cam.rot.yaw) + dx * Math.sin(cam.rot.yaw); + const camX = dx * Math.cos(cam.rot.yaw) - dz * Math.sin(cam.rot.yaw); + + // Apply pitch rotation + const tempY = dy * Math.cos(cam.rot.pitch) - camZ * Math.sin(cam.rot.pitch); + const tempZ = dy * Math.sin(cam.rot.pitch) + camZ * Math.cos(cam.rot.pitch); + const finalZ = tempZ; // This is now the new Z after pitch rotation + const finalY = tempY; // This is now the new Y after pitch rotation + + // Apply roll rotation + const finalX = finalY * Math.sin(cam.rot.roll) + camX * Math.cos(cam.rot.roll); + const adjustedY = finalY * Math.cos(cam.rot.roll) - camX * Math.sin(cam.rot.roll); + + // Calculate screen coordinates + const screenX = (finalX / finalZ) * cam.fov; + const screenY = (adjustedY / finalZ) * cam.fov; + return `${screenX},${screenY}`; + } + + rotateAroundOrigin(args) { + const [vx, vy, vz] = args.v.split(',').map(Number); + const [ox, oy, oz] = args.origin.split(',').map(Number); + const rx = (Math.PI / 180) * args.rx; + const ry = (Math.PI / 180) * args.ry; + const rz = (Math.PI / 180) * args.rz; + + // Translate vector to origin + let x = vx - ox; + let y = vy - oy; + let z = vz - oz; + + // Rotate around Z-axis + let tempX = x * Math.cos(rz) - y * Math.sin(rz); + let tempY = x * Math.sin(rz) + y * Math.cos(rz); + x = tempX; y = tempY; + + // Rotate around Y-axis + tempX = x * Math.cos(ry) + z * Math.sin(ry); + let tempZ = -x * Math.sin(ry) + z * Math.cos(ry); + x = tempX; z = tempZ; + + // Rotate around X-axis + tempY = y * Math.cos(rx) - z * Math.sin(rx); + tempZ = y * Math.sin(rx) + z * Math.cos(rx); + y = tempY; z = tempZ; + + // Translate back to original position + x += ox; + y += oy; + z += oz; + + return `${x},${y},${z}`; + } + + isCulled(args) { + const [x, y, z] = args.v.split(',').map(Number); + const { pos, rot } = this.camera; + + // Transform point relative to camera + const dx = x - pos.x; + const dy = y - pos.y; + const dz = z - pos.z; + + // Simple culling: check if behind the camera (z <= 0 in camera space) + const camZ = dz * Math.cos(rot.yaw) + dx * Math.sin(rot.yaw); + return camZ <= 0; + } + + cullAgainstPlane(args) { + const [x, y, z] = args.v.split(',').map(Number); + const [nx, ny, nz] = args.plane.split(',').map(Number); + + // Plane culling: check if point is behind the plane (dot product <= 0) + const dot = x * nx + y * ny + z * nz; + return dot <= 0; + } + + frustumCull(args) { + const [x, y, z] = args.v.split(',').map(Number); + const { pos, rot, fov } = this.camera; + const near = args.near, far = args.far; + + // Translate point relative to camera + const dx = x - pos.x; + const dy = y - pos.y; + const dz = z - pos.z; + + // Rotate point relative to camera + const cx = dx * Math.cos(rot.yaw) - dz * Math.sin(rot.yaw); + const cz = dx * Math.sin(rot.yaw) + dz * Math.cos(rot.yaw); + const cy = dy; + + // Check depth (near and far planes) + if (cz < near || cz > far) return true; + + // Check horizontal FOV + const hHalf = Math.tan((fov / 2) * (Math.PI / 180)) * cz; + if (cx < -hHalf || cx > hHalf) return true; + + // Check vertical FOV + const vHalf = hHalf * (3 / 4); // Assuming aspect ratio of 4:3 + if (cy < -vHalf || cy > vHalf) return true; + + return false; + } + + backFaceCull(args) { + const [x1, y1, z1] = args.v1.split(',').map(Number); + const [x2, y2, z2] = args.v2.split(',').map(Number); + const [x3, y3, z3] = args.v3.split(',').map(Number); + const { pos } = this.camera; + + // Calculate face normal + const ux = x2 - x1, uy = y2 - y1, uz = z2 - z1; + const vx = x3 - x1, vy = y3 - y1, vz = z3 - z1; + const nx = uy * vz - uz * vy; + const ny = uz * vx - ux * vz; + const nz = ux * vy - uy * vx; + + // Vector from camera to one vertex + const cx = x1 - pos.x, cy = y1 - pos.y, cz = z1 - pos.z; + + // Dot product of face normal and camera vector + const dot = nx * cx + ny * cy + nz * cz; + + return dot >= 0; + } + + // Utility Functions + _vectorOp(v1, v2, op) { + const [x1, y1, z1] = v1.split(',').map(Number); + const [x2, y2, z2] = v2.split(',').map(Number); + return `${op(x1, x2)},${op(y1, y2)},${op(z1, z2)}`; + } + + _scalarOp(v, scalar, op) { + const [x, y, z] = v.split(',').map(Number); + return `${op(x, scalar)},${op(y, scalar)},${op(z, scalar)}`; + } + + _setVec(target, v) { const [x, y, z] = v.split(',').map(Number); target.x = x; target.y = y; target.z = z; } + _addVec(target, v) { const [x, y, z] = v.split(',').map(Number); target.x += x; target.y += y; target.z += z; } + _setRot(target, v) { const [x, y, z] = v.split(',').map(Number); target.yaw = x; target.pitch = y; target.roll = z; } + _addRot(target, v) { const [x, y, z] = v.split(',').map(Number); target.yaw += x; target.pitch += y; target.roll += z; } + + _rotate3D(v, rx, ry, rz) { + const cos = Math.cos, sin = Math.sin; + let { x, y, z } = v; + [y, z] = [y * cos(rx) - z * sin(rx), y * sin(rx) + z * cos(rx)]; + [x, z] = [x * cos(ry) + z * sin(ry), -x * sin(ry) + z * cos(ry)]; + [x, y] = [x * cos(rz) - y * sin(rz), x * sin(rz) + y * cos(rz)]; + return `${x},${y},${z}`; + } + + moveByVec2(args, util) { + const [dx, dy] = args.v.split(',').map(Number); + const x = Scratch.Cast.toNumber(dx); + const y = Scratch.Cast.toNumber(dy); + util.target.setXY(util.target.x + x, util.target.y + y); + } + + goToVec2(args, util) { + const [dx, dy] = args.v.split(',').map(Number); + const x = Scratch.Cast.toNumber(dx); + const y = Scratch.Cast.toNumber(dy); + util.target.setXY(x, y); + } + + getPosVec2(args, util) { + return `${util.target.x},${util.target.y}`; + } + + getSizeVec2(args, util) { + const bounds = Scratch.vm.renderer.getBounds(util.target.drawableID) + return `${Math.ceil(bounds.width)},${Math.ceil(bounds.height)}`; + } + } + + Scratch.extensions.register(new VecMath3D()); +})(Scratch); From 18190b9a68aefe4c647ad9180369de316918bd55 Mon Sep 17 00:00:00 2001 From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com> Date: Tue, 19 Nov 2024 11:39:40 +0000 Subject: [PATCH 02/10] Delete static/extensions/Cool_skratcher/abbreviations.js --- .../Cool_skratcher/abbreviations.js | 318 ------------------ 1 file changed, 318 deletions(-) delete mode 100644 static/extensions/Cool_skratcher/abbreviations.js diff --git a/static/extensions/Cool_skratcher/abbreviations.js b/static/extensions/Cool_skratcher/abbreviations.js deleted file mode 100644 index ef542672..00000000 --- a/static/extensions/Cool_skratcher/abbreviations.js +++ /dev/null @@ -1,318 +0,0 @@ -// Name: Number Abbiviation! -// ID: abbreviate -// Description: Adds blocks to convert any big number to way less text like: 1200000 -> 1.2M. -// By: cool_skratcher -// License: MIT - -(function (Scratch) { - "use strict"; - - class Abbreviation { - getInfo() { - return { - id: "abbreviate", - name: "Abbreviation!", - color1: "#9dd13d", - color2: "#8fbe37", - blocks: [ - { - opcode: "abbriviate", - blockType: Scratch.BlockType.REPORTER, - text: "abbreviate: [NUM]", - arguments: { - NUM: { - type: Scratch.ArgumentType.NUMBER, - }, - }, - }, - { - opcode: "unabbriviate", - blockType: Scratch.BlockType.REPORTER, - text: "un-abbreviate: [NUM]", - arguments: { - NUM: { - type: Scratch.ArgumentType.STRING, - }, - }, - }, - { - opcode: "addabbriviated", - blockType: Scratch.BlockType.REPORTER, - text: "add abbreviated [NUM1] + [NUM2]", - arguments: { - NUM1: { - type: Scratch.ArgumentType.STRING, - }, - NUM2: { - type: Scratch.ArgumentType.STRING, - }, - }, - }, - { - opcode: "subabbriviated", - blockType: Scratch.BlockType.REPORTER, - text: "subtract abbreviated [NUM1] - [NUM2]", - arguments: { - NUM1: { - type: Scratch.ArgumentType.STRING, - }, - NUM2: { - type: Scratch.ArgumentType.STRING, - }, - }, - }, - { - opcode: "multiabbriviated", - blockType: Scratch.BlockType.REPORTER, - text: "multiply abbreviated [NUM1] * [NUM2]", - arguments: { - NUM1: { - type: Scratch.ArgumentType.STRING, - }, - NUM2: { - type: Scratch.ArgumentType.STRING, - }, - }, - }, - { - opcode: "divabbriviated", - blockType: Scratch.BlockType.REPORTER, - text: "divide abbreviated [NUM1] / [NUM2]", - arguments: { - NUM1: { - type: Scratch.ArgumentType.STRING, - }, - NUM2: { - type: Scratch.ArgumentType.STRING, - }, - }, - }, - { - opcode: "equalabbriviated", - blockType: Scratch.BlockType.BOOLEAN, - text: "is equal abbreviated [NUM1] = [NUM2]", - arguments: { - NUM1: { - type: Scratch.ArgumentType.STRING, - }, - NUM2: { - type: Scratch.ArgumentType.STRING, - }, - }, - }, - { - opcode: "moreabbriviated", - blockType: Scratch.BlockType.BOOLEAN, - text: "is greater abbreviated [NUM1] > [NUM2]", - arguments: { - NUM1: { - type: Scratch.ArgumentType.STRING, - }, - NUM2: { - type: Scratch.ArgumentType.STRING, - }, - }, - }, - { - opcode: "lessabbriviated", - blockType: Scratch.BlockType.BOOLEAN, - text: "is less abbreviated [NUM1] < [NUM2]", - arguments: { - NUM1: { - type: Scratch.ArgumentType.STRING, - }, - NUM2: { - type: Scratch.ArgumentType.STRING, - }, - }, - }, - ], - }; - } - abbriviate(args) { - return abbreviateNumber(args.NUM); - } - unabbriviate(args) { - return unAbbreviateNumber(args.NUM); - } - addabbriviated(args) { - return addAbbreviated(args.NUM1, args.NUM2); - } - subabbriviated(args) { - return subtractAbbreviated(args.NUM1, args.NUM2); - } - multiabbriviated(args) { - return multiplyAbbreviated(args.NUM1, args.NUM2); - } - divabbriviated(args) { - return divideAbbreviated(args.NUM1, args.NUM2); - } - equalabbriviated(args) { - if (compareAbbreviated(args.NUM1, args.NUM2) === 0) { - return true; - } else { - return false; - } - } - moreabbriviated(args) { - if (compareAbbreviated(args.NUM1, args.NUM2) === 1) { - return true; - } else { - return false; - } - } - lessabbriviated(args) { - if (compareAbbreviated(args.NUM1, args.NUM2) === -1) { - return true; - } else { - return false; - } - } - } - - function abbreviateNumber(number) { - const suffixes = [ - "", - "K", - "M", - "B", - "T", - "Q", - "Qi", - "Sx", - "Sp", - "Oc", - "Nn", - "Dc", - "Ud", - "Dd", - "Td", - "Qd", - "Qid", - "Sxd", - "Spd", - "Ocd", - "Nnd", - "Vg", - "Uvg", - "Dvg", - "Tvg", - "Qvg", - "Qivg", - "Sxvg", - "Spvg", - "Ocvg", - "Nnvg", - "Ce", - ]; - - if (Math.abs(number) < 1000) return number.toString(); - - const suffixIndex = Math.floor(Math.log10(Math.abs(number)) / 3); - if (suffixIndex >= suffixes.length) { - return number.toExponential(1); - } - - const abbreviatedNumber = (number / Math.pow(1000, suffixIndex)).toFixed(1); - return `${abbreviatedNumber}${suffixes[suffixIndex]}`; - } - - function unAbbreviateNumber(abbreviated) { - const suffixes = { - K: 1e3, - M: 1e6, - B: 1e9, - T: 1e12, - Q: 1e15, - QI: 1e18, - SX: 1e21, - SP: 1e24, - OC: 1e27, - NN: 1e30, - DC: 1e33, - UD: 1e36, - DD: 1e39, - TD: 1e42, - QD: 1e45, - QID: 1e48, - SXD: 1e51, - SPD: 1e54, - OCD: 1e57, - NND: 1e60, - VG: 1e63, - UVG: 1e66, - DVG: 1e69, - TVG: 1e72, - QVG: 1e75, - QIVG: 1e78, - SXVG: 1e81, - SPVG: 1e84, - OCVG: 1e87, - NNVG: 1e90, - CE: 1e303, - }; - - const regex = /^(-?\d+(\.\d+)?)([a-zA-Z]*)$/; - const match = abbreviated.match(regex); - - if (!match) return NaN; - - const numberPart = parseFloat(match[1]); - const suffix = match[3].toUpperCase(); - - if (!suffix) return numberPart; - - const multiplier = suffixes[suffix]; - if (!multiplier) return NaN; - - return numberPart * multiplier; - } - - function addAbbreviated(a, b) { - const num1 = unAbbreviateNumber(a); - const num2 = unAbbreviateNumber(b); - if (isNaN(num1) || isNaN(num2)) return NaN; - - const sum = num1 + num2; - return abbreviateNumber(sum); - } - - function subtractAbbreviated(a, b) { - const num1 = unAbbreviateNumber(a); - const num2 = unAbbreviateNumber(b); - if (isNaN(num1) || isNaN(num2)) return NaN; - - const difference = num1 - num2; - return abbreviateNumber(difference); - } - - function multiplyAbbreviated(a, b) { - const num1 = unAbbreviateNumber(a); - const num2 = unAbbreviateNumber(b); - if (isNaN(num1) || isNaN(num2)) return NaN; - - const product = num1 * num2; - return abbreviateNumber(product); - } - - function divideAbbreviated(a, b) { - const num1 = unAbbreviateNumber(a); - const num2 = unAbbreviateNumber(b); - if (isNaN(num1) || isNaN(num2) || num2 === 0) return NaN; - - const quotient = num1 / num2; - return abbreviateNumber(quotient); - } - - function compareAbbreviated(a, b) { - const num1 = unAbbreviateNumber(a); - const num2 = unAbbreviateNumber(b); - if (isNaN(num1) || isNaN(num2)) return NaN; - - if (num1 > num2) return 1; - if (num1 < num2) return -1; - return 0; - } - - Scratch.extensions.register(new Abbreviation()); -})(Scratch); From 0e29c7dcc35a9ae5a34dc7dc18efb494d9ff2abb Mon Sep 17 00:00:00 2001 From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com> Date: Tue, 19 Nov 2024 11:39:49 +0000 Subject: [PATCH 03/10] Delete static/extensions/Cool_skratcher/noise.js --- static/extensions/Cool_skratcher/noise.js | 185 ---------------------- 1 file changed, 185 deletions(-) delete mode 100644 static/extensions/Cool_skratcher/noise.js diff --git a/static/extensions/Cool_skratcher/noise.js b/static/extensions/Cool_skratcher/noise.js deleted file mode 100644 index 7e2846e1..00000000 --- a/static/extensions/Cool_skratcher/noise.js +++ /dev/null @@ -1,185 +0,0 @@ -(function(Scratch) { - 'use strict'; - - // Perlin Noise algorithm from Noise.js - const Perlin = { - perm: new Array(512), - gradP: new Array(512), - grad3: [ - [1, 1, 0], [-1, 1, 0], [1, -1, 0], [-1, -1, 0], - [1, 0, 1], [-1, 0, 1], [1, 0, -1], [-1, 0, -1], - [0, 1, 1], [0, -1, 1], [0, 1, -1], [0, -1, -1] - ], - seed(seed) { - let p = []; - for (let i = 0; i < 256; i++) { - p[i] = i; - } - let n, q; - for (let i = 255; i > 0; i--) { - n = Math.floor(seed * (i + 1)) % 256; - q = p[i]; - p[i] = p[n]; - p[n] = q; - } - for (let i = 0; i < 512; i++) { - this.perm[i] = p[i & 255]; - this.gradP[i] = this.grad3[this.perm[i] % 12]; - } - }, - fade(t) { - return t * t * t * (t * (t * 6 - 15) + 10); - }, - lerp(t, a, b) { - return a + t * (b - a); - }, - dot(g, x, y) { - return g[0] * x + g[1] * y; - }, - noise(x, y) { - const X = Math.floor(x) & 255; - const Y = Math.floor(y) & 255; - x = x - Math.floor(x); - y = y - Math.floor(y); - - const u = this.fade(x); - const v = this.fade(y); - - const grad00 = this.gradP[X + this.perm[Y]]; - const grad01 = this.gradP[X + this.perm[Y + 1]]; - const grad10 = this.gradP[X + 1 + this.perm[Y]]; - const grad11 = this.gradP[X + 1 + this.perm[Y + 1]]; - - const n00 = this.dot(grad00, x, y); - const n10 = this.dot(grad10, x - 1, y); - const n01 = this.dot(grad01, x, y - 1); - const n11 = this.dot(grad11, x - 1, y - 1); - - const nx0 = this.lerp(u, n00, n10); - const nx1 = this.lerp(u, n01, n11); - - return this.lerp(v, nx0, nx1); - } - }; - - class PerlinNoiseExtension { - constructor() { - this.noiseMap = {}; - } - - // Pre-generate Perlin noise based on seed and store it - generateNoise(seed, octaves) { - Perlin.seed(seed); - this.noiseMap[seed] = { octaves }; - } - - // Get pre-generated noise at X, Y - getNoiseAt({ seed, x, y }) { - const noiseData = this.noiseMap[seed]; - if (!noiseData) { - return 0; // Return 0 if noise is not pre-generated - } - - const { octaves } = noiseData; - let total = 0; - let frequency = 1; - let amplitude = 1; - let maxValue = 0; - - for (let i = 0; i < octaves; i++) { - total += Perlin.noise(x * frequency, y * frequency) * amplitude; - maxValue += amplitude; - amplitude /= 2; - frequency *= 2; - } - - return total / maxValue; // Normalize the result - } - - // Get Perlin noise directly without pre-generation - getDirectNoise({ seed, x, y, octaves }) { - Perlin.seed(seed); - let total = 0; - let frequency = 1; - let amplitude = 1; - let maxValue = 0; - - for (let i = 0; i < octaves; i++) { - total += Perlin.noise(x * frequency, y * frequency) * amplitude; - maxValue += amplitude; - amplitude /= 2; - frequency *= 2; - } - - return total / maxValue; // Normalize the result - } - - getInfo() { - return { - id: 'perlinNoise', - name: 'Perlin Noise', - blocks: [ - { - opcode: 'generateNoise', - blockType: Scratch.BlockType.COMMAND, - text: 'pre-generate perlin noise Seed: [SEED] Octave: [OCTAVE]', - arguments: { - SEED: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1234, - }, - OCTAVE: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 4, - }, - }, - }, - { - opcode: 'getNoiseAt', - blockType: Scratch.BlockType.REPORTER, - text: 'get pre-generated perlin noise Seed: [SEED] at X: [X] Y: [Y]', - arguments: { - SEED: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1234, - }, - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - }, - }, - { - opcode: 'getDirectNoise', - blockType: Scratch.BlockType.REPORTER, - text: 'get direct perlin noise Seed: [SEED] X: [X] Y: [Y] Octave: [OCTAVE]', - arguments: { - SEED: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1234, - }, - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - OCTAVE: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 4, - }, - }, - } - ], - }; - } - } - - Scratch.extensions.register(new PerlinNoiseExtension()); -})(Scratch); \ No newline at end of file From 57487db43b297de247cc40c77b11d9854a76b58d Mon Sep 17 00:00:00 2001 From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com> Date: Tue, 19 Nov 2024 11:40:36 +0000 Subject: [PATCH 04/10] Add files via upload --- static/images/Cool_skratcher/vectors.svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 static/images/Cool_skratcher/vectors.svg diff --git a/static/images/Cool_skratcher/vectors.svg b/static/images/Cool_skratcher/vectors.svg new file mode 100644 index 00000000..bc388ede --- /dev/null +++ b/static/images/Cool_skratcher/vectors.svg @@ -0,0 +1 @@ + \ No newline at end of file From f907dc0699cde4310b3f7b17884e7db103574b84 Mon Sep 17 00:00:00 2001 From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com> Date: Tue, 19 Nov 2024 11:42:45 +0000 Subject: [PATCH 05/10] Update vectors.js --- static/extensions/Cool_skratcher/vectors.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/extensions/Cool_skratcher/vectors.js b/static/extensions/Cool_skratcher/vectors.js index 230d3362..e039a53d 100644 --- a/static/extensions/Cool_skratcher/vectors.js +++ b/static/extensions/Cool_skratcher/vectors.js @@ -1,5 +1,5 @@ // Name: Vectors! -// ID: vectors +// ID: vectorscoolskratcher // Description: Adds a set of blocks for vector operations in 2D and 3D space. // By: cool_skratcher // License: MIT @@ -14,7 +14,7 @@ getInfo() { return { - id: 'vectors', + id: 'vectorscoolskratcher', name: 'Vectors', color1: "#57a3e5", color2: "#0063ba", From 835c2c44476ba5d78217193443020e33d29c7353 Mon Sep 17 00:00:00 2001 From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com> Date: Tue, 19 Nov 2024 14:05:28 +0000 Subject: [PATCH 06/10] Update vectors.js --- static/extensions/Cool_skratcher/vectors.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/static/extensions/Cool_skratcher/vectors.js b/static/extensions/Cool_skratcher/vectors.js index e039a53d..b460032c 100644 --- a/static/extensions/Cool_skratcher/vectors.js +++ b/static/extensions/Cool_skratcher/vectors.js @@ -1,5 +1,5 @@ // Name: Vectors! -// ID: vectorscoolskratcher +// ID: vectors // Description: Adds a set of blocks for vector operations in 2D and 3D space. // By: cool_skratcher // License: MIT @@ -7,14 +7,14 @@ (function(Scratch) { 'use strict'; - class VecMath3D { + class VecMath { constructor() { this.camera = { pos: { x: 0, y: 0, z: 0 }, rot: { yaw: 0, pitch: 0, roll: 0 }, fov: 100 }; } getInfo() { return { - id: 'vectorscoolskratcher', + id: 'vectors', name: 'Vectors', color1: "#57a3e5", color2: "#0063ba", @@ -98,7 +98,7 @@ rotateVec3(args) { const [x, y, z] = args.v.split(',').map(Number); - return this._rotate3D({ x, y, z }, args.rx, args.ry, args.rz); + return this._rotate3D({ x, y, z }, this._toRadians(args.rx), this._toRadians(args.ry), this._toRadians(args.rz)); } // Camera Controls @@ -145,9 +145,9 @@ rotateAroundOrigin(args) { const [vx, vy, vz] = args.v.split(',').map(Number); const [ox, oy, oz] = args.origin.split(',').map(Number); - const rx = (Math.PI / 180) * args.rx; - const ry = (Math.PI / 180) * args.ry; - const rz = (Math.PI / 180) * args.rz; + const rx = this._toRadians(args.rx); + const ry = this._toRadians(args.ry); + const rz = this._toRadians(args.rz); // Translate vector to origin let x = vx - ox; @@ -299,7 +299,12 @@ const bounds = Scratch.vm.renderer.getBounds(util.target.drawableID) return `${Math.ceil(bounds.width)},${Math.ceil(bounds.height)}`; } + + // New utility function to convert degrees to radians + _toRadians(degrees) { + return degrees * (Math.PI / 180); + } } - Scratch.extensions.register(new VecMath3D()); + Scratch.extensions.register(new VecMath()); })(Scratch); From 32934a8b65bccd287f6351fb95fdf3980543dd63 Mon Sep 17 00:00:00 2001 From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com> Date: Wed, 20 Nov 2024 09:17:38 +0000 Subject: [PATCH 07/10] Update vectors.js added pen+ to draw triangles with vectors and fixed some bugs --- static/extensions/Cool_skratcher/vectors.js | 78 ++++++++++++++++++--- 1 file changed, 67 insertions(+), 11 deletions(-) diff --git a/static/extensions/Cool_skratcher/vectors.js b/static/extensions/Cool_skratcher/vectors.js index b460032c..710ba8d8 100644 --- a/static/extensions/Cool_skratcher/vectors.js +++ b/static/extensions/Cool_skratcher/vectors.js @@ -6,6 +6,30 @@ (function(Scratch) { 'use strict'; + const vm = Scratch.vm; + + let penPLoaded = false; + let penPModule = null; + const penPCheck = () => { + if (penPLoaded) { + return; + } // Return if pen+ integration is loaded + if (vm.runtime.ext_penP) { + penPLoaded = true; + } + penPModule = vm.runtime.ext_penP; + + if (penPModule) { + penPModule.turnAdvancedSettingOff({ + Setting: "wValueUnderFlow", + onOrOff: "on", + }); + } + + vm.runtime.extensionManager.refreshBlocks(); + }; + penPCheck(); + vm.runtime.on("EXTENSION_ADDED", penPCheck); class VecMath { constructor() { @@ -61,6 +85,9 @@ { opcode: 'goToVec2', blockType: Scratch.BlockType.COMMAND, text: 'go to vec2 [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }}}, { opcode: 'getPosVec2', blockType: Scratch.BlockType.REPORTER, text: 'get position as vec2' }, { opcode: 'getSizeVec2', blockType: Scratch.BlockType.REPORTER, text: 'get size as vec2' }, + "---", + { hideFromPalette: !penPLoaded, text: 'Pen+', blockType: Scratch.BlockType.LABEL }, + { hideFromPalette: !penPLoaded, opcode: 'drawTriangle', blockType: Scratch.BlockType.COMMAND, text: 'triangle between [v1] [v2] [v3]', arguments: { v1: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }, v2: { type: Scratch.ArgumentType.STRING, defaultValue: '1,0' }, v3: { type: Scratch.ArgumentType.STRING, defaultValue: '0,1' }}}, ], menus: { components: { items: ['x', 'y', 'z'] }, @@ -122,19 +149,19 @@ const cam = this.camera; const dx = x - cam.pos.x, dy = y - cam.pos.y, dz = z - cam.pos.z; - // Apply yaw rotation - const camZ = dz * Math.cos(cam.rot.yaw) + dx * Math.sin(cam.rot.yaw); - const camX = dx * Math.cos(cam.rot.yaw) - dz * Math.sin(cam.rot.yaw); + // Apply yaw rotation (now in degrees) + const camZ = dz * Math.cos(this._toRadians(cam.rot.yaw)) + dx * Math.sin(this._toRadians(cam.rot.yaw)); + const camX = dx * Math.cos(this._toRadians(cam.rot.yaw)) - dz * Math.sin(this._toRadians(cam.rot.yaw)); - // Apply pitch rotation - const tempY = dy * Math.cos(cam.rot.pitch) - camZ * Math.sin(cam.rot.pitch); - const tempZ = dy * Math.sin(cam.rot.pitch) + camZ * Math.cos(cam.rot.pitch); + // Apply pitch rotation (now in degrees) + const tempY = dy * Math.cos(this._toRadians(cam.rot.pitch)) - camZ * Math.sin(this._toRadians(cam.rot.pitch)); + const tempZ = dy * Math.sin(this._toRadians(cam.rot.pitch)) + camZ * Math.cos(this._toRadians(cam.rot.pitch)); const finalZ = tempZ; // This is now the new Z after pitch rotation const finalY = tempY; // This is now the new Y after pitch rotation - // Apply roll rotation - const finalX = finalY * Math.sin(cam.rot.roll) + camX * Math.cos(cam.rot.roll); - const adjustedY = finalY * Math.cos(cam.rot.roll) - camX * Math.sin(cam.rot.roll); + // Apply roll rotation (now in degrees) + const finalX = finalY * Math.sin(this._toRadians(cam.rot.roll)) + camX * Math.cos(this._toRadians(cam.rot.roll)); + const adjustedY = finalY * Math.cos(this._toRadians(cam.rot.roll)) - camX * Math.sin(this._toRadians(cam.rot.roll)); // Calculate screen coordinates const screenX = (finalX / finalZ) * cam.fov; @@ -265,8 +292,19 @@ _setVec(target, v) { const [x, y, z] = v.split(',').map(Number); target.x = x; target.y = y; target.z = z; } _addVec(target, v) { const [x, y, z] = v.split(',').map(Number); target.x += x; target.y += y; target.z += z; } - _setRot(target, v) { const [x, y, z] = v.split(',').map(Number); target.yaw = x; target.pitch = y; target.roll = z; } - _addRot(target, v) { const [x, y, z] = v.split(',').map(Number); target.yaw += x; target.pitch += y; target.roll += z; } + _setRot(target, v) { + const [yaw, pitch, roll] = v.split(',').map(Number); + target.yaw = yaw; + target.pitch = pitch; + target.roll = roll; + } + + _addRot(target, v) { + const [yaw, pitch, roll] = v.split(',').map(Number); + target.yaw += yaw; + target.pitch += pitch; + target.roll += roll; + } _rotate3D(v, rx, ry, rz) { const cos = Math.cos, sin = Math.sin; @@ -300,6 +338,24 @@ return `${Math.ceil(bounds.width)},${Math.ceil(bounds.height)}`; } + drawTriangle(args, util) { + const [x1, y1] = args.v1.split(',').map(Number); + const [x2, y2] = args.v2.split(',').map(Number); + const [x3, y3] = args.v3.split(',').map(Number); + + penPModule.drawSolidTri( + { + x1: x1, + y1: y1, + x2: x2, + y2: y2, + x3: x3, + y3: y3, + }, + util + ); + } + // New utility function to convert degrees to radians _toRadians(degrees) { return degrees * (Math.PI / 180); From f0c2788e4976867da741f03b94772a35d6aba4f1 Mon Sep 17 00:00:00 2001 From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com> Date: Wed, 20 Nov 2024 12:20:37 +0000 Subject: [PATCH 08/10] Update vectors.js added some more sprite move blocks fixed frustum culling and added better error handeling --- static/extensions/Cool_skratcher/vectors.js | 252 ++++++++++++++------ 1 file changed, 180 insertions(+), 72 deletions(-) diff --git a/static/extensions/Cool_skratcher/vectors.js b/static/extensions/Cool_skratcher/vectors.js index 710ba8d8..2db9f524 100644 --- a/static/extensions/Cool_skratcher/vectors.js +++ b/static/extensions/Cool_skratcher/vectors.js @@ -7,26 +7,27 @@ (function(Scratch) { 'use strict'; const vm = Scratch.vm; + const mouse = vm.runtime.ioDevices.mouse; let penPLoaded = false; let penPModule = null; const penPCheck = () => { if (penPLoaded) { return; - } // Return if pen+ integration is loaded + } if (vm.runtime.ext_penP) { penPLoaded = true; - } - penPModule = vm.runtime.ext_penP; + penPModule = vm.runtime.ext_penP; - if (penPModule) { - penPModule.turnAdvancedSettingOff({ - Setting: "wValueUnderFlow", - onOrOff: "on", - }); - } + if (penPModule) { + penPModule.turnAdvancedSettingOff({ + Setting: "wValueUnderFlow", + onOrOff: "on", + }); + } - vm.runtime.extensionManager.refreshBlocks(); + vm.runtime.extensionManager.refreshBlocks(); + } }; penPCheck(); vm.runtime.on("EXTENSION_ADDED", penPCheck); @@ -83,8 +84,10 @@ { text: 'Sprite Movement', blockType: Scratch.BlockType.LABEL }, { opcode: 'moveByVec2', blockType: Scratch.BlockType.COMMAND, text: 'change pos by vec2 [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }}}, { opcode: 'goToVec2', blockType: Scratch.BlockType.COMMAND, text: 'go to vec2 [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }}}, + { opcode: 'pointTo', blockType: Scratch.BlockType.COMMAND, text: 'point to vec2 [v]', arguments: { v: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }}}, { opcode: 'getPosVec2', blockType: Scratch.BlockType.REPORTER, text: 'get position as vec2' }, { opcode: 'getSizeVec2', blockType: Scratch.BlockType.REPORTER, text: 'get size as vec2' }, + { opcode: 'getMousePosVec2', blockType: Scratch.BlockType.REPORTER, text: 'mouse pos vec2' }, "---", { hideFromPalette: !penPLoaded, text: 'Pen+', blockType: Scratch.BlockType.LABEL }, { hideFromPalette: !penPLoaded, opcode: 'drawTriangle', blockType: Scratch.BlockType.COMMAND, text: 'triangle between [v1] [v2] [v3]', arguments: { v1: { type: Scratch.ArgumentType.STRING, defaultValue: '0,0' }, v2: { type: Scratch.ArgumentType.STRING, defaultValue: '1,0' }, v3: { type: Scratch.ArgumentType.STRING, defaultValue: '0,1' }}}, @@ -97,8 +100,18 @@ } // Vector creation - vec2(args) { return `${args.x},${args.y},0`; } - vec3(args) { return `${args.x},${args.y},${args.z}`; } + vec2(args) { + const x = Scratch.Cast.toNumber(args.x) || 0; + const y = Scratch.Cast.toNumber(args.y) || 0; + return `${x},${y}`; + } + + vec3(args) { + const x = Scratch.Cast.toNumber(args.x) || 0; + const y = Scratch.Cast.toNumber(args.y) || 0; + const z = Scratch.Cast.toNumber(args.z) || 0; + return `${x},${y},${z}`; + } // Vector component access getComponent(args) { @@ -107,25 +120,54 @@ } // Basic vector math - add(args) { return this._vectorOp(args.v1, args.v2, (a, b) => a + b); } - sub(args) { return this._vectorOp(args.v1, args.v2, (a, b) => a - b); } - mul(args) { return this._scalarOp(args.v, args.scalar, (a, b) => a * b); } - div(args) { return this._scalarOp(args.v, args.scalar, (a, b) => a / b); } - mag(args) { return Math.hypot(...args.v.split(',').map(Number)); } + add(args) { + return this._vectorOp(args.v1, args.v2, (a, b) => (a || 0) + (b || 0)); + } + + sub(args) { + return this._vectorOp(args.v1, args.v2, (a, b) => (a || 0) - (b || 0)); + } + + mul(args) { + const scalar = Scratch.Cast.toNumber(args.scalar) || 0; + return this._scalarOp(args.v, scalar, (a, b) => (a || 0) * b); + } + + div(args) { + const scalar = Scratch.Cast.toNumber(args.scalar) || 1; + return this._scalarOp(args.v, scalar, (a, b) => b !== 0 ? (a || 0) / b : 0); + } + + mag(args) { + const components = args.v.split(',').map(n => Scratch.Cast.toNumber(n) || 0); + return Math.hypot(...components); + } + + // Fixed dot product with validation dot(args) { - const [x1, y1, z1] = args.v1.split(',').map(Number); - const [x2, y2, z2] = args.v2.split(',').map(Number); + const v1 = args.v1.split(',').map(n => Scratch.Cast.toNumber(n) || 0); + const v2 = args.v2.split(',').map(n => Scratch.Cast.toNumber(n) || 0); + const [x1 = 0, y1 = 0, z1 = 0] = v1; + const [x2 = 0, y2 = 0, z2 = 0] = v2; return x1 * x2 + y1 * y2 + z1 * z2; } + + // Improved cross product cross(args) { - const [x1, y1, z1] = args.v1.split(',').map(Number); - const [x2, y2, z2] = args.v2.split(',').map(Number); + const v1 = args.v1.split(',').map(n => Scratch.Cast.toNumber(n) || 0); + const v2 = args.v2.split(',').map(n => Scratch.Cast.toNumber(n) || 0); + const [x1 = 0, y1 = 0, z1 = 0] = v1; + const [x2 = 0, y2 = 0, z2 = 0] = v2; return `${y1 * z2 - z1 * y2},${z1 * x2 - x1 * z2},${x1 * y2 - y1 * x2}`; } + // Fixed rotation functions rotateVec3(args) { - const [x, y, z] = args.v.split(',').map(Number); - return this._rotate3D({ x, y, z }, this._toRadians(args.rx), this._toRadians(args.ry), this._toRadians(args.rz)); + const [x = 0, y = 0, z = 0] = args.v.split(',').map(n => Scratch.Cast.toNumber(n) || 0); + const rx = this._toRadians(Scratch.Cast.toNumber(args.rx) || 0); + const ry = this._toRadians(Scratch.Cast.toNumber(args.ry) || 0); + const rz = this._toRadians(Scratch.Cast.toNumber(args.rz) || 0); + return this._rotate3D({ x, y, z }, rx, ry, rz); } // Camera Controls @@ -145,27 +187,43 @@ // Projection project(args) { - const [x, y, z] = args.v.split(',').map(Number); + const [x = 0, y = 0, z = 0] = args.v.split(',').map(n => Scratch.Cast.toNumber(n) || 0); const cam = this.camera; - const dx = x - cam.pos.x, dy = y - cam.pos.y, dz = z - cam.pos.z; - - // Apply yaw rotation (now in degrees) - const camZ = dz * Math.cos(this._toRadians(cam.rot.yaw)) + dx * Math.sin(this._toRadians(cam.rot.yaw)); - const camX = dx * Math.cos(this._toRadians(cam.rot.yaw)) - dz * Math.sin(this._toRadians(cam.rot.yaw)); - - // Apply pitch rotation (now in degrees) - const tempY = dy * Math.cos(this._toRadians(cam.rot.pitch)) - camZ * Math.sin(this._toRadians(cam.rot.pitch)); - const tempZ = dy * Math.sin(this._toRadians(cam.rot.pitch)) + camZ * Math.cos(this._toRadians(cam.rot.pitch)); - const finalZ = tempZ; // This is now the new Z after pitch rotation - const finalY = tempY; // This is now the new Y after pitch rotation - - // Apply roll rotation (now in degrees) - const finalX = finalY * Math.sin(this._toRadians(cam.rot.roll)) + camX * Math.cos(this._toRadians(cam.rot.roll)); - const adjustedY = finalY * Math.cos(this._toRadians(cam.rot.roll)) - camX * Math.sin(this._toRadians(cam.rot.roll)); + + // Apply transformations in correct order + const dx = x - cam.pos.x; + const dy = y - cam.pos.y; + const dz = z - cam.pos.z; + + // Convert angles to radians for consistency + const yawRad = this._toRadians(cam.rot.yaw); + const pitchRad = this._toRadians(cam.rot.pitch); + const rollRad = this._toRadians(cam.rot.roll); + + // Apply rotations in correct order: yaw -> pitch -> roll + // First yaw (around Y axis) + let cx = dx * Math.cos(yawRad) - dz * Math.sin(yawRad); + let cz = dx * Math.sin(yawRad) + dz * Math.cos(yawRad); + let cy = dy; + + // Then pitch (around X axis) + const tempZ = cz * Math.cos(pitchRad) - cy * Math.sin(pitchRad); + cy = cz * Math.sin(pitchRad) + cy * Math.cos(pitchRad); + cz = tempZ; + + // Finally roll (around Z axis) + const finalX = cx * Math.cos(rollRad) - cy * Math.sin(rollRad); + const finalY = cx * Math.sin(rollRad) + cy * Math.cos(rollRad); + + // Prevent division by zero + if (Math.abs(cz) < 0.0001) { + return '0,0'; + } + + // Calculate screen coordinates with FOV + const screenX = (finalX / cz) * cam.fov; + const screenY = (finalY / cz) * cam.fov; - // Calculate screen coordinates - const screenX = (finalX / finalZ) * cam.fov; - const screenY = (adjustedY / finalZ) * cam.fov; return `${screenX},${screenY}`; } @@ -228,32 +286,45 @@ } frustumCull(args) { - const [x, y, z] = args.v.split(',').map(Number); + const [x = 0, y = 0, z = 0] = args.v.split(',').map(n => Scratch.Cast.toNumber(n) || 0); const { pos, rot, fov } = this.camera; - const near = args.near, far = args.far; - - // Translate point relative to camera + const near = Math.max(0.1, Scratch.Cast.toNumber(args.near) || 0.1); + const far = Math.max(near + 0.1, Scratch.Cast.toNumber(args.far) || 100); + + // Transform point to camera space const dx = x - pos.x; const dy = y - pos.y; const dz = z - pos.z; - - // Rotate point relative to camera - const cx = dx * Math.cos(rot.yaw) - dz * Math.sin(rot.yaw); - const cz = dx * Math.sin(rot.yaw) + dz * Math.cos(rot.yaw); - const cy = dy; - - // Check depth (near and far planes) + + // Convert angles to radians + const yawRad = this._toRadians(rot.yaw); + const pitchRad = this._toRadians(rot.pitch); + + // Apply rotations (yaw then pitch) + let cx = dx * Math.cos(yawRad) - dz * Math.sin(yawRad); + let cz = dx * Math.sin(yawRad) + dz * Math.cos(yawRad); + let cy = dy; + + // Apply pitch + const temp_z = cz * Math.cos(pitchRad) - cy * Math.sin(pitchRad); + cy = cz * Math.sin(pitchRad) + cy * Math.cos(pitchRad); + cz = temp_z; + + // Early exit if behind camera + if (cz <= 0) return true; + + // Check against near/far planes if (cz < near || cz > far) return true; - - // Check horizontal FOV - const hHalf = Math.tan((fov / 2) * (Math.PI / 180)) * cz; - if (cx < -hHalf || cx > hHalf) return true; - - // Check vertical FOV - const vHalf = hHalf * (3 / 4); // Assuming aspect ratio of 4:3 - if (cy < -vHalf || cy > vHalf) return true; - - return false; + + // Calculate FOV bounds with correct aspect ratio (4:3) + const hFovRad = this._toRadians(fov); + const vFovRad = 2 * Math.atan(Math.tan(hFovRad / 2) * (3/4)); + + // Check against frustum planes + const hHalf = Math.abs(Math.tan(hFovRad / 2) * cz); + const vHalf = Math.abs(Math.tan(vFovRad / 2) * cz); + + return Math.abs(cx) > hHalf || Math.abs(cy) > vHalf; } backFaceCull(args) { @@ -280,8 +351,10 @@ // Utility Functions _vectorOp(v1, v2, op) { - const [x1, y1, z1] = v1.split(',').map(Number); - const [x2, y2, z2] = v2.split(',').map(Number); + const vec1 = v1.split(',').map(n => Scratch.Cast.toNumber(n) || 0); + const vec2 = v2.split(',').map(n => Scratch.Cast.toNumber(n) || 0); + const [x1 = 0, y1 = 0, z1 = 0] = vec1; + const [x2 = 0, y2 = 0, z2 = 0] = vec2; return `${op(x1, x2)},${op(y1, y2)},${op(z1, z2)}`; } @@ -307,11 +380,26 @@ } _rotate3D(v, rx, ry, rz) { - const cos = Math.cos, sin = Math.sin; + const cos = Math.cos; + const sin = Math.sin; let { x, y, z } = v; - [y, z] = [y * cos(rx) - z * sin(rx), y * sin(rx) + z * cos(rx)]; - [x, z] = [x * cos(ry) + z * sin(ry), -x * sin(ry) + z * cos(ry)]; - [x, y] = [x * cos(rz) - y * sin(rz), x * sin(rz) + y * cos(rz)]; + + // Apply rotations in order: X -> Y -> Z + // X rotation + let temp = y; + y = y * cos(rx) - z * sin(rx); + z = temp * sin(rx) + z * cos(rx); + + // Y rotation + temp = x; + x = x * cos(ry) + z * sin(ry); + z = -temp * sin(ry) + z * cos(ry); + + // Z rotation + temp = x; + x = x * cos(rz) - y * sin(rz); + y = temp * sin(rz) + y * cos(rz); + return `${x},${y},${z}`; } @@ -322,6 +410,23 @@ util.target.setXY(util.target.x + x, util.target.y + y); } + pointTo(args, util) { + const [dx, dy] = args.v.split(',').map(Number); + const x = Scratch.Cast.toNumber(dx); + const y = Scratch.Cast.toNumber(dy); + if (util.target.y > y) { + util.target.setDirection( + (180 / Math.PI) * + Math.atan((x - util.target.x) / (y - util.target.y)) + + 180 + ); + } else { + util.target.setDirection( + (180 / Math.PI) * Math.atan((x - util.target.x) / (y - util.target.y)) + ); + } + } + goToVec2(args, util) { const [dx, dy] = args.v.split(',').map(Number); const x = Scratch.Cast.toNumber(dx); @@ -329,14 +434,17 @@ util.target.setXY(x, y); } - getPosVec2(args, util) { + getPosVec2(util) { return `${util.target.x},${util.target.y}`; } - getSizeVec2(args, util) { + getSizeVec2(util) { const bounds = Scratch.vm.renderer.getBounds(util.target.drawableID) return `${Math.ceil(bounds.width)},${Math.ceil(bounds.height)}`; } + getMousePosVec2() { + return `${Math.round(mouse._scratchX)},${Math.round(mouse._scratchY)}`; + } drawTriangle(args, util) { const [x1, y1] = args.v1.split(',').map(Number); @@ -358,7 +466,7 @@ // New utility function to convert degrees to radians _toRadians(degrees) { - return degrees * (Math.PI / 180); + return (degrees || 0) * (Math.PI / 180); } } From de3ac697d3f21b711abd9759ae3d7c97b0ab7c6f Mon Sep 17 00:00:00 2001 From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com> Date: Wed, 20 Nov 2024 15:57:28 +0000 Subject: [PATCH 09/10] Update vectors.js --- static/extensions/Cool_skratcher/vectors.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/static/extensions/Cool_skratcher/vectors.js b/static/extensions/Cool_skratcher/vectors.js index 2db9f524..a6d4ab2c 100644 --- a/static/extensions/Cool_skratcher/vectors.js +++ b/static/extensions/Cool_skratcher/vectors.js @@ -1,5 +1,5 @@ // Name: Vectors! -// ID: vectors +// ID: cooldevvectors // Description: Adds a set of blocks for vector operations in 2D and 3D space. // By: cool_skratcher // License: MIT @@ -30,16 +30,19 @@ } }; penPCheck(); - vm.runtime.on("EXTENSION_ADDED", penPCheck); class VecMath { constructor() { this.camera = { pos: { x: 0, y: 0, z: 0 }, rot: { yaw: 0, pitch: 0, roll: 0 }, fov: 100 }; + Scratch.vm.runtime.on("EXTENSION_ADDED", () => { + penPCheck(); + console.log(vm.runtime.ext_penP) + }); } getInfo() { return { - id: 'vectors', + id: 'cooldevvectors', name: 'Vectors', color1: "#57a3e5", color2: "#0063ba", From 495214b31eb447b81cb83342dc846d43ebf92274 Mon Sep 17 00:00:00 2001 From: CoolDevXD <84728499+CoolDevXD@users.noreply.github.com> Date: Wed, 20 Nov 2024 17:45:20 +0000 Subject: [PATCH 10/10] Update extensions.js --- src/lib/extensions.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/extensions.js b/src/lib/extensions.js index 09657d34..ee15a425 100644 --- a/src/lib/extensions.js +++ b/src/lib/extensions.js @@ -13,6 +13,14 @@ export default [ creator: "MikeDev101", isGitHub: true, }, + { + name: "Vectors", + description: "Adds a set of blocks for vector operations in 2D and 3D space.", + code: "Cool_skratcher/vectors.js", + banner: "Cool_skratcher/vectors.svg", + creator: "cool_dev", + isGitHub: true, + }, { name: "Pen+", description: "Extended pen section! Adds blocks for drawing triangles using textures and tints, drawing images and editing their pixels, etc.",