canvas实现一个疯狂的迷宫动画效果代码
代码语言:html
所属分类:动画
代码描述:canvas实现一个疯狂的迷宫动画效果代码,点击可切换新的迷宫
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <style> body { font-family: Arial, Helvetica, "Liberation Sans", FreeSans, sans-serif; background-color: #000; margin: 0; padding: 0; border-width: 0; cursor: pointer; } </style> </head> <body > <script> "use strict"; window.addEventListener("load", function () { let canv, ctx; // canvas and context let maxx, maxy; // canvas dimensions let lSegment, nbx, nby, offsx, offsy, posx, posy; let segs, nbRot, maxNbRot; let grid; let balls; const wSegment = 5; // for animation let messages; // shortcuts for Math. const mrandom = Math.random; const mfloor = Math.floor; const mround = Math.round; const mceil = Math.ceil; const mabs = Math.abs; const mmin = Math.min; const mmax = Math.max; const mPI = Math.PI; const mPIS2 = Math.PI / 2; const mPIS3 = Math.PI / 3; const m2PI = Math.PI * 2; const m2PIS3 = Math.PI * 2 / 3; const msin = Math.sin; const mcos = Math.cos; const matan2 = Math.atan2; const mhypot = Math.hypot; const msqrt = Math.sqrt; const rac3 = msqrt(3); const rac3s2 = rac3 / 2; //------------------------------------------------------------------------ function alea(mini, maxi) { // random number in given range if (typeof maxi == "undefined") return mini * mrandom(); // range 0..mini return mini + mrandom() * (maxi - mini); // range mini..maxi } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function intAlea(mini, maxi) { // random integer in given range (mini..maxi - 1 or 0..mini - 1) // if (typeof maxi == "undefined") return mfloor(mini * mrandom()); // range 0..mini - 1 return mini + mfloor(mrandom() * (maxi - mini)); // range mini .. maxi - 1 } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function arrayShuffle(array) { /* randomly changes the order of items in an array only the order is modified, not the elements */ let k1, temp; for (let k = array.length - 1; k >= 1; --k) { k1 = intAlea(0, k + 1); temp = array[k]; array[k] = array[k1]; array[k1] = temp; } // for k return array; } // arrayShuffle //------------------------------------------------------------------------ class EdgeLine { constructor(square, side) { this.s0 = { square, side }; this.p0 = { x: posx[square.kx + [0, 1, 0, 0][side]], y: posy[square.ky + [0, 0, 1, 0][side]] }; this.p1 = { x: posx[square.kx + [1, 1, 1, 0][side]], y: posy[square.ky + [0, 1, 1, 1][side]] }; // prevent segments from coming on outer edges of grid if (square.ky == 0 && side == 0) this.occupied = true; // top edge if (square.kx == nbx - 1 && side == 1) this.occupied = true; // right edge if (square.ky == nby - 1 && side == 2) this.occupied = true; // bottom edge if (square.kx == 0 && side == 3) this.occupied = true; // left edge }} // class EdgeLine //------------------------------------------------------------------------ class Segment { constructor() { let kx, ky, kedge; // pick random edge of random square - unouccupied do { kx = intAlea(nbx); ky = intAlea(nby); kedge = intAlea(4); } while (grid[ky][kx].edges[kedge].edgeLine.occupied); this.edgeLine = grid[ky][kx].edges[kedge].edgeLine; this.edgeLine.occupied = true; this.color = alea(1) > 0.05 ? "white" : `hsl(${intAlea(360)} 100% 50%)`; } // constructor rotate() { /* initiates a rotation returns true if successful, false if failed (rotation was not possible or already in progress) */ if (this.resting) return false; if (this.rotating) return false; let poss = [0, 1, 2, 3]; this.tInit = performance.now(); this.duration = alea(600, 800); otherPoss: while (poss.length) { let choice = poss.splice(intAlea(poss.length), 1)[0]; let ssquare = choice & 2 ? this.edgeLine.s0 : this.edgeLine.s1; // choice of the square the segment will cross if (ssquare.square.occupied) continue otherPoss; // chosen square already occupied let dSide = choice & 1 ? 1 : 3; // choice of rotation (1 means ccw, 3 = -1 % 4 means cw) let nextSide = (ssquare.side + dSide) % 4; if (ssquare.square.edges[nextSide].edgeLine.occupied) continue otherPoss; // target side already occupied // found good move ssquare.square.edges[nextSide].edgeLine.occupied = true; // will occupy next side let kcenter = (ssquare.side + (choice & 1)) % 4; this.center = { x: posx[ssquare.square.kx + [0, 1, 1, 0][kcenter]], y: posy[ssquare.square.ky + [0, 0, 1, 1][kcenter]] }; this.alpha0 = (kcenter + (choice & 1)) * mPI / 2; // initial angle this.alpha1 = this.alpha0 + (choice & 1 ? -1 : 1) * mPI / 2; ssquare.square.occupied = true; this.sSquare = ssquare; this.edgeLine.occupied = false; this.edgeLine = ssquare.square.edges[nextSide].edgeLine; this.edgeLine.occupied = true; this.rotating = true; this.tInit = performance.now(); ++nbRot; return true; } // while poss.length return false; // found no good move } // rotate draw() { ctx.beginPath(); ctx.lineWidth = wSegment; ctx.strokeStyle = this.color; if (this.rotating) { let dt = performance.now() - this.tInit; dt = mmin(1, dt / this.duration); let angle = this.alpha0 * (1 - dt) + this.alpha1 * dt; ctx.moveTo(this.center.x, this.center.y); ctx.lineTo( this.center.x + lSegment * mcos(angle), this.center.y + lSegment * msin(angle)); if (dt >= 1) { this.rotating = false; this.resting = true; this.duration = alea(800, 1200); this.tInit = performance.now(); this.sSquare.square.occupied = false; --nbRot; } } else { ctx.moveTo(this.edgeLine.p0.x, this.edgeLine.p0.y); ctx.lineTo(this.edgeLine.p1.x, this.edgeLine.p1.y); if (this.resting && performance.now() - this.tInit > this.duration) { this.resting = false; } } ctx.stroke(); } // draw } // class Segment //------------------------------------------------------------------------ class Square { constructor(kx, ky) { // relies on the fact that grid squares are built in a given order let otherEdge; this.kx = kx; this.ky = ky; this.edges = []; // top edge this.edges[0] = {}; if (this.ky == 0) { this.edges[0].edgeLine = new EdgeLine(this, 0); } else { otherEdge = grid[ky - 1][kx].edges[2]; this.edges[0].edgeLine = otherEdge.edgeLine; this.edges[0].edgeLine.s1 = { square: this, side: 0 }; this.edges[0].other = otherEdge; otherEdge.other = this.edges[0]; } // right edge this.edges[1] = {}; .........完整代码请登录后点击上方下载按钮下载查看
网友评论0