resetting canvas strokes each re-iteration through the function(animation). how? - javascript

At the moment the lines stick permanently creating a drawing. I want the line to be drawm and reset everytime the function is called via setInterval() therefore creating a brain-wave ripple like animation.
Here's my current source code:
var rippleEffect = function(){
var co = [];
for(var i=0; i<=5; i++){
var r = Math.floor(Math.random()*250);
co.push(r);
//each time through the loop throws/pushes 6 random numbers to array 'co' for bezier curve.
}
var canvas = document.getElementById('brainWave');
var context = canvas.getContext('2d');
context.beginPath();
context.moveTo(500, 75);
context.bezierCurveTo(co[0], co[1], co[2], co[3], co[4], co[5]);
context.lineWidth = 2;
// line color
context.strokeStyle = '#444';
context.stroke(); //exicute the stroke based on the structions we've provided.
};
setInterval(ripple,100); //this re-calls the functions every few miller-seconds.
is .clearRect() some part of the solution?

I'm not quite sure what you're trying to do, but here are some observations on your code:
clearRect is essential if you don't want the drawings to accumulate on top of each other.
setInterval is calling "ripple", but it should be calling "rippleEffect".
var canvas and var context should be pulled outside-before rippleEffect (they just need to be created once, not with every loop.
Totally random control points for a Bezier curve yields spaghetti, not brain-waves.
Good luck with your project :)

Related

Constant not staying constant?

