バネ関数とベクトルを使用してスライムを作ってみました。
I tried to make a slime using a spring function and vector.
Forked from ykob's Pen canvas demo template.
A Pen by Captain Anonymous on CodePen.
| canvas#canvas |
| var body = document.body; | |
| var width = body.clientWidth; | |
| var height = body.clientHeight; | |
| var canvas = document.getElementById('canvas'); | |
| var ctx = canvas.getContext('2d'); | |
| var animeObjArr = []; | |
| var fps = 60; | |
| var frameTime = 1000 / fps; | |
| var lastTime = +new Date(); | |
| var pointBase = { | |
| x: width / 2, | |
| y: height | |
| }; | |
| var pointGlip = { | |
| x: 0, | |
| y: 0 | |
| }; | |
| var isTouched = false; | |
| var isGliped = false; | |
| var getRandomInt = function(min, max) { | |
| return Math.floor(Math.random() * (max - min)) + min; | |
| }; | |
| var getRadian = function(degrees) { | |
| return degrees * Math.PI / 180; | |
| }; | |
| var getDegree = function(radian) { | |
| return radian / Math.PI * 180; | |
| }; | |
| var getDistance = function(p1x, p1y, p2x, p2y) { | |
| var distX = p1x - p2x; | |
| var distY = p1y - p2y; | |
| return Math.sqrt(distX * distX + distY * distY); | |
| }; | |
| var debounce = function(object, eventType, callback){ | |
| var timer; | |
| object.addEventListener(eventType, function() { | |
| clearTimeout(timer); | |
| timer = setTimeout(function(){ | |
| callback(); | |
| }, 500); | |
| }, false); | |
| }; | |
| var setPointBase = function() { | |
| pointBase.x = width / 2; | |
| pointBase.y = height; | |
| }; | |
| var canvasResize = function() { | |
| ctx.clearRect(0, 0, width, height); | |
| width = document.body.clientWidth; | |
| height = document.body.clientHeight; | |
| canvas.width = width; | |
| canvas.height = height; | |
| setPointBase(); | |
| }; | |
| canvasResize(); | |
| debounce(window, 'resize', function(){ | |
| canvasResize(); | |
| }); | |
| var animeObj = function() { | |
| this.size = 45; | |
| this.angle = 90; | |
| this.k = 0.05; | |
| this.px = width / 2; | |
| this.py = height - 150; | |
| this.x = this.px; | |
| this.y = this.py; | |
| this.ax = 0; | |
| this.ay = 0; | |
| this.vx = 0; | |
| this.vy = 0; | |
| this.cd = 0.1; | |
| this.distance = 0; | |
| this.vector = 0; | |
| this.cp1x = 0; | |
| this.cp1y = 0; | |
| this.cp2x = 0; | |
| this.cp2y = 0; | |
| this.cp3x = 0; | |
| this.cp3y = 0; | |
| this.cp4x = 0; | |
| this.cp4y = 0; | |
| this.cp5x = 0; | |
| this.cp5y = 0; | |
| this.cp6x = 0; | |
| this.cp6y = 0; | |
| this.cp7x = 0; | |
| this.cp7y = 0; | |
| }; | |
| animeObj.prototype.move = function() { | |
| this.px = width / 2; | |
| this.py = height - 150; | |
| if (isGliped) { | |
| this.x = pointGlip.x; | |
| this.y = pointGlip.y; | |
| } else { | |
| this.ax = (this.px - this.x + Math.cos(this.angle) * 50) * this.k; | |
| this.ay = (this.py - this.y + Math.sin(this.angle * 3) * 10) * this.k; | |
| this.ax -= this.cd * this.vx; | |
| this.ay -= this.cd * this.vy; | |
| this.vx += this.ax; | |
| this.vy += this.ay; | |
| this.angle += 0.05; | |
| this.x += this.vx; | |
| this.y += this.vy; | |
| if(this.y > height - this.size) { | |
| this.y = height - this.size; | |
| } | |
| } | |
| this.distance = getDistance(pointBase.x, pointBase.y, this.x, this.y); | |
| this.vector = getDegree(Math.atan2(pointBase.y - this.y, pointBase.x - this.x)); | |
| this.cp1x = width / 2 - this.size * 1.2; | |
| this.cp1y = height; | |
| this.cp2x = width / 2 - (this.size - this.distance / 33) * Math.cos(getRadian(this.vector - 60)); | |
| this.cp2y = height - (this.size - this.distance / 33) * Math.sin(getRadian(this.vector - 60)); | |
| this.cp3x = this.x - (this.size - this.distance / 33) * Math.cos(getRadian(this.vector - 90)); | |
| this.cp3y = this.y - (this.size - this.distance / 33) * Math.sin(getRadian(this.vector - 90)); | |
| this.cp4x = this.x - (this.size - this.distance / 33) * 1.33 * Math.cos(getRadian(this.vector - 45)); | |
| this.cp4y = this.y - (this.size - this.distance / 33) * 1.33 * Math.sin(getRadian(this.vector - 45)); | |
| this.cp5x = this.x - (this.size - this.distance / 33) * Math.cos(getRadian(this.vector)); | |
| this.cp5y = this.y - (this.size - this.distance / 33) * Math.sin(getRadian(this.vector)); | |
| this.cp6x = this.x - (this.size - this.distance / 33) * 1.33 * Math.cos(getRadian(this.vector + 45)); | |
| this.cp6y = this.y - (this.size - this.distance / 33) * 1.33 * Math.sin(getRadian(this.vector + 45)); | |
| this.cp7x = this.x - (this.size - this.distance / 33) * Math.cos(getRadian(this.vector + 90)); | |
| this.cp7y = this.y - (this.size - this.distance / 33) * Math.sin(getRadian(this.vector + 90)); | |
| this.cp8x = width / 2 - this.size * Math.cos(getRadian(this.vector + 60)); | |
| this.cp8y = height - this.size * Math.sin(getRadian(this.vector + 60)); | |
| this.cp9x = width / 2 + this.size * 1.2; | |
| this.cp9y = height; | |
| }; | |
| animeObj.prototype.render = function() { | |
| ctx.font = "14px Arial"; | |
| ctx.lineWidth = 3; | |
| ctx.strokeStyle = '#5d7490'; | |
| ctx.fillStyle = '#a6c0e1'; | |
| ctx.beginPath(); | |
| ctx.moveTo(this.cp1x, this.cp1y); | |
| ctx.quadraticCurveTo(this.cp2x, this.cp2y, this.cp3x, this.cp3y); | |
| ctx.quadraticCurveTo(this.cp4x, this.cp4y, this.cp5x, this.cp5y); | |
| ctx.quadraticCurveTo(this.cp6x, this.cp6y, this.cp7x, this.cp7y); | |
| ctx.quadraticCurveTo(this.cp8x, this.cp8y, this.cp9x, this.cp9y); | |
| ctx.fill(); | |
| ctx.stroke(); | |
| ctx.closePath(); | |
| ctx.fillStyle = '#5d7490'; | |
| ctx.beginPath(); | |
| ctx.arc(this.x, this.y, this.size / 3, 0, getRadian(360), false); | |
| ctx.fill(); | |
| ctx.closePath(); | |
| ctx.fillText("distance : " + Math.floor(this.distance) + 'px', this.x + this.size, this.y - this.size); | |
| ctx.fillText("vector : " + Math.floor(this.vector) + '°', this.x + this.size + 10, this.y - this.size + 20); | |
| }; | |
| animeObj.prototype.judgeGliped = function() { | |
| if(getDistance(pointGlip.x, pointGlip.y, this.x, this.y) < this.size && isTouched === true) { | |
| isGliped = true; | |
| }; | |
| isTouched = false; | |
| }; | |
| animeObjArr.push(new animeObj()); | |
| var render = function() { | |
| ctx.clearRect(0, 0, width, height); | |
| for (var i = 0; i < animeObjArr.length; i++) { | |
| animeObjArr[i].move(); | |
| animeObjArr[i].render(); | |
| animeObjArr[i].judgeGliped(); | |
| }; | |
| }; | |
| var renderloop = function() { | |
| var now = +new Date(); | |
| requestAnimationFrame(renderloop); | |
| if (now - lastTime < frameTime) return; | |
| render(); | |
| }; | |
| renderloop(); | |
| document.addEventListener('mousedown', function(event) { | |
| isTouched = true; | |
| pointGlip.x = event.x; | |
| pointGlip.y = event.y; | |
| }, false); | |
| document.addEventListener('touchstart', function(event) { | |
| event.preventDefault(); | |
| isTouched = true; | |
| pointGlip.x = event.touches[0].pageX; | |
| pointGlip.y = event.touches[0].pageY; | |
| }, false); | |
| document.addEventListener('mousemove', function(event) { | |
| if (!isGliped) return; | |
| pointGlip.x = event.x; | |
| pointGlip.y = event.y; | |
| }, false); | |
| document.addEventListener('touchmove', function(event) { | |
| event.preventDefault(); | |
| if (!isGliped) return; | |
| pointGlip.x = event.touches[0].pageX; | |
| pointGlip.y = event.touches[0].pageY; | |
| }, false); | |
| document.addEventListener('mouseup', function(event) { | |
| isGliped = false; | |
| }, false); | |
| document.addEventListener('mouseout', function(event) { | |
| isGliped = false; | |
| }, false); | |
| document.addEventListener('touchend', function(event) { | |
| event.preventDefault(); | |
| isGliped = false; | |
| }, false); |
バネ関数とベクトルを使用してスライムを作ってみました。
I tried to make a slime using a spring function and vector.
Forked from ykob's Pen canvas demo template.
A Pen by Captain Anonymous on CodePen.
| * { | |
| margin: 0; | |
| padding: 0; | |
| } | |
| html { | |
| height: 100%; | |
| background-color: #fff; | |
| } | |
| body { | |
| height: 100%; | |
| overflow: hidden; | |
| } |