html5 canvas collision detection with multiple blocks - javascript

I've been trying to create a game with falling blocks that will stack on top of each other. The blocks will fall into one of 6 columns and need to stop falling down the screen when they collide with the top block on that column. I've been trying to get the y-coordinate of the top block, but that causes a problem because its still getting the newest created block and not the last finished block. Any help would be greatly appreciated!
var FPS = 60;
setInterval(function() {
//update();
draw();
}, 1000/FPS);
var y = 30;
//draw the screen
function draw() {
if(+new Date() > lastTime + minWait){
var column = Math.floor(Math.random()*6)
lastTime = +new Date();
blocks.push(new Block(5 + column*40, 30,40,40, 5, "red","black"));
}
context.clearRect(0,0,canvas.width, canvas.height);
blocks.forEach(function(e){
e.update();
e.render();
});
};
var blocks = [];
var lastTime = +new Date();
var minWait = 1000;
var topBlock = 310;
function columnTop(column){
for(var i=0; i < blocks.length; i++){
if(blocks[i].x === (5 + 40*columnTop)){
if(blocks[i].y < topBlock){
topBlock = blocks[i].y
}
}
}
}
//block functions
Block.prototype.update = function(){
var topCol1 = columnTop(1);
var topCol2 = columnTop(2);
var topCol3 = columnTop(3);
var topCol4 = columnTop(4);
var topCol5 = columnTop(5);
var topCol6 = columnTop(6);
if(this.y < 310){
this.y+= this.dy
}else{
this.dy = 0;
}
};
Block.prototype.render = function(){
Block(this.x, this.y, this.w, this.h, this.r, this.fillstyle, this.strokestyle);
};

