js实现数字自由落体弹跳canvas动画效果代码
代码语言:html
所属分类:动画
代码描述:js实现数字自由落体弹跳canvas动画效果代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<html> <head> <style> html, body { touch-action: none; content-zooming: none; margin: 0; padding: 0; background: #333; position: absolute; width: 100%; height: 100%; } #screen { width: 100%; height: 100%; margin: auto auto; position: fixed; top: 0; bottom: 0; left: 0; right: 0; background: #000; cursor: pointer; } </style> </head> <body> <canvas id="screen" width="642" height="679"></canvas><script> ! function () { "use strict"; /* ==== screen setup ==== */ var screen = { elem: document.getElementById("screen"), width: 0, height: 0, top: 0, left: 0, resize: function () { var o = screen.elem; screen.width = o.offsetWidth; screen.height = o.offsetHeight; for (screen.left = 0, screen.top = 0; o != null; o = o.offsetParent) { screen.left += o.offsetLeft; screen.top += o.offsetTop; } screen.elem.width = screen.width; screen.elem.height = screen.height; if (PHY2D) { PHY2D.deleteStatic(); PHY2D.rectangle(screen.width / 2, screen.height + 50, screen.width, 100, 0, 0); PHY2D.rectangle(screen.width / 2, -screen.height * 2, screen.width, 100, 0, 0); PHY2D.rectangle(-50, 0, 100, screen.height * 4, 0, 0); PHY2D.rectangle(screen.width + 50, 0, 100, screen.height * 4, 0, 0); } } } screen.elem.onselectstart = function () { return false; } screen.elem.ondrag = function () { return false; } var ctx = screen.elem.getContext("2d"); window.addEventListener('resize', screen.resize, false); /* ==== pointer setup ==== */ var pointer = { pos: { x: 0, y: 0 }, active: false, down: function (e, touch) { e.preventDefault(); var p = touch ? e.touches[0]: e; (!touch && document.setCapture) && document.setCapture(); this.pos.x = p.clientX - screen.left; this.pos.y = p.clientY - screen.top; this.active = true; }, up: function (e, touch) { e.preventDefault(); (!touch && document.releaseCapture) && document.releaseCapture(); this.active = false; }, move: function (e, touch) { e.preventDefault(); var p = touch ? e.touches[0]: e; if (this.active) { this.pos.x = p.clientX - screen.left; this.pos.y = p.clientY - screen.top; } } } if ('ontouchstart' in window) { screen.elem.ontouchstart = function (e) { pointer.down(e, true); }.bind(pointer); screen.elem.ontouchmove = function (e) { pointer.move(e, true); }.bind(pointer); screen.elem.ontouchend = function (e) { pointer.up(e, true); }.bind(pointer); screen.elem.ontouchcancel = function (e) { pointer.up(e, true); }.bind(pointer); } document.addEventListener("mousedown", function (e) { pointer.down(e, false); }.bind(pointer), true); document.addEventListener("mousemove", function (e) { pointer.move(e, false); }.bind(pointer), true); document.addEventListener("mouseup", function (e) { pointer.up(e, false); }.bind(pointer), true); /* ==== vector 2D library ==== */ function Vector(x, y) { this.x = x || 0.0; this.y = y || 0.0; } Vector.prototype = { set: function (x, y) { this.x = x; this.y = y; return this; }, dot: function (v) { return this.x * v.x + this.y * v.y; }, lenSqr: function () { return this.x * this.x + this.y * this.y; }, transform: function (v, m) { this.x = m.cos * v.x - m.sin * v.y + m.pos.x; this.y = m.sin * v.x + m.cos * v.y + m.pos.y; return this; }, rotate: function (v, m) { this.x = m.cos * v.x - m.sin * v.y; this.y = m.sin * v.x + m.cos * v.y; return this; }, normal: function (a, b) { var x = a.x - b.x, y = a.y - b.y, len = Math.sqrt(x * x + y * y); this.x = -y / len; this.y = x / len; return this; }, project: function (a, b, n) { var x = a.x - b.x, y = a.y - b.y, len = Math.sqrt(x * x + y * y); return (-y / len) * n.x + (x / len) * n.y; }, addScale: function (v1, v2, s) { this.x = v1.x + (v2.x * s); this.y = v1.y + (v2.y * s); return this; }, subScale: function (v1, v2, s) { this.x = v1.x - (v2.x * s); this.y = v1.y - (v2.y * s); return this; }, add: function (v1, v2) { this.x = v1.x + v2.x; this.y = v1.y + v2.y; return this; }, sub: function (v1, v2) { this.x = v1.x - v2.x; this.y = v1.y - v2.y; return this; }, scale: function (v1, s) { this.x = v1.x * s; this.y = v1.y * s; return this; }, perp: function () { var x = this.x; this.x = -this.y; this.y = x; return this; }, inv: function (v1) { this.x = -v1.x; this.y = -v1.y; return this; }, clamp: function (v, min, max) { if (v > max) v = max; else if (v < min) v = min; return v; }, rotateIntoSpaceOf: function (a, m) { var dx = -a.x, dy = -a.y; this.x = dx * m.cos + dy * m.sin; this.y = dx * -m.sin + dy * m.cos; return this; }, // SIMD Array vectors array: function (n, values) { var array = new Array(n); array.min = new Vector(); array.max = new Vector(); for (var i = 0; i < n; i++) { array[i] = new Vector( values ? values[i * 2 + 0]: 0.0, values ? values[i * 2 + 1]: 0.0 ); } array.transform = function (v, m) { for (var i = 0, len = this.length; i < len; i++) { var vi = v[i], elem = this[i]; var x = m.cos * vi.x - m.sin * vi.y + m.pos.x; var y = m.sin * vi.x + m.cos * vi.y + m.pos.y; if (x < this.min.x) this.min.x = x; if (y < this.min.y) this.min.y = y; if (x > this.max.x) this.max.x = x; if (y > this.max.y) this.max.y = y; elem.x = x; elem.y = y; } return this; } array.rotate = function (v, m) { for (var i = 0, len = this.length; i < len; i++) { var vi = v[i], elem = this[i]; elem.x = m.cos * vi.x - m.sin * vi.y; elem.y = m.sin * vi.x + m.cos * vi.y; } return this; } array.resetMinmax = function () { this.min.x = 100000.0; this.min.y = 100000.0; this.max.x = -100000.0; this.max.y = -100000.0; } array.normal = function (points) { for (var i = 0; i < this.length; i++) { this[i].normal( points[(i + 1) % this.length], points[i] ); } return this; } return array; } } /* ==== Matrix container ==== */ function Matrix() { this.cos = 0.0; this.sin = 0.0; this.pos = new Vector(); this.ang = 0.0; } Matrix.prototype = { set: function (a, x, y, w, h) { this.cos = Math.cos(a); this.sin = Math.sin(a); this.ang = a; this.pos.x = x; this.pos.y = y; this.w = w; this.h = h; return this; }, copy: function (matrix) { this.cos = matrix.cos; this.sin = matrix.sin; this.ang = matrix.ang; this.pos.x = matrix.pos.x; this.pos.y = matrix.pos.y; return this; }, integrate: function (va, vx, vy, kTimeStep) { this.pos.x += vx * kTimeStep; this.pos.y += vy * kTimeStep; this.ang += va * kTimeStep; this.cos = Math.cos(this.ang); this.sin = Math.sin(this.ang); return this; } } /* ==== PHY2D continuous collision engine ==== */ var PHY2D = function (ctx, pointer, Vector, Matrix) { var kGravity = 5; var kTimeStep = 1 / 60; var kFriction = 0.5; var objects = []; var drag = false; var v0 = new Vector(); var v1 = new Vector(); var v2 = new Vector(); var v3 = new Vector(); var v4 = new Vector(); var v5 = new Vector(); // contacts list var contacts = []; contacts.index = 0; contacts.create = function (A, B, pa, pb, nx, ny) { if (!this[this.index]) this[this.index] = new Contact(); this[this.index++].set(A, B, pa, pb, nx, ny); } // AABB container function AABB() { this.x = 0.0; this.y = 0.0; this.w = 0.0; this.h = 0.0; } // Polygon constructor function Polygon(x, y, w, h, vertices, invMass, angle, img) { this.img = img; this.vel = new Vector(); this.angularVel = 0.0; this.invMass = invMass; this.matrix = new Matrix().set(angle, x, y, w, h); this.aabb = new AABB(); this.drag = false; this.static = false; this.length = (vertices.length / 2) | 0; this.localSpacePoints = new Vector().array(this.length, vertices); this.localSpaceNormals = new Vector().array(this.length).normal(this.localSpacePoints); this.worldSpaceNormals = new Vector().array(this.length); this.worldSpacePoints = new Vector().array(this.length); this.invI = (invMass > 0) ? 1 / ((1 / invMass) * (w * w + h * h) / 3): 0 this.c1 = new Vector(); this.c0 = new Vector(); objects.push(this); } Polygon.prototype = { // calculate aabb & transform world space points motionAABB: function () { this.worldSpacePoints.resetMinmax(); this.worldSpacePoints.transform(this.localSpacePoints, this.matrix); this.worldSpaceNormals.rotate(this.localSpaceNormals, this.matrix); var min = this.worldSpacePoints.min; var max = this.worldSpacePoints.max; this.aabb.x = (min.x + max.x) * 0.5; this.aabb.y = (min.y + max.y) * 0.5; this.aabb.w = (max.x - min.x) * 0.5; this.aabb.h = (max.y - min.y) * 0.5; }, // Poly vs poly collision detection (Minkowski Difference) contact: function (that) { var face, vertex, vertexRect, faceRect, fp, va, vb, vc, nx, ny, wsN, wdV0, wdV1, wsV0, wsV1; mostSeparated.set(100000, -1, -1, 0, 100000); mostPenetrating.set(-100000, -1, -1, 0, 100000); this.featurePairJudgement(that, 2); that.featurePairJudgement(this, 1); if (mostSeparated.dist > 0 && mostSeparated.fpc !== 0) { face = mostSeparated.edge; vertex = mostSeparated.closestI; fp = mostSeparated.fpc; } else if (mostPenetrating.dist <= 0) { face = mostPenetrating.edge; vertex = mostPenetrating.closestI; fp = mostPenetrating.fpc; } if (fp === 1) vertexRect = this, faceRect = that; else vertexRect = that, faceRect = this; wsN = faceRect.worldSpaceNormals[face]; va = vertexRect.worldSpacePoints[(vertex - 1 + vertexRect.length) % vertexRect.length]; vb = vertexRect.worldSpacePoints[vertex]; vc = vertexRect.worldSpacePoints[(vertex + 1) % vertexRect.length]; if (v0.project(vb, va, wsN) < v1.project(vc, vb, wsN)) { wdV0 .........完整代码请登录后点击上方下载按钮下载查看
网友评论0