I made a code with the intention of having a square appear where the mouse is pressed down, stay in that spot despite mouse movement and not disappear when the mouse it released.
THIS IS P5.JS ! https://p5js.org/reference/
Instead, the square follows the mouse until it is released then it disappears!
I believe that my code keeps declaring a new constant and deleting the old one every time the shoot() function is run.
var clocker = 0;// NOT YET USED
var player = {
x:400,
y:400,
};
function shoot(x1, y1, x2, y2, speed, range, power, playerDirection){
var bulletAlive = true;
var bulletDamage = power;
const startX = x1;
const startY = y1;
const destX = x2;
const destY = y2;
var bulletX = startX;
var bulletY = startY;
if(bulletAlive){
fill(0,100,200);
rect(destX-12.5,destY-12.5,25,25);
};
};
function setup() {
createCanvas(1000,650);
}
function draw() {
background(204,204,204);
if(mouseIsPressed){
shoot(player.x,player.y,mouseX,mouseY,2,100,0,"right");
}
}
Perhaps I am using const wrong. If so how should I use it? How can I make it so that destX and destY don't change? (Don't follow mouse or disappear)
PS: sorry for the miscellaneous information, this is supposed to build up to simple bullet physics.
It sounds like there is some confusion about scoping, and there is probably a better way to think about this problem.
First let's look at what is going wrong, and talk through a few details to explain why.
Just like variables (let, var), constants are always declared in a specific scope.
Scopes are like containers for constants and variables. Scopes are private, that is they cannot be accessed from the outside. Scopes can be created and destroyed.
When you declare a constant directly inside a function, the scope is the function itself (like startX inside shoot). (Note that if you declare a constant inside an if statement or other block, the scope is the block. That's not the case here, though.)
Function scopes are created each time the function is called, and destroyed when the function is finished executing.
Each time a function is called and its scope is created, all constants (and variables) are reinitialized with new values.
A constant appearing in your code may have different values during different function calls. It is only constant during its lifetime, which in your case is a single given execution of the function.
This is why your constants aren't staying constant. You are calling shoot() repeatedly while the mouse is down, and so the constants are repeatedly being recreated and assigned new values.
With this information, hopefully you can see the problems with the current approach. As for a solution, let's think about what exactly is happening. shoot() is an action that should be triggered when the user issues a "shoot" command, such as a mouse click. The draw() function is a continuous event triggered to say "hey, update the screen". Putting the shoot action inside the draw event is kind of a mis-match of intentions and is the root of struggles like this.
Instead, let's introduce the idea of a bullet object. A bullet has an x and a y value. A bullet is created when the user shoots, and is given a specific x and y value at the moment of creation. None of this happens inside draw, it happens in another event listener such as "click".
The job of draw is to check to see if there is an active bullet, and if there is one, draw it at the specified x and y coordinate. If there is no bullet, do nothing. (Of course you might need to draw other things as well, but that's unrelated to drawing the bullet).
Keeping object creation and object drawing separate makes it easier to have the kind of control you're looking for.
Edit: Adding some code examples
Here's what the code would look like to do exactly what you asked, using the bullet object idea above. The inline comments should explain each step.
// This is where we'll store an active bullet object.
// The `shoot()` function is responsible for setting this.
// `draw()` is responsible for rendering the bullet.
// Initially we'll set the value to `null` to explicitly
// indicate that there is no bullet.
let activeBullet = null;
// The purpose of `shoot()` is to create a bullet
// and make it available to be rendered.
function shoot(x, y) {
// Create the bullet object.
const newBullet = {
x: x,
y: y,
size: 25
};
// Set the active bullet to the new bullet. This will
// cause any previously active bullet to disappear.
activeBullet = newBullet;
}
// P5 functions
// ------------
function setup() {
createCanvas(1000, 650);
}
// Shoot when the player clicks.
function mousePressed() {
shoot(mouseX, mouseY);
}
function draw() {
// Always start with a blank canvas.
clear();
// If there is an active bullet, draw it!
// (`null` is "falsy", objects are "truthy", so the
// `if` statement will only run after the `activeBullet`
// variable is assigned a bullet object.)
if (activeBullet) {
fill(0, 100, 200);
rect(
activeBullet.x - activeBullet.size / 2,
activeBullet.y - activeBullet.size / 2,
activeBullet.size,
activeBullet.size
);
}
}
You also mentioned you wanted to build up to simple bullet physics. Just to show how the bullet object idea works nicely, here's a demo where you can click to shoot multiple bullets, they all move independently, and collide with a wall at which point they are removed. There's a lot more involved in building games, but hopefully it's an inspiring starting point :)
// Store canvas dimensions globally so we have easy access.
const canvasWidth = 1000;
const canvasHeight = 650;
// We'll add a "wall" object so we have something the bullets can
// collide with. This value is the X position of the wall.
const wallX = canvasWidth - 200;
// Instead of a single bullet, using an array can accommodate
// multiple bullets. It's empty to start, which means no bullets.
// We can also use `const` for this, because we won't ever assign
// a new value, we'll only modify the contents of the array.
const activeBullets = [];
function shoot(x, y) {
// Create the bullet object.
const newBullet = {
x: x,
y: y,
size: 25,
speed: 4
};
// Instead of overwriting a single bullet variable, we'll push
// the new bullet onto an array of bullets so multiple can exist.
activeBullets.push(newBullet);
}
// P5 functions
// ------------
function setup() {
createCanvas(canvasWidth, canvasHeight);
}
// Shoot when the player clicks.
function mousePressed() {
shoot(mouseX, mouseY);
}
function draw() {
// Always start with a blank canvas.
clear();
// Draw our "wall".
fill(50);
rect(wallX, 0, 60, canvasHeight);
// Set the fill color once, to use for all bullets. This doesn't
// need to be set for each bullet.
fill(0, 100, 200);
// Loop through the array of bullets and draw each one, while also
// checking for collisions with the wall so we can remove them. By
// looping backwards, we can safely remove bullets from the array
// without changing the index of the next bullet in line.
for (let i=activeBullets.length-1; i>=0; i--) {
// Grab the current bullet we're operating on.
const bullet = activeBullets[i];
// Move the bullet horizontally.
bullet.x += bullet.speed;
// Check if the bullet has visually gone past the wall. This
// means a collision.
if (bullet.x + bullet.size / 2 > wallX) {
// If the bullet has collided, remove it and don't draw it.
activeBullets.splice(i, 1);
} else {
// If the bullet hasn't collided, draw it.
rect(
bullet.x - bullet.size / 2,
bullet.y - bullet.size / 2,
bullet.size,
bullet.size
);
}
}
}
The const declaration exists only within the scope of shoot. So once the shoot function is finished executing, startX startY destX destY, being const, are deleted.
Possible fix:
var didShootAlready = false;
var startX, startY, destX, destY;
function shoot(/*params*/){
if(!didShootAlready){
didShootAlready = true;
startX = x1;
startY = y1;
destX = x2;
destY = y2;
}
//do the rest
}

Pong game in p5.js - background image not loading properly

I'm using a javascript framework called p5. I'm trying to set the background of my Pong game to an image I found online. I followed all references I could find to try to get it to work, but for some reason the background doesn't update itself. I end up getting a line of chickens (the ball of my game). The only part of the background that seems to work properly is the top left corner.
var sticks = [];
var ball;
var wallDis = 50;
// var imgs = [];
var score = [];
function preload(){
chick = loadImage('images/chick.png');
farm = loadImage('images/Farm.jpg');
}
function setup(){
createCanvas(600, 600);
sticks[0] = new Stick([enter image description here][1]wallDis);
sticks[1] = new Stick(width-wallDis);
ball = new Ball(chick);
score[0] = new ScoreBoard(width/3, 50);
score[1] = new ScoreBoard(width*2/3, 50);
}
function draw(){
background(farm);
// resizeCanvas(img.width, img.height);
for(var i =0; i<sticks.length; i++){
sticks[i].move();
sticks[i].show();
}
ball.move();
ball.show();
... etc
The background() function doesn't stretch the image to fit the size of the canvas. From the reference, emphasis mine:
p5.Image: image created with loadImage() or createImage(), to set as background (must be same size as the sketch window)
That's why you're seeing the image in the upper-left corner.
To fix your problem, just resize the image to be the same size as your sketch. You can do that ahead of time, or there are handy functions in the reference you could use as well.

HTML5 Canvas image rotation with dynamic values and images

I have the following code -
for(var i = 0; i < treesLength; i++){
var tmpTree = trees[i];
tmpTreeX = 1+Math.random()*($("#gameBoard").width()-95);
tmpTreeY = 1+Math.random()*($("#gameBoard").height()-90);
var imgTreeFile = new Image();
imgTreeFile.onload = function() {
context.save();
context.translate(tmpTreeX,tmpTreeY);
context.rotate(47 * Math.PI / 180);
context.translate(-tmpTreeX,-tmpTreeY);
context.drawImage(imgTreeFile, tmpTreeX, tmpTreeY);
context.restore();
};
imgTreeFile.src = 'img/tree.png';
}
What I am trying to achieve is to add 'n' amount of images to the canvas (That happen to be trees) I want to rotate the images a random amount of radians. Currently just to get it working I have set this number rather than randomly generate the radians.
If I do no try to rotate the images, I successfully get all the images in the loop randomly placed throughout the canvas. When I try to rotate I just get all of the images in the same place with no rotation.
Can anyone point me in the right direction, my searching has only left me frustrated as I "appear" to be doing it correctly (Clearly I am not!)
In a quick test here there doesn't seem to be an issue: http://jsfiddle.net/ZZ7MQ/
But I do notice two weird things about your code:
.width() and not .width seems weird, but maybe thats a jQuery thing? it should be canvas.width in any case.
You are using a loop variable inside of code called asynchronously, which is 99% likely your problem. I highly recommend that you refactor your code so that all the images are loaded before the loop ever happens. If they are all the same image, that makes this very easy:
var imgTreeFile = new Image();
imgTreeFile.onload = function() {
for(var i = 0; i < treesLength; i++){
var tmpTree = trees[i];
tmpTreeX = 1+Math.random()*($("#gameBoard").width()-95);
tmpTreeY = 1+Math.random()*($("#gameBoard").height()-90);
context.save();
context.translate(tmpTreeX,tmpTreeY);
context.rotate(47 * Math.PI / 180);
context.translate(-tmpTreeX,-tmpTreeY);
context.drawImage(imgTreeFile, tmpTreeX, tmpTreeY);
context.restore();
}
};
imgTreeFile.src = 'img/tree.png';

Collision Detection with Javascript, Canvas, and Alpha Detection

I'm currently working on a basic javascript game that has two sprites that are not to be collided together. However, basic bounding box collision won't suffice as there are portions of the sprites that are transparent and wouldn't 'count' as colliding. I found a solution to the problem that I am having, but I can't get it to work. What I would like to do is calculate the transparent portions of the sprites and make sure that if the transparent portions overlap, that there is no collision detected. Here is what I found that solves the problem.
http://blog.weeblog.net/?p=40#comments
/**
* Requires the size of the collision rectangle [width, height]
* and the position within the respective source images [srcx, srcy]
*
* Returns true if two overlapping pixels have non-zero alpha channel
* values (i.e. there are two vissible overlapping pixels)
*/
function pixelCheck(spriteA, spriteB, srcxA, srcyA, srcxB, srcyB, width, height){
var dataA = spriteA.getImageData();
var dataB = spriteB.getImageData();
for(var x=0; x<width; x++){
for(var y=0; y<height; y++){
if( (dataA[srcxA+x][srcyA+y] > 0) && (dataB[srcxB+x][srcyB+y] > 0) ){
return true;
}
}
}
return false;
}
And for calculating the image data:
/**
* creating a temporary canvas to retrieve the alpha channel pixel
* information of the provided image
*/
function createImageData(image){
$('binaryCanvas').appendTo('body');
var canvas = document.getElementById('binaryCanvas');
var ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0);
var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var imageData = [image.width];
for(var x=0; x<image.width; x++){
imageData[x] = [image.height];
for(var y=0; y<image.height; y++){
var idx = (x + y * image.width) * 4;
imageData[x][y] = canvasData.data[idx+3];
}
}
$("#binaryCanvas").remove();
return imageData;
}
The problem is that I don't know how to implement this solution, or if this is the best solution to my problem. Is this what I'm looking for? And if so, where do I put these methods? The thing that I'm most confused about is what I should be passing to spriteA and spriteB. I've tried passing Images and I've tried passing the imageData returned from the pixelCheck method, but receiving the same error: that the object or image has no method 'getImageData'. What am I doing wrong?
Two things are wrong with this.
You made a function:
function createImageData(image){...}
But what you are calling is:
spriteA.getImageData();
spriteB.getImageData();
The dot notates a property of an object. You were trying to call a function that was never part to the objects. There are some simple fixes.
add the createImageData() function to your constructor :
function Sprite(){
...
this.createImageData = function(image){...};
...
}
or :
Sprite.createImageData = function(image{...};
or just call it correctly:
createImageData(spriteA.image); // or whatever the image is
Second, your function calls for an image parameter, but you aren't supplying one. Simply remember to supply the image when you call it. You could also remove the parameter and get the image from within the function.
Sort of like this:
function Sprite(){
...
this.createImageData = function(){
var image = this.image;
// or just use this.image, or whatever it is
...
}
...
}
Hope this helped.

Image appearing multiple times on canvas?

I'm drawing a simple dynamic canvas and I'm wondering how I can make the .png file in my drawImage method appear like 40 times at different places on my canvas at the same time?
Thanks beforehand! :)
Thank you all very much for your reply! This is as far as I've gotten now:
<script type="text/javascript">
var ctx;
var imgBg;
var imgDrops;
var x = 40;
var y = 0;
function setup() {
var canvas = document.getElementById('canvasRegn');
if (canvas.getContext) {
ctx = canvas.getContext('2d');
setInterval('draw();', 36);
imgBg = new Image();
imgBg.src = 'dimma.jpg';
imgDrops = new Image();
imgDrops.src = 'drop.png';
}
}
function draw() {
drawBackground();
for(var i=0; i <= 40; i++) {
ctx.drawImage (imgDrops, x, y);
y += 3;
if(y > 450)
y = -20;
x=Math.random()*600;
}
}
function drawBackground(){
ctx.drawImage(imgBg, 0, 0);
}
</script>
My problem is now that the images are jumping all over the place... I want them "falling" down slowly from above and coming back around:(
Have a look at this fiddle http://jsfiddle.net/joevallender/D83uC/10/
I made it to explain some basics of canvas to a friend recently. Although I'm using shapes instead of .png files I think the loop you are looking for is the same.
The key bit of code being this loop below
setInterval(function(){
// clear stage
context.clearRect(0, 0, width, height);
for(var i = 0; i < balls.length; i++) {
balls[i].move(balls);
}
}, 1000/FPS)
FPS is a variable, and .move() is a function that calculated new co-ordinates for and then re-draws the ball object.
I think it might simply not clearing the 'stage' context.clearRect(0, 0, width, height);
EDIT Perhaps that example had too much going on in it to be useful.
Please see a much earlier version http://jsfiddle.net/joevallender/D83uC/2 that simple animates the ball. The main point remains though, you need to clear the canvas if you don't want the 'trails'
Think of canvas like windows paint, not flash. The things you have drawn aren't editable objects. You need to redraw the whole thing each time. (Unless you use a JS library that makes things seem more like flash - but I'm guessing you want to learn without helper libraries at first)
As I said, I was explaining canvas to someone recently and you can see the various stages between the two links I've sent you by changing the number on the end of the URL http://jsfiddle.net/joevallender/D83uC/3
http://jsfiddle.net/joevallender/D83uC/4
etc.
EDIT2
Or if I've misunderstood, post a jsfiddle and let us know what is wrong with it
This is what you need: http://edumax.org.ro/extra/new/imagetut/
You can get the code here: http://edumax.org.ro/extra/new/imagetut/script.js
The relevant part is this:
function draw_image(){
//draw one image code
}
window.onload = function () {
for (var i=0;i<10;i++){
for (var j=0;j<10;j++){
draw_image(10+i*40, 10+j*40, 40, 40);
}
}
}
This code only explains the concept, it will not work by itself, for a full version check the link above.

Categories