Maintain a maximum-Y value for each column.
maximum-Y is the y-position of the last stacked block.
Whenever a block exceeds the maximum-Y, force that block to sit atop the maximum-Y.
Then reduce maximum-Y by that blocks height.
if( block.y + block.height > maxY ){
block.y = maxY - block.height;
maxY = block.y;
}
Here's code and a Demo: http://jsfiddle.net/m1erickson/FMv2q/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" />
<script src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
function Blocks(floor,colCount){
this.blocks=[];
this.floor=floor;
this.cols=[];
this.continueRAF=true;
for(var i=0;i<colCount;i++){
this.cols.push({maxY:floor,needsNewBlock:true});
}
}
function animate(){
if(blocks.continueRAF){ requestAnimationFrame(animate); }
for(var i=0;i<blocks.cols.length;i++){
if(blocks.cols[i].needsNewBlock){
blocks.cols[i].needsNewBlock=false;
blocks.blocks.push(new Block(i));
}
}
ctx.clearRect(0,0,canvas.width,canvas.height);
var fallingCount=0;
for(var i=0;i<blocks.blocks.length;i++){
var block=blocks.blocks[i];
fallingCount+=block.fall();
ctx.fillStyle=block.fill;
ctx.fillRect(block.x,block.y,block.w,block.h);
}
if(fallingCount==0 && blocks.continueRAF){
blocks.continueRAF=false;
alert("All done after "+blocks.blocks.length+" blocks fell.");
}
}
function Block(column){
this.column=column;
this.x=this.column*50;
this.w=parseInt(Math.random()*20+15);
this.h=parseInt(Math.random()*15+5);
this.y=-this.h;
this.vy=parseInt(Math.random()*3+4);
this.fill=randomColor();;
this.isFalling=true;
}
Block.prototype.fall=function(){
if(!this.isFalling){return(0);}
var col=blocks.cols[this.column];
if(this.y+this.h+this.vy>col.maxY){
this.isFalling=false;
this.y=col.maxY-this.h;
col.maxY=this.y;
if(col.maxY>35){
col.needsNewBlock=true;
}
}else{
this.y+=this.vy;
}
return(1);
}
var blocks=new Blocks(350,6);
animate();
function randomColor(){
return('#'+Math.floor(Math.random()*16777215).toString(16));
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=350 height=350></canvas>
</body>
</html>

Related

Image jumping fast when triggered again

Im trying to make the image of a trex jump when canavas is clicked
Here is my code
index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<canvas onclick="canjump = true; renderer = requestAnimationFrame(loop); dinoy = 150;" height="250px" width="350px" style="border: 2px solid black" id="canvas"></canvas>
<img src="./dino.png" height="0px" width="0px" id="dinoimg">
<img src="./cacti.png" height="0px" width="0px" id="cactimg">
<script type="text/javascript" src="./main.js"></script>
</body>
</html>
main.js
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
var dinoimage = document.getElementById('dinoimg');
var dinoheight = 100;
var dinowidth = 50;
var dinox = 0;
var dinoy = 150;
var canjump = false;
var renderer;
var jmpv = 15;
function loop() {
if (canjump = true && dinoy <= 150) {
jumpdino();
} else {
dinoy = 151;
jmpv = 15;
canjump = false;
cancelAnimationFrame(renderer);
}
//setcacti();
//checkcollision();
renderer = requestAnimationFrame(loop);
}
function jumpdino() {
ctx.clearRect(0, 0, 350, 250);
ctx.drawImage(dinoimage, dinox, dinoy, dinowidth, dinoheight);
dinoy -= jmpv;
jmpv--;
}
The problem is that everything work as expected for first time but when canvas is clicked after then (second click and after), the image just go up and come down very fast and not smoothly with acceleration like first time.
Please help!!!
Those two fore function calls are commented because they arent implemented yet.
Just fixing the code you have I added a return in the else, the issue was even though you canceled the requestAnimationFrame after the else condition it still would continue and reassign renderer to the loop. So it was always running, each time you clicked it was just adding another instance making it go faster and faster.
function loop() {
if (canjump = true && dinoy <= 150) {
jumpdino();
} else {
dinoy = 151;
jmpv = 15;
canjump = false;
cancelAnimationFrame(renderer);
// You need to exit out.
return;
}
//setcacti();
//checkcollision();
renderer = requestAnimationFrame(loop);
}
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
var dinoheight = 100;
var dinowidth = 50;
var dinox = 0;
var dinoy = 150;
var canjump = false;
var renderer;
var jmpv = 15;
function loop() {
if (canjump = true && dinoy <= 150) {
jumpdino();
} else {
dinoy = 151;
jmpv = 15;
canjump = false;
cancelAnimationFrame(renderer);
return;
}
//setcacti();
//checkcollision();
renderer = requestAnimationFrame(loop);
}
function jumpdino() {
ctx.clearRect(0, 0, 350, 250);
ctx.fillRect(dinox, dinoy, dinowidth, dinoheight);
dinoy -= jmpv;
jmpv--;
}
<canvas onclick="canjump = true; requestAnimationFrame(loop); dinoy = 150;" height="250px" width="350px" style="border: 2px solid black" id="canvas"></canvas>
Personally I'd remove the inline event handler and do something like this in your code as well.
canvas.addEventListener('click', () => {
canjump = true;
dinoy = 150;
loop();
});

How can I check if an attractor is strange?

Lately I learned a bit about strange attractors, and I created the following programm in JS:
var ctx, clock, width, height, pixSize;
var x,y,a,b,c,d;
window.onload = function(){
start();
};
function start(random=true){
window.cancelAnimationFrame(clock);
if(random){
a = 6*Math.random()-3;
b = 6*Math.random()-3;
c = 2*Math.random()-0.5;
d = 2*Math.random()-0.5;
}
canvasSetup();
clearCanvas();
x = Math.random()-Math.random();
y = Math.random()-Math.random();
clock = requestAnimationFrame(main);
}
function save(){
var text = JSON.stringify({
a:a,
b:b,
c:c,
d:d
});
window.prompt("Copy to clipboard: Ctrl+C", text);
}
function load(){
var input = JSON.parse(window.prompt("Import Save:"));
a = input.a;
b = input.b;
c = input.c;
d = input.d;
start(false);
}
function canvasSetup(){
canvas = document.getElementById('canvas');
width = window.innerWidth-5;
height = window.innerHeight-5;
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext('2d');
var min = Math.min(width,height);
var scale = min/4;
ctx.translate(width/2, height/2);
ctx.scale(scale, scale);
pixSize = 1/scale/2;
ctx.globalCompositeOperation = "lighter";
}
function clearCanvas(){
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0,0,width,height);
ctx.restore();
}
function main(){
for(var i=0;i<10000;i++){
var xnew = Math.sin(y*b)+c*Math.sin(x*b);
var ynew = Math.sin(x*a)+d*Math.sin(y*a);
x = xnew;
y = ynew;
plot(x,y,"rgb(50,5,1)");
}
clock = requestAnimationFrame(main);
}
function plot(x,y,color="white"){
ctx.fillStyle = color;
ctx.fillRect(x,-y,pixSize,pixSize);
}
body {
background-color: black;
color: white;
font-family: Consolas;
font-size: 13px;
margin: 0;
padding: 0;
}
#buttons{
position: absolute;
top: 0;
left: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Strange Attractor</title>
<link rel="stylesheet" href="style.css">
<script src="rules.js"></script>
<script src="script.js"></script>
</head>
<body>
<div align="center">
<canvas id="canvas"></canvas>
</div>
<div id="buttons">
<button onclick="start()">New Attractor</button><br>
<button onclick="save()">Save</button><br>
<button onclick="load()">Load</button>
</div>
</body>
</html>
It's taking 4 random Parameters (a,b,c,d) and uses the formular
var xnew = Math.sin(y*b)+c*Math.sin(x*b);
var ynew = Math.sin(x*a)+d*Math.sin(y*a);
x = xnew;
y = ynew;
for the new point. In some cases this indeed creates a fancy strange sttractor:
But in other cases I only get a single line or a few points. Is there a simple way to look at the parameters and find out, if the attrator they create will be strange?
I know, that I could save a bunch of values, compare them with each other and test in that way, if the picture might be intresting, but I'd love a different solution...
I hope you can help :)
EDIT:
To look at speccific values you can simply use the save and load buttons in the js sketch above...

Referencing canvas with button in Javascript

Ok so I'm attempting to have a webpage with two buttons. Each of these buttons, when clicked, creates a new canvas and calls a different draw function. The first draw function would draw large circles where the users mouse is and small ones when the mouse is pressed. The other draw function does the same thing except small circles when the mouse is unpressed and large ones when it is. I'm not having a problem referencing one of these with the button but the other button doesn't seem to call its draw function. sketch2.js seems to be working fine but it seems that the draw function in sketch.js is not being called. Any advice on how I should go about fixing this is greatly appreciated!
Below is my HTML code:
<html>
<head>
<meta charset="UTF-8">
<button id="myBtn">little then big</button>
<div id="holder"></div>
<button id="myBtn2">big then little</button>
<div id="holder2"></div>
<style> body {padding: 0; margin:0;} </style>
</head>
<body>
<script type="text/javascript" src = "/Users/bburke95/Desktop/JS/p5.dom.js"> </script>
<script language="javascript" type="text/javascript" src="../p5.js"></script>
<script language="javascript" type="text/javascript" src="sketch.js"></script>
<script language="javascript" type="text/javascript" src="sketch2.js"></script>
</body>
</html>
This is my sketch.js class
btn = document.getElementById("myBtn");
var q;
btn.onclick = function setup() {
createCanvas(640, 480);
document.getElementById("holder").innerHTML = '<canvas id="myCanvas" width="490" height="220"></canvas>';
q = 1;
set = 0;
}
function draw() {
if (q == 1) {
var x;
var y;
if (mouseIsPressed) {
fill(255);
x = 160;
y = 160;
} else {
fill(0);
x = 80;
y = 80;
}
ellipse(mouseX, mouseY, x, y);
}
}
and this is my sketch2.js class
btn2 = document.getElementById("myBtn2");
var set;
btn2.onclick = function setup() {
createCanvas(640, 480);
document.getElementById("holder2").innerHTML = '<canvas id="myCanvas2" width="490" height="220"></canvas>';
set = 1;
q = 0;
}
function draw() {
if (set == 1) {
var x;
var y;
if (mouseIsPressed) {
fill(0);
x = 80;
y = 80;
} else {
fill(255);
x = 160;
y = 160;
}
ellipse(mouseX, mouseY, x, y);
}
}
If you want to run more than one P5.js processing sketches on the same page, you have to use "instance mode" to ensure that all the functions aren't cluttering the global namespace (which is a good idea anyway) so they don't overwrite one another.
From their Github project, you can instantiate new sketches like this:
var s = function( p ) {
var x = 100;
var y = 100;
p.setup = function() {
p.createCanvas(700, 410);
};
p.draw = function() {
p.background(0);
p.fill(255);
p.rect(x,y,50,50);
};
};
var myp5 = new p5(s);

How to write a loop so that I will draw to user canvas?

I have a canvas element. I have a few troubles, how to draw to user canvas in "realtime",.. So, that my drawing is not already there when they open the site, but rather to draw to the canvas like somebody is actually drawing... So looping through the coordinates.
That's what I tried so far but it's BAAD! It's drawing slowly and it takes a lot of CPU.
// Pencil Points
var ppts = [];
/* Drawing on Paint App */
tmp_ctx.lineWidth = 4;
tmp_ctx.lineJoin = 'round';
tmp_ctx.lineCap = 'round';
tmp_ctx.strokeStyle = '#4684F6';
tmp_ctx.fillStyle = '#4684F6';
// Tmp canvas is always cleared up before drawing.
tmp_ctx.clearRect(0, 0, tmp_canvas.width, tmp_canvas.height);
tmp_ctx.beginPath();
var timer = 0;
$.timer(500, function() {
ppts.push({x: 10*timer, y: 5*timer});
timer++;
})
$.timer(10, function() {
if (timer > 250) {
timer = 0;
clearTempCanvas();
} else {
for (var i = 1; i < ppts.length - 2; i++) {
var c = (ppts[i].x + ppts[i + 1].x) / 2;
var d = (ppts[i].y + ppts[i + 1].y) / 2;
tmp_ctx.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d);
}
console.log(i);
tmp_ctx.stroke();
}
})
function clearTempCanvas() {
// Writing down to real canvas now
ctx.drawImage(tmp_canvas, 0, 0);
// Clearing tmp canvas
tmp_ctx.clearRect(0, 0, tmp_canvas.width, tmp_canvas.height);
// Emptying up Pencil Points
ppts = [];
}
Here's an example for you to learn from: http://jsfiddle.net/m1erickson/j4HWS/
It works like this:
define some points to animate along and put those points in an array points.push({x:25,y:50})
use requestAnimationFrame to create an animation loop
break each line segment into 100 sub-segments and animate along those sub-segments
Example code:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" />
<script src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.lineWidth=2;
ctx.strokeStyle="blue";
var points=[];
points.push({x:125,y:125});
points.push({x:250,y:200});
points.push({x:125,y:200});
points.push({x:125,y:125});
var pointIndex=1;
var linePct=0;
var continueAnimating=true;
var img=new Image();img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/pen.png";
function start(){
animate();
}
function draw(pointIndex,linePct){
// clear the canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
// draw fully completed lines
ctx.beginPath();
ctx.moveTo(points[0].x,points[0].y);
for(var i=1;i<pointIndex;i++){
ctx.lineTo(points[i].x,points[i].y);
}
// draw current line-in-process
var pos=getLineXYatPercent(points[pointIndex-1],points[pointIndex],linePct/100);
ctx.lineTo(pos.x,pos.y);
ctx.stroke();
// draw the pen
ctx.drawImage(img,pos.x-93,pos.y-92);
}
function animate() {
if(!continueAnimating){return;}
requestAnimationFrame(animate);
// Drawing code goes here
draw(pointIndex,linePct);
if(++linePct>100){
linePct=1;
if(++pointIndex>points.length-1){
continueAnimating=false;
}
}
}
function getLineXYatPercent(startPt,endPt,percent) {
var dx = endPt.x-startPt.x;
var dy = endPt.y-startPt.y;
var X = startPt.x + dx*percent;
var Y = startPt.y + dy*percent;
return( {x:X,y:Y} );
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=350 height=350></canvas>
</body>
</html>

Canvas waving flag HTML5

I need a little help about canvas and HTML5.
I have this code
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>HTML Canvas Flag Wave</title>
<style type="text/css" media="screen">
body { background:#eee }
#flag { position:absolute; top:50%; left:50% }
</style>
<script type="text/javascript">
var h = new Image;
h.onload = function(){
var flag = document.getElementById('flag');
var amp = 20;
flag.width = h.width;
flag.height = h.height + amp*2;
flag.getContext('2d').drawImage(h,0,amp,h.width,h.height);
flag.style.marginLeft = -(flag.width/2)+'px';
flag.style.marginTop = -(flag.height/2)+'px';
var timer = waveFlag( flag, h.width/10, amp );
};
h.src = 'gkhead.jpg';
function waveFlag( canvas, wavelength, amplitude, period, shading, squeeze ){
if (!squeeze) squeeze = 0;
if (!shading) shading = 100;
if (!period) period = 200;
if (!amplitude) amplitude = 10;
if (!wavelength) wavelength = canvas.width/10;
var fps = 30;
var ctx = canvas.getContext('2d');
var w = canvas.width, h = canvas.height;
var od = ctx.getImageData(0,0,w,h).data;
// var ct = 0, st=new Date;
return setInterval(function(){
var id = ctx.getImageData(0,0,w,h);
var d = id.data;
var now = (new Date)/period;
for (var y=0;y<h;++y){
var lastO=0,shade=0;
var sq = (y-h/2)*squeeze;
for (var x=0;x<w;++x){
var px = (y*w + x)*4;
var pct = x/w;
var o = Math.sin(x/wavelength-now)*amplitude*pct;
var y2 = y + (o+sq*pct)<<0;
var opx = (y2*w + x)*4;
shade = (o-lastO)*shading;
d[px ] = od[opx ]+shade;
d[px+1] = od[opx+1]+shade;
d[px+2] = od[opx+2]+shade;
d[px+3] = od[opx+3];
lastO = o;
}
}
ctx.putImageData(id,0,0);
// if ((++ct)%100 == 0) console.log( 1000 * ct / (new Date - st));
},1000/fps);
}
</script>
</head>
<body>
<canvas id="flag"></canvas>
</body>
</html>
The result is this:
http://www.americkiplakari.org/zastavanovo.html
Nice waving flag, but I have a problem, I'm not so good with canvas. I want to rotate canvas, I want to top of image be fixed and waves goes from top to bottom, is it possible to do that.
Ok here is simple solution, just rotate with CSS3, put canvas in another div and you are ready to go go....
<style type="text/css" media="screen">
body { background:#eee }
#flagunustra { position:absolute; top:50%; left:50% }
#flag{
margin-top:250px;
width:414px;
transform:rotate(90deg);
-ms-transform:rotate(90deg); /* IE 9 */
-moz-transform:rotate(90deg); /* Firefox */
-webkit-transform:rotate(90deg); /* Safari and Chrome */
-o-transform:rotate(90deg); /* Opera */
}
</style>
<div id="flagunustra">
<canvas id="flag"></canvas></div>

Categories