Last active
December 29, 2016 06:45
-
-
Save zymiboxpay/32c7fc79f6e7892e9a2ee7d596346f7c to your computer and use it in GitHub Desktop.
particle_system
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>partical</title> | |
<style> | |
body { | |
margin: 0; | |
padding: 0; | |
} | |
canvas { | |
background-color: black; | |
border: 1px solid; | |
} | |
</style> | |
</head> | |
<body> | |
<canvas></canvas> | |
<script> | |
var GAME_OVER = false; | |
var PAUSE = false; | |
var total = 0; | |
var canvas = document.querySelector('canvas'); | |
var ctx = canvas.getContext('2d'); | |
canvas.width = 250;//window.innerWidth; | |
canvas.height = 250;//window.innerHeight; | |
var midX = canvas.width / 2; | |
var midY = canvas.height / 2; | |
function Vector(x, y){ | |
this.x = x || 0; | |
this.y = y || 0; | |
} | |
Vector.prototype = { | |
add: function(vector){ | |
this.x += vector.x; | |
this.y += vector.y; | |
}, | |
getMagnitude: function(){ | |
return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2)); | |
}, | |
getAngle: function(){ | |
return Math.atan2(this.y, this.x); | |
} | |
}; | |
Vector.fromAngle = function(angle, magnitude){ | |
return new Vector(magnitude * Math.cos(angle), magnitude * Math.sin(angle)); | |
}; | |
function Particle(point, velocity, acceleration){ | |
this.position = point || new Vector(0,0); | |
this.velocity = velocity || new Vector(0,0); | |
this.acceleration = acceleration || new Vector(0,0); | |
} | |
Particle.prototype = { | |
move: function(){ | |
this.velocity.add(this.acceleration); | |
this.position.add(this.velocity); | |
}, | |
bounceX: function(){ | |
this.velocity.x = -(this.velocity.x); | |
}, | |
bounceY: function(){ | |
this.velocity.y = -(this.velocity.y); | |
} | |
}; | |
function Obstacle(point, status, width, height){ | |
this.position = point || new Vector(0,0); | |
this.status = status || 'active'; | |
this.width = width || 1; | |
this.height = height || 1; | |
this.drawColor = "#999"; | |
} | |
function generateObstacles(){ | |
var arr = []; | |
total = 0; | |
for (var i = canvas.width * 0.2; i < canvas.width * 0.8; i+= 4) { | |
for (var j = canvas.height * 0.2; j < canvas.height * 0.3; j+= 4){ | |
ob = new Obstacle(new Vector(i, j), 'active', 3, 3); | |
total += 1; | |
arr.push(ob); | |
} | |
} | |
return arr; | |
} | |
function plotObstacles(){ | |
} | |
function drawObstacles(){ | |
for (var i = 0; i < obstacles.length ; i++) { | |
if(obstacles[i].status == 'active'){ | |
drawRect(obstacles[i]); | |
} | |
} | |
} | |
function Emitter(point, velocity, spread){ | |
this.position = point; | |
this.velocity = velocity; | |
this.spread = spread || Math.PI / 32; | |
this.drawColor = "#999"; | |
} | |
Emitter.prototype = { | |
emitParticle: function(){ | |
var angle = this.velocity.getAngle();// + this.spread - (Math.random() * this.spread * 2); | |
var magnitude = this.velocity.getMagnitude(); | |
var velocity = Vector.fromAngle(angle, magnitude); | |
var position = new Vector(this.position.x, this.position.y); | |
return new Particle(position, velocity); | |
} | |
}; | |
function Board(point, width, height, velocity){ | |
this.position = point || new Vector(0,0); | |
this.width = width || 1; | |
this.height = height || 1; | |
this.acceleration = new Vector(0,0); | |
this.velocity = velocity || new Vector(0,0); | |
this.max_velocity = 1.6; | |
} | |
Board.prototype = { | |
move: function(){ | |
this.velocity.add(this.acceleration); | |
if(this.velocity > this.max_velocity){ | |
this.velocity = this.max_velocity; | |
} | |
this.position.add(this.velocity); | |
}, | |
is_stopped: function(){ | |
return this.velocity.x == 0 && this.velocity.y == 0; | |
} | |
}; | |
function plotParticle(boundX, boundY){ | |
if(particle.position.y > boundY){ | |
GAME_OVER = true; | |
return; | |
} | |
if(particle.position.y < 0){ | |
particle.bounceY(); | |
} | |
if(particle.position.x < 0 || particle.position.x > boundX){ | |
particle.bounceX(); | |
} | |
if((boundY - particle.position.y) < 10){ | |
if(particle.position.x > board.position.x && particle.position.x < board.position.x + board.width && particle.position.y > board.position.y){ | |
if(board.velocity.x != 0){ | |
particle.velocity.x = board.velocity.x; | |
} | |
particle.bounceY(); | |
} | |
} | |
for (var i = 0; i < obstacles.length ; i++) { | |
// 让 obstacle 近似圆,根据两物体中心点距离是否小于两物体半径和判断是否碰撞,很粗 | |
if(obstacles[i].status == 'active' && Math.sqrt(Math.pow((particle.position.x-(obstacles[i].position.x + obstacles[i].width / 2)),2) + Math.pow((particle.position.y-(obstacles[i].position.y + obstacles[i].height / 2)),2)) <= (1.5 * 1.414 + 2)){ | |
obstacles[i].status = 'inactive'; | |
total -= 1; | |
if(total <= 0) { | |
GAME_OVER = true; | |
} | |
//从上下碰撞 | |
if(particle.position.x >= obstacles[i].position.x && particle.position.x <= (obstacles[i].position.x + obstacles[i].width)){ | |
particle.bounceY(); | |
} | |
//从左右碰撞 | |
else if (particle.position.y >= obstacles[i].position.y && particle.position.y <= (obstacles[i].position.y + obstacles[i].height)) { | |
particle.bounceX(); | |
} | |
} | |
} | |
particle.move(); | |
} | |
function plotBoard(boundX, boundY){ | |
if(board.position.x < 0){ | |
board.position.x = 0; | |
board.acceleration = new Vector(0,0); | |
board.velocity = new Vector(0,0); | |
} | |
if(board.position.x > boundX - board.width){ | |
board.position.x = boundX - board.width; | |
board.acceleration = new Vector(0,0); | |
board.velocity = new Vector(0,0); | |
} | |
if(board.position.y < 0){ | |
board.position.y = 0; | |
board.acceleration = new Vector(0,0); | |
board.velocity = new Vector(0,0); | |
} | |
if(board.position.y > boundY - board.height){ | |
board.position.y = boundY - board.height; | |
board.acceleration = new Vector(0,0); | |
board.velocity = new Vector(0,0); | |
} | |
board.move(); | |
} | |
var particleSize = 2; | |
function drawParticle(){ | |
ctx.fillStyle = 'rgb(255,255,255)'; | |
ctx.beginPath(); | |
ctx.arc(particle.position.x, particle.position.y, particleSize, 0, Math.PI * 2); | |
ctx.closePath(); | |
ctx.fill(); | |
} | |
var objectSize = 2; | |
function drawCircle(object){ | |
ctx.fillStyle = object.drawColor; | |
ctx.beginPath(); | |
ctx.arc(object.position.x, object.position.y, object.size || objectSize, 0, Math.PI * 2); | |
ctx.closePath(); | |
ctx.fill(); | |
} | |
function drawBoard(){ | |
ctx.fillStyle = 'rgb(0,255,0)'; | |
ctx.fillRect(board.position.x, board.position.y, board.width, board.height); | |
} | |
function drawRect(object){ | |
ctx.fillStyle = object.drawColor; | |
ctx.fillRect(object.position.x, object.position.y, object.width, object.height); | |
} | |
function drawPause(){ | |
if(PAUSE) { | |
ctx.fillStyle = "#999"; | |
ctx.fillText('pause', 100, 100); | |
} | |
} | |
function boardListenEvent(){ | |
document.addEventListener('keydown', function(e){ | |
switch(e.keyCode){ | |
case 65: | |
// console.log('keydown left'); | |
if(board.velocity.x > 0){ | |
board.velocity.x = 0; | |
} | |
board.acceleration = new Vector(-0.2, board.acceleration.y); | |
break; | |
case 68: | |
// console.log('keydown right'); | |
if(board.velocity.x < 0){ | |
board.velocity.x = 0; | |
} | |
board.acceleration = new Vector(0.2, board.acceleration.y); | |
break; | |
case 32: | |
// console.log('keydown run/pause toggle'); | |
PAUSE = !PAUSE; | |
if(!PAUSE) { | |
window.requestAnimationFrame(loop); | |
} | |
break; | |
default: | |
console.log('keydown skip code: ', e.keyCode); | |
} | |
},false); | |
document.addEventListener('keyup', function(e){ | |
switch(e.keyCode){ | |
case 65: | |
// console.log('keyup left'); | |
board.acceleration = new Vector(0, 0); | |
board.velocity = new Vector(0, 0); | |
break; | |
case 68: | |
// console.log('keyup right'); | |
board.acceleration = new Vector(0, 0); | |
board.velocity = new Vector(0, 0); | |
break; | |
default: | |
// console.log('keyup skip code: ', e.keyCode); | |
} | |
// console.log('now velocity:', board.velocity); | |
}, false); | |
} | |
var board,emitter,particle,obstacles; | |
function begin(){ | |
board = new Board(new Vector(0,canvas.height), 40, 5); | |
emitter = new Emitter(new Vector(midX - 50, midY), Vector.fromAngle(-1, 2), Math.PI / 4); | |
particle = emitter.emitParticle(); | |
obstacles = generateObstacles(); | |
} | |
function loop(){ | |
clear(); | |
update(); | |
draw(); | |
queue(); | |
} | |
function clear(){ | |
ctx.clearRect(0,0, canvas.width, canvas.height); | |
} | |
function update(){ | |
plotBoard(canvas.width, canvas.height); | |
plotParticle(canvas.width, canvas.height); | |
plotObstacles(); | |
} | |
function draw(){ | |
drawParticle(); | |
drawBoard(); | |
drawObstacles(); | |
drawPause(); | |
} | |
function queue(){ | |
if(!over() && !PAUSE){ | |
window.requestAnimationFrame(loop); | |
} | |
else if(over()) { | |
var confirm = window.confirm('game over, play again?'); | |
if(confirm) { | |
GAME_OVER = false; | |
begin(); | |
loop(); | |
} | |
} | |
} | |
function over(){ | |
return GAME_OVER == true; | |
} | |
begin(); | |
boardListenEvent(); | |
loop(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment