Skip to content

Instantly share code, notes, and snippets.

@zymiboxpay
Last active December 29, 2016 06:45
Show Gist options
  • Save zymiboxpay/32c7fc79f6e7892e9a2ee7d596346f7c to your computer and use it in GitHub Desktop.
Save zymiboxpay/32c7fc79f6e7892e9a2ee7d596346f7c to your computer and use it in GitHub Desktop.
particle_system
<!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