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.
Related
Why can't the images be defined in an array as shown here.
Why is it necessary push a new Image object in the array every time?
var canvas = null;
var ctx = null;
var assets = [
'/media/img/gamedev/robowalk/robowalk00.png',
'/media/img/gamedev/robowalk/robowalk01.png',
'/media/img/gamedev/robowalk/robowalk02.png',
'/media/img/gamedev/robowalk/robowalk03.png',
'/media/img/gamedev/robowalk/robowalk04.png',
'/media/img/gamedev/robowalk/robowalk05.png',
'/media/img/gamedev/robowalk/robowalk06.png',
'/media/img/gamedev/robowalk/robowalk07.png',
'/media/img/gamedev/robowalk/robowalk08.png',
'/media/img/gamedev/robowalk/robowalk09.png',
'/media/img/gamedev/robowalk/robowalk10.png',
'/media/img/gamedev/robowalk/robowalk11.png',
'/media/img/gamedev/robowalk/robowalk12.png',
'/media/img/gamedev/robowalk/robowalk13.png',
'/media/img/gamedev/robowalk/robowalk14.png',
'/media/img/gamedev/robowalk/robowalk15.png',
'/media/img/gamedev/robowalk/robowalk16.png',
'/media/img/gamedev/robowalk/robowalk17.png',
'/media/img/gamedev/robowalk/robowalk18.png'
];
var frames = [];
var onImageLoad = function() {
console.log("IMAGE!!!");
};
var setup = function() {
j=0;
body = document.getElementById('body');
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
canvas.width = 100;
canvas.height = 100;
body.appendChild(canvas);
for (i = 0; i <= assets.length - 1; ++i) {
frames[i].src = assets[i];
}
setInterval(animate,30);
}
var animate = function() {
ctx.clearRect(0,0,canvas.width,canvas.height);
if (j >= assets.length) {
j=0;
}
var image = new Image();
image.src = frames[j];
ctx.drawImage(image,0,0);
++j;
}
The first reason is to reduce latency. Putting only the URLs into an array means that images have not been pre-fetched before the animation starts. The first round of animation is going to be slow and jerky as each image is retrieved from the net. If the animation is repeated, the next round will be faster. This consideration mostly applies to animations which replaced image elements on the page (in the DOM) rather than by writing to a canvas.
The second reason is to remove overhead and improve efficiency in the animation loop. Using new Image() inside the loop means that drawing time for each frame includes the time taken to create a new Image object as well as draw it on the canvas. In addition the image content can only be written to the canvas after it has been fetched, making it necessary to write to the canvas from an onload handler attached to the image object. The posted code does not do this and could throw an error in some browsers trying to synchronously write an image with no data to the canvas. Even if otherwise successful, repeated animations would be creating a new Image object each time a frame is displayed and churning memory usage.
Note the original version probably used onImageLoad to check when the image has been fully loaded from the web before pushing the object into an array of preloaded image objects. This is the preferred method of prefetching animation images.
And don't forget to define j before use :-)
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 :)
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';
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.
I'm interested in moving a pixel (eventually all of them) from an image drawn on canvas. This is the sample code i'm working off and i believe it does some pretty standard stuff in terms of drawing the image:
var images = [ // predefined array of used images
'http://distilleryimage6.instagram.com/928c49ec07d411e19896123138142014_7.jpg'
];
var iActiveImage = 0;
$(function(){
// drawing active image
var image = new Image();
image.onload = function () {
ctx.drawImage(image, 0, 0, image.width, image.height); // draw the image on the canvas
}
image.src = images[iActiveImage];
// creating canvas object
canvas = document.getElementById('panel');
ctx = canvas.getContext('2d');
console.log(ctx);
var imageData = ctx.getImageData(200, 150, 1, 1);
var pixel = imageData.data;
});
So i have this but could someone point me in the right direction of doing something like picking a pixel at random from the image and physically moving it somewhere else on the page? Is this possible?
Thanks
I'm not sure what you mean by "physically moving it", but you can use ctx.putImageData() to apply the pixel elsewhere inside the canvas.
var imageData = ctx.getImageData(200, 150, 1, 1);
var pixel = imageData.data;
// You can even get or set the color or alpha of the pixel. (values between 0-255)
var r = pixel[0];
var g = pixel[1];
var b = pixel[2];
var a = pixel[3];
ctx.putImageData(imageData, x, y); // Where x y are the new coordinates.
Also, you should put all this imageData manipulation inside the onload function, because in your example, the image is still not loaded when you call ctx.getImageData(), so you're manipulating blank pixels.
Note also that for security reason, you cannot use getImageData() on an image loaded from a different domain. So I think your example will throw an exception of type Uncaught Error: SECURITY_ERR: DOM Exception 18, because the image is loaded from Instagram.
I think this tutorial might help you:
https://developer.mozilla.org/en/Canvas_tutorial/Basic_animations