UNPKG

paper

Version:

The Swiss Army Knife of Vector Graphics Scripting

152 lines (135 loc) 5.01 kB
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Candy Crash</title> <link rel="stylesheet" href="../css/style.css"> <script type="text/javascript" src="../../dist/paper-full.js"></script> <script type="text/paperscript" canvas="canvas"> // kynd.info 2014 function Ball(r, p, v) { this.radius = r; this.point = p; this.vector = v; this.maxVec = 15; this.numSegment = Math.floor(r / 3 + 2); this.boundOffset = []; this.boundOffsetBuff = []; this.sidePoints = []; this.path = new Path({ fillColor: { hue: Math.random() * 360, saturation: 1, brightness: 1 }, blendMode: 'lighter' }); for (var i = 0; i < this.numSegment; i ++) { this.boundOffset.push(this.radius); this.boundOffsetBuff.push(this.radius); this.path.add(new Point()); this.sidePoints.push(new Point({ angle: 360 / this.numSegment * i, length: 1 })); } } Ball.prototype = { iterate: function() { this.checkBorders(); if (this.vector.length > this.maxVec) this.vector.length = this.maxVec; this.point += this.vector; this.updateShape(); }, checkBorders: function() { var size = view.size; if (this.point.x < -this.radius) this.point.x = size.width + this.radius; if (this.point.x > size.width + this.radius) this.point.x = -this.radius; if (this.point.y < -this.radius) this.point.y = size.height + this.radius; if (this.point.y > size.height + this.radius) this.point.y = -this.radius; }, updateShape: function() { var segments = this.path.segments; for (var i = 0; i < this.numSegment; i ++) segments[i].point = this.getSidePoint(i); this.path.smooth(); for (var i = 0; i < this.numSegment; i ++) { if (this.boundOffset[i] < this.radius / 4) this.boundOffset[i] = this.radius / 4; var next = (i + 1) % this.numSegment; var prev = (i > 0) ? i - 1 : this.numSegment - 1; var offset = this.boundOffset[i]; offset += (this.radius - offset) / 15; offset += ((this.boundOffset[next] + this.boundOffset[prev]) / 2 - offset) / 3; this.boundOffsetBuff[i] = this.boundOffset[i] = offset; } }, react: function(b) { var dist = this.point.getDistance(b.point); if (dist < this.radius + b.radius && dist != 0) { var overlap = this.radius + b.radius - dist; var direc = (this.point - b.point).normalize(overlap * 0.015); this.vector += direc; b.vector -= direc; this.calcBounds(b); b.calcBounds(this); this.updateBounds(); b.updateBounds(); } }, getBoundOffset: function(b) { var diff = this.point - b; var angle = (diff.angle + 180) % 360; return this.boundOffset[Math.floor(angle / 360 * this.boundOffset.length)]; }, calcBounds: function(b) { for (var i = 0; i < this.numSegment; i ++) { var tp = this.getSidePoint(i); var bLen = b.getBoundOffset(tp); var td = tp.getDistance(b.point); if (td < bLen) { this.boundOffsetBuff[i] -= (bLen - td) / 2; } } }, getSidePoint: function(index) { return this.point + this.sidePoints[index] * this.boundOffset[index]; }, updateBounds: function() { for (var i = 0; i < this.numSegment; i ++) this.boundOffset[i] = this.boundOffsetBuff[i]; } }; //--------------------- main --------------------- var balls = []; var numBalls = 18; for (var i = 0; i < numBalls; i++) { var position = Point.random() * view.size; var vector = new Point({ angle: 360 * Math.random(), length: Math.random() * 10 }); var radius = Math.random() * 60 + 60; balls.push(new Ball(radius, position, vector)); } function onFrame() { for (var i = 0; i < balls.length - 1; i++) { for (var j = i + 1; j < balls.length; j++) { balls[i].react(balls[j]); } } for (var i = 0, l = balls.length; i < l; i++) { balls[i].iterate(); } } </script> </head> <body> <canvas id="canvas" resize hidpi="off" style="background:black"></canvas> </body> </html>