I have a bird={} object where I define a draw function, however the image does not appear when called in the render function. Could anyone point me to what Im doing wrong? Thanks in advance.
EDIT: I have noticed the reason it does not always show up is because there are other sprites on the screen, and when I turn them off the bird always show up. Is there anything that can fix this?
bird = {
draw:function() {
var birdimg = new Image();
birdimg.onload = function() {
ctx.drawImage(birdimg, -20, height - 200);
}
birdimg.src = "//i.stack.imgur.com/nsZLM.png"; //"assets/bird.png";
}
};
function main() {
canvas = document.createElement("canvas");
//Set the width and height to the sizes of the browser
width = window.innerWidth;
height = window.innerHeight;
//Frames the game if the width is larger than 500
if(width >=500){
width = 320;
height = 480;
canvas.style.border = "1px solid #000";
evt = "mousedown";
}
//Sets the canvas sizes to the width and height variables
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext("2d");
//Set the default state
currentstate = states.Splash;
document.body.appendChild(canvas);
render();
}
function render(){
//Adding bird
bird.draw();
//Loads sky.png
bgimg = new Image();
bgimg.onload = function() {
ctx.drawImage(bgimg,-20,height-200);
ctx.drawImage(bgimg,256,height-200);
}
bgimg.src = "assets/sky.png";
//Loads land img
landimg = new Image();
landimg.onload = function() {
ctx.drawImage(landimg,0,height-100);
}
landimg.src = "assets/land.png";
//Creates rectangle that colors background. THIS IS THE BOTTOM LAYER. WRITE CODE ABOVE
ctx.fillStyle="#4ec0ca";
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.stroke();
}
Following #K3N's suggestions here is a working example. Thanks #K3N for the guidance.
With these changes your code would look something like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script>
// declare vars so they are available outside of main()
var canvas,
ctx,
width,
height;
var bird = {
draw: function() {
var birdimg = new Image();
birdimg.src ="http://www.jqueryscript.net/images/Simplest-Responsive-jQuery-Image-Lightbox-Plugin-simple-lightbox.jpg";
birdimg.onload = function() {
ctx.drawImage(birdimg, -20, height - 200);
};
}
};
function main(){
canvas = document.createElement("canvas");
//Set the width and height to the sizes of the browser
width = window.innerWidth;
height = window.innerHeight;
//Frames the game if the width is larger than 500
if(width >=500){
width = 320;
height = 480;
canvas.style.border = "1px solid #000";
var evt = "mousedown";
}
//Sets the canvas sizes to the width and height variables
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext("2d");
//Set the default state
// "states" is not defined so I'm commenting this out
// var currentstate = states.Splash;
document.body.appendChild(canvas);
render();
}
main();
function render(){
//Adding bird
bird.draw();
}
</script>
</body>
</html>
Live Demo
Hope this helps,
Nick Leoutsakos
Related
I'm trying to make a web game based on canvas and vanilla JS, but i'm struggling with displaying my canvas on mobile devices. On window.onload I'm assignin window height and width to the canvas dimensions. On PC it looks and works great but unfortunately while displayin on phone I have some bad white spaces under it or left site.
const CANVAS_ID = "game";
let canvas, canvasContext;
let bullets = [];
window.onload = function(){
resizeCanvas();
canvas = document.getElementById(CANVAS_ID);
canvasContext = canvas.getContext('2d');
resetGame();
document.getElementById('overlay').style.display = "none";
}
function resizeCanvas (){
let canvas = document.getElementById(CANVAS_ID);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
function resetGame (){
colorRect (0,0, canvas.width,canvas.height, "black");
canvasContext.font = "100px Arial";
//colorText("Welcome", 100, canvas.height/2, "white");
setInterval(drawGame, 1000/60);
setInterval(spawnBullet, 100);
}
Do you have any ideas what should I do?
Edit.
I have <meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1; user-scalable=0;"/> this tag.Is it correct?
I'm trying to make a little game to play around with canvas. I've decided to go for Flappy Bird as there are plenty of examples online. My goal was to make the game "responsive" for all devices. If you open it in a mobile or whichever screen, you should be able to play it normally.
For this purpose I drew a background image within the canvas that will adapt the height to the screen's height and repeat it through the x-axis.
The issue I'm having is that, when I animate the bird, this one leaves a trail behind it.
As like so:
An easy fix would be clearing the canvas as explained in this post:
Canvas image leaves weird trail when moving left
But it isn't possible because of the way I'm painting my background (I paint it once and repaint it if it resizes).
Question
How do I avoid this image trail with a static background? Is it maybe possible to have like a false static background that doesn't need to be repainted?
I obviously want to do it in the canvas, without needing to have an image in the html.
This is the code with the main functionality so that you can take a look:
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
cvs.style.height = "100vh";
cvs.style.width = "100vw";
var bird = new Image();
var bg = new Image();
bird.src = "https://lh3.googleusercontent.com/prntPuix7QxlhKXx6IBtTxv7PrdEJtmzFJ4mopScNS1_klze86BVNy3PqHbQn2UQ4JyJdix3XQ=w128-h128-e365";
bg.src = "https://opengameart.org/sites/default/files/bg_5.png";
let gravity = 1;
birdPositionY = 10;
birdPositionX = 50;
const draw = () => {
ctx.drawImage(bird, birdPositionX, birdPositionY);
birdPositionY += gravity;
birdPositionX += 3;
requestAnimationFrame(draw);
};
const resizeCanvas = () => {
const {
width,
height
} = cvs.getBoundingClientRect();
cvs.height = height;
cvs.width = width;
let x = 0,
y = 0;
while (x < cvs.width && y < cvs.height) {
ctx.drawImage(bg, x, y, 360, cvs.height);
x += bg.width;
}
};
bg.onload = () => {
resizeCanvas();
};
window.addEventListener("resize", resizeCanvas, false);
draw();
<!DOCTYPE html>
<html>
<head>
<title>Flappy Bird</title>
<meta name="viewport" content="width=device-width, user-scalable=no" />
<style>
html {
overflow: hidden;
}
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="index.js"></script>
</body>
</html>
Hope it did make sense!
Thanks in advance!
Draw your background on a canvas that you will keep off-screen, then draw this canvas every frame on your visible one before you draw your moving parts.
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
// our backround canvas that we won't append in the doc ("off-screen")
const background = cvs.cloneNode();
const bg_ctx = background.getContext('2d');
cvs.style.height = "100vh";
cvs.style.width = "100vw";
var bird = new Image();
var bg = new Image();
bird.src = "https://lh3.googleusercontent.com/prntPuix7QxlhKXx6IBtTxv7PrdEJtmzFJ4mopScNS1_klze86BVNy3PqHbQn2UQ4JyJdix3XQ=w128-h128-e365";
bg.src = "https://opengameart.org/sites/default/files/bg_5.png";
let gravity = 1;
birdPositionY = 10;
birdPositionX = 50;
const draw = () => {
// first draw the background canvas
ctx.drawImage(background, 0,0);
// then your persona
ctx.drawImage(bird, birdPositionX, birdPositionY);
birdPositionY += gravity;
birdPositionX += 3;
requestAnimationFrame(draw);
};
const resizeCanvas = () => {
const {
width,
height
} = cvs.getBoundingClientRect();
// resize both canvases
cvs.height = background.height = height;
cvs.width = background.width = width;
let x = 0,
y = 0;
while (x < cvs.width && y < cvs.height) {
// draw on the off-screen canvas
bg_ctx.drawImage(bg, x, y, 360, cvs.height);
x += bg.width;
}
};
bg.onload = () => {
resizeCanvas();
draw();
};
window.addEventListener("resize", resizeCanvas, false);
<!DOCTYPE html>
<html>
<head>
<title>Flappy Bird</title>
<meta name="viewport" content="width=device-width, user-scalable=no" />
<style>
html {
overflow: hidden;
}
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="index.js"></script>
</body>
</html>
I think you could just call resizeCanvas in your draw loop to redraw the background.
EDIT: Apparently that does not work. Another option is just drawing it in the draw loop like this:
const draw = () => {
ctx.clearRect(0, 0, cvs.width, cvs.height)
let x = 0, y = 0;
while (x < cvs.width && y < cvs.height) {
ctx.drawImage(bg, x, y, 360, cvs.height);
x += bg.width;
}
ctx.drawImage(bird, birdPositionX, birdPositionY);
birdPositionY += gravity;
birdPositionX += 3;
requestAnimationFrame(draw);
};
Edit: That did not work either. The other option would be to make two canvases and overlap them with one drawing the background and one drawing the bird.
I'm trying to create a canvas where I have an image as a background that repeats horizontally and adapts the height automatically.
I've managed to repeat the background image following the x-axis but I'm unable to make the height responsive.
This is my code so far:
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
const bg = new Image();
bg.src = "http://lorempixel.com/100/100";
const draw = () => {
const ptrn = ctx.createPattern(bg, "repeat-x");
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, canvas.width, canvas.height);
requestAnimationFrame(draw);
};
draw();
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<canvas id="canvas" width="1000" height="200"></canvas>
<script src="index.js"></script>
</body>
</html>
TLDR: I would like to be able to have an image within my canvas that repeats horizontally and its height is responsive.
Thanks in advance.
Hopefully the explanation in the comments answers your question. Feel free to ask for clarification.
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
// First stretch the canvas so we can get
// the full size of teh browser window
cvs.style.height = '100vh';
cvs.style.width = '100vw';
// Now adjust actual canvas size to match
const {width, height} = cvs.getBoundingClientRect();
cvs.height = height;
cvs.width = width;
const bg = new Image();
// Should always wait for onload
// before drawing to prevent race condition.
bg.onload = ()=>{
var x=0;
while(x < cvs.width){
ctx.drawImage(bg, x, 0, 100, cvs.height);
x += bg.width;
}
// draw the image a bunch of times
// var x=0, y=0;
// while(x < cvs.width && y < cvs.height){
// ctx.drawImage(bg, x, y);
// x += bg.width;
// if(x > cvs.width){
// x = 0;
// y += bg.height;
// }
// }
};
bg.src = "http://lorempixel.com/100/100";
<canvas id="canvas"></canvas>
<script src="index.js"></script>
If I got it right you want to fill the height and repeat horizontally, is that correct?
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
var bg = new Image();
bg.src = "http://lorempixel.com/100/100";
var tempCanvas = document.createElement("canvas"),
tCtx = tempCanvas.getContext("2d");
var imgWidth = 200;
var imgHeight = 200;
const draw = () => {
tempCanvas.width = imgWidth;
tempCanvas.height = imgHeight;
tCtx.drawImage(bg, 0, 0, 100, 100, 0, 0, imgWidth, imgHeight);
const ptrn = ctx.createPattern(tempCanvas , "repeat-x");
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, canvas.width, canvas.height);
requestAnimationFrame(draw);
};
bg.onload = () => {
draw();
}
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<canvas id="canvas" width="1000" height="200"></canvas>
<script src="index.js"></script>
</body>
</html>
try setting up the image size to match the canvas size just like that:
bg.src = "http://lorempixel.com/200/200";
Cheers! :)
I have problem creating simple circle. I think code drawing it is writed like it suposed to be, and another problem is with axis. I dont know why but 0x point begins in the middle of the "game screen". How to make game screen 640px/480px?
Fiddle demo | Screenshot
start.wyswietl = (function(){
var dom = start.dom,
$ = dom.$,
gracz = start.gracz,
canvas, ctx,
pUruchomienie = true;
function createBackground(){
var background = document.createElement("canvas");
bgctx = background.getContext("2d");
dom.dodKlase(background, "background");
background.width = 640;
background.height = 480;
background = new Image();
background.onload = function(){
bgctx.drawImage(background, 0, 0);
};
background.src = "../obrazki/tapeta.png";
dom.dodKlase(background, "board-bg");
return background;
}
function rysuj(callback){
var gracz = document.createElement("canvas");
gctx = gracz.getContext("2d");
gctx.fillStyle = "black";
gctx.arc(5, 40, 5, 0, 2*Math.PI);
gctx.fill();
// dom.dodKlase(gracz, "plansza");
dom.dodKlase(gracz, "gracze");
return gracz;
callback();
}
//function ()
I am trying to use waveform.js found on http://www.waveformjs.org to draw waveforms of SoundCloud tracks. It hasn't been working so I've stripped down waveform.js to a bare bones form that attempts to draw a fillRect in a newly created canvas element through a Waveform object. The canvas element is successfully created but the fillRect does not appear. I've contrasted this to the direct creation of a canvas element and fillRect, which both work.
Here is the HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Sample document</title>
</head>
<body>
<div id="example1"></div>
<hr>
<div id="example2"></div>
</body>
<script src="waveform.js"></script>
<script src="script.js"></script>
</html>
Here is script.js:
var canvas, container;
// Creating canvas element and rect in example1
canvas = document.createElement("canvas");
canvas.setAttribute("id", "canvas");
container = document.getElementById("example1");
container.appendChild(canvas);
canvas.width = container.clientWidth;
canvas.height = container.clientHeight;
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
ctx.fillRect(20,20,50,100);
// Both created successfully
// Creating canvas element and rect in example2, through waveform object
var waveform = new Waveform({
container: document.getElementById("example2")
});
// Canvas element created successfully, no rectangle
Here is waveform.js:
(function() {
var Waveform;
window.Waveform = Waveform = (function() {
Waveform.name = 'Waveform';
function Waveform(options) {
this.container = options.container;
this.canvas = this.createCanvas(this.container, this.container.clientWidth, this.container.clientHeight);
this.context = this.canvas.getContext("2d");
this.width = parseInt(this.context.canvas.width, 10);
this.height = parseInt(this.context.canvas.height, 10);
this.makeRect();
};
Waveform.prototype.createCanvas = function(container, width, height) {
var canvas;
canvas = document.createElement("canvas");
canvas.setAttribute("id", "wfCanvas");
container.appendChild(canvas);
canvas.width = width;
canvas.height = height;
return canvas;
};
Waveform.prototype.makeRect = function() {
var wfCanvas = document.getElementById("wfCanvas");
var ctx = wfCanvas.getContext("2d");
ctx.fillRect(20,20,50,100);
}
return Waveform;
})();
}).call(this);
Bruh you're way over doing it.
Just be sure that the container you are applying the waveform to has PIXEL DIMENSIONS defined as either css or inline.