Vector2打造一个跟随鼠标移动的深海奇异生物效果代码
代码语言:html
所属分类:动画
代码描述:Vector2打造一个跟随鼠标移动的深海奇异生物效果代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <link type="text/css" rel="stylesheet" href="//repo.bfw.wiki/bfwrepo/css/reset.min.css"> <style> body { background: black; } .canvas { mix-blend-mode: screen; } .canvas, .background, .overlay { position: absolute; width: 100vw; height: 100vh; } </style> </head> <body > <canvas class="background"></canvas> <canvas class="canvas"></canvas> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/Vector2.min.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/perlin-min.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/dat.gui-min.js"></script> <script > "use strict"; const { abs, acos, asin, atan, atan2, ceil, cos, max, min, PI, pow, random, round, sin, sqrt, tan } = Math; const HALF_PI = 0.5 * PI; const QUART_PI = 0.25 * PI; const TAU = 2 * PI; const TO_RAD = PI / 180; const G = 6.67 * pow(10, -11); const EPSILON = 2.220446049250313e-16; const rand = n => n * random(); const randIn = (_min, _max) => rand(_max - _min) + _min; const randRange = n => n - rand(2 * n); const fadeIn = (t, m) => t / m; const fadeOut = (t, m) => (m - t) / m; const fadeInOut = (t, m) => { let hm = 0.5 * m; return abs((t + hm) % m - hm) / hm; }; const dist = (x1, y1, x2, y2) => sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2)); const angle = (x1, y1, x2, y2) => atan2(y2 - y1, x2 - x1); const lerp = (a, b, t) => (1 - t) * a + t * b; const clamp = (n, _min, _max) => min(max(n, _min), _max); const norm = (n, _min, _max) => (n - _min) / (_max - _min); const floor = n => n | 0; const fract = n => n - floor(n); const vh = p => p * window.innerHeight * 0.01; const vw = p => p * window.innerWidth * 0.01; const vmin = p => min(vh(p), vw(p)); const vmax = p => max(vh(p), vw(p)); const intToRGBA = n => { let r, g, b, a; n >>>= 0; r = (n & 0xff000000) >>> 24; g = (n & 0xff0000) >>> 16; b = (n & 0xff00) >>> 8; a = (n & 0xff) / 255; return `rgba(${[r, g, b, a].join()})`; }; const nearestMultiple = (n, d) => n - n % d; const drawTypes = { FILL: 'fill', STROKE: 'stroke' }; const textAlignTypes = { CENTER: 'center', END: 'end', LEFT: 'left', RIGHT: 'right', START: 'start' }; const textBaselineTypes = { ALPHABETIC: 'alphabetic', BOTTOM: 'bottom', HANGING: 'hanging', MIDDLE: 'middle', TOP: 'top' }; Array.prototype.lerp = function (t = [], a = 0) { this.forEach((n, i) => this[i] = lerp(n, t[i], a)); }; Float32Array.prototype.get = function (i = 0, n = 0) { const t = i + n; let r = []; for (; i < t; i++) { r.push(this[i]); } return r; }; class PropsArray { constructor(count = 0, props = [], type = 'float') { this.count = count; this.props = props; this.spread = props.length; this.values = type === 'float' ? new Float32Array(count * props.length) : new Uint32Array(count * props.length); } get length() { return this.values.length; } set(a = [], i = 0) { this.values.set(a, i); } setMap(o = {}, i = 0) { this.set(Object.values(o), i); } get(i = 0) { return this.values.get(i, this.spread); } getMap(i = 0) { return this.get(i).reduce( (r, v, i) => ({ ...r, ...{ [this.props[i]]: v } }), {}); } forEach(cb) { let i = 0; for (; i < this.length; i += this.spread) { cb(this.get(i), i, this); } } map(cb) { let i = 0; for (; i < this.length; i += this.spread) { this.set(cb(this.get(i), i, this), i); } } async *read() { let i = 0; for (; i < this.length; i += this.spread) { yield { index: i, value: this.get(i) }; } }} function createOffscreenCanvas(width, height) { let _canvas; if (typeof OffscreenCanvas !== undefined) { _canvas = new OffscreenCanvas(parseFloat(width), parseFloat(height)); } else { _canvas = createCanvas(width, height); } return _canvas; } function createCanvas(width, height) { const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; return canvas; } function createContext2D(width = innerWidth, height = innerHeight, contextAttributes) { return createCanvas(width, height).getContext('2d', contextAttributes); } function createOffscreenContext2D(width = innerWidth, height = innerHeight, contextAttributes) { return createOffscreenCanvas(width, height).getContext('2d', contextAttributes); } function createRenderingContext(width, height) { const contextAttributes = { desynchronized: true, willReadFrequently: true }; const ctx = createContext2D(width, height, contextAttributes); const buffer = createOffscreenContext2D(width, height, contextAttributes); ctx.canvas.style.position = 'absolute'; document.body.appendChild(ctx.canvas); return { buffer, ctx }; } let canvas, background, creature, mouse; let tick = 0; let opts = { animation: { breathe: true, spin: true, followMouse: true, type: "mobius", speed: 4 }, motion: { rigidity: parseFloat(rand(1).toFixed(1)), responsiveness: parseFloat(rand(1).toFixed(1)) }, color: { startHue: rand(360), glow: 0.4 }, structure: { baseRadius: round(rand(20)) + 20, armCount: round(rand(15)) + 15, segmentLength: 18, segmentMin: 6, segmentMax: 28, segmentNum: () => Math.round(Math.random() * (opts.structure.segmentMax - opts.structure.segmentMin) + opts.structure.segmentMin) }, noise: { enabled: true, strength: 0.5, type: "rough" }, reset: () => { noise.seed(Math.round(2000 * Math.random())); creature = new Creature(opts.structure.armCount); ctx.clearRect(0, 0, canvas.dimensions.x, canvas.dimensions.y); } }; class Mouse { constructor() { this.hover = false; this.position = new Vector2( 0.5 * window.innerWidth, 0.5 * window.innerHeight); this.animationTarget = new Vector2( this.position.x, this.position.y); this.animate = { random: () => { if (tick % 180 === 0) { this.animationTarget.x = Math.random() * canvas.dimensions.x; this.animationTarget.y = Math.random() * canvas.dimensions.y; } this.position.lerp(this.animationTarget, 0.35); }, mobius: () => { this.animationTarget.lerp({ x: 0.5 * canvas.dimensions.x + 0.35 * canvas.dimensions.x * -cos(tick * 0.0125), y: 0.5 * canvas.dimensions.y + 0.35 * canvas.dimensions.y * -sin(tick * 0.025) }, 0.85); this.position.lerp(this.animationTarget, 0.65); }, idle: () => { this.animationTarget.x = 0.5 * canvas.dimensions.x; this.animationTarget.y = 0.5 * canvas.dimensions.y; this.position.lerp(this.animationTarget, 1); } }; }} class Segment { constructor(x, y, len, angle, parent, index) { this.index = index; switch (opts.noise.type) { case "rough": this.tick = Math.round(Math.random() * 10 * opts.structure.armCount); break; case "even": this.tick = 0; break; case "gradient": this.tick = index * 200; break; case "fractal": this.tick = noise.simplex3(x * 0.015, y * 0.015, index * 0.015) * 200; break; default: break;} this.jointSize = Math.random() * 2.5; this.parent = parent; this.len = len; this.angle = angle; this.position = new Vector2(x + this.len * cos(this.angle), y + this.len * sin(this.angle)); this.velocity = new Vector2(); this.head = new Vector2( this.position.x + this.len * cos(this.angle), this.position.y + this.len * sin(this.angle)); this.color = 'hsla(0,0%,0%,0)'; this.renderProps = { line: { x1: this.position.x, y1: this.position.y, x2: this.head.x, y2: this.head.y, w: 1, c: this.color }, arcLine: { x: this.head.x, y: this.head.y, r: this.jointSize, s: 0, e: TAU, c: this.color } }; } update() { this.tick++; this.angle = Math.atan2( this.parent.position.y - this.position.y, this.parent.position.x - this.position..........完整代码请登录后点击上方下载按钮下载查看
网友评论0