バネ関数とベクトルを使用してスライムを作ってみました。
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; | |
} |