I am having trouble with globalCompositeOperation in javascript for the html5 canvas.
https: //jsfiddle.net/6j51kxeh/
I am using "destination-in" do draw a black square in a sprite of a heart, so when the the player is missing that heart, it shows. It draws the black heart alright, but it draws white over top of everything else. If you comment out the globalCompositeOperation line you will see it is drawn on top of other things (just a random group of sprites from the same sprite sheet). Thanks for any help.
I am also having trouble just linking to jsfiddle and I'm done playing with it.
var canvas = document.createElement("canvas");
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
var scale = 4;
document.body.appendChild(canvas);
var draw = canvas.getContext("2d");
draw.imageSmoothingEnabled = false;
draw.mozImageSmoothingEnabled = false;
draw.oImageSmoothingEnabled = false;
draw.webkitImageSmoothingEnabled = false;
var assetsToLoad = [];
var assetsLoaded = 0;
var sprites = new Image();
sprites.onload = loadHandler;
sprites.src = "https://dl.dropboxusercontent.com/u/38825680/Site/images/sprites.png";
assetsToLoad.push(sprites);
function loadHandler() {
assetsLoaded++;
if(assetsLoaded === assetsToLoad.length) {
console.log(assetsLoaded + " asset[s] loaded");
Draw();
}
};
function Draw() {
draw.save();
draw.scale(scale,scale);
draw.drawImage(sprites,0,64,64,64,0,0,64,64);
// draw.drawImage(sprites,112,80,16,16,0,0,16,16);
draw.fillStyle = "black";
draw.fillRect(0,0,16,16);
//draw.globalCompositeOperation = "destination-in";
draw.drawImage(sprites,96,48,16,16,0,0,16,16);
draw.restore();
}
destination-in compositing is destructive in the sense that it will erase everything on the canvas except where the new (heart) overlaps any existing non-transparent pixels. So this form of compositing is not likely what you need.
To clarify: You want to draw the heart sprite over another sprite image and then later clear that sprite from the other sprite image that the heart was added to?
If yes, then:
To add the heart, draw the heart sprite over the other sprite.
To clear the heart, just redraw the other sprite.
Example code and a Demo:
var canvas = document.createElement("canvas");
canvas.height = 640;//window.innerHeight;
canvas.width = 960;//window.innerWidth;
var scale = 4;
document.body.appendChild(canvas);
var draw = canvas.getContext("2d");
draw.imageSmoothingEnabled = false;
draw.mozImageSmoothingEnabled = false;
draw.oImageSmoothingEnabled = false;
draw.webkitImageSmoothingEnabled = false;
var assetsToLoad = [];
var assetsLoaded = 0;
var sprites = new Image();
sprites.onload = loadHandler;
sprites.src = "https://dl.dropboxusercontent.com/u/38825680/Site/images/sprites.png";
assetsToLoad.push(sprites);
function loadHandler() {
assetsLoaded++;
if(assetsLoaded === assetsToLoad.length) {
console.log(assetsLoaded + " asset[s] loaded");
draw.scale(scale,scale);
Draw();
}
};
function Draw() {
draw.drawImage(sprites,0,64,64,64,0,0,64,64);
}
function addHeart(x,y){
draw.fillStyle = "black";
draw.fillRect(x,y,16,16);
draw.drawImage(sprites,96,48,16,16,x,y,16,16);
}
function removeHeart(x,y,spriteX,spriteY){
draw.clearRect(x,y,16,16);
draw.drawImage(sprites,spriteX,spriteY+64,16,16,x,y,16,16)
}
$('#add').click(function(){
addHeart(0,0);
});
$('#remove').click(function(){
removeHeart(0,0,0,0);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id=add>Add heart</button>
<button id=remove>Remove heart</button>
Related
I have coded a cube using canvas and the <script> tag. I would like to create a function that changes the color of a single line from black to grey to white within a given timeframe.
var c = document.getElementById("myCanvas");
var ctxfii = c.getContext("2d");
ctxfii.beginPath();
ctxfii.moveTo(700, 415);
ctxfii.lineTo(700, 515);
ctxfii.lineWidth = 1;
ctxfii.strokeStyle = "black";
ctxfii.stroke();
var colorChange = ctxfii;
function colorChange () {
window.setInterval(10);
document.getElementById("myCanvas").strokeStyle = "grey"
};
Nothing comes up the whole canvas appears blank.
I'm animating the value for strokeStyle from black rgb(0,0,0) to white rgb(255,255,255). In order to make it go from black to grey to white back to grey and black again I'm using Math.abs(Math.sin(H)) * 255;
Instead of using setInterval I'm using requestAnimationFrame
Also I'm translating the context because I wanted to see the line, but you can remove this part.
var c = document.getElementById("myCanvas");
c.width = 400;
c.height = 400;
var ctxfii = c.getContext("2d");
// I'm translating the context because I want to see the line;
ctxfii.translate(-600,-400)
ctxfii.strokeStyle = "black";
drawLine();
let H = 0;
function colorChange () {
requestAnimationFrame(colorChange);
H+= .01;
let h = Math.abs(Math.sin(H)) * 255;
//delete everithing on the canvas
ctxfii.clearRect(0,0,c.width,c.height)
// I'm animating the strokeStyle from black: rgb(0,0,0) to white: rgb(255,255,255)
ctxfii.strokeStyle = `rgb(${h},${h},${h})`;
//redraw the line:
drawLine();
};
colorChange()
// a function to draw the line; I'll need this function more than once
function drawLine(){
ctxfii.beginPath();
ctxfii.moveTo(700, 415);
ctxfii.lineTo(700, 515);
ctxfii.lineWidth = 1;
ctxfii.stroke();
}
canvas{border:1px solid;background:skyblue;}
<canvas id="myCanvas"></canvas>
I am new to JavaScript and I am having a hard time understanding how to get the canvas to cooperate with stuff I want to do.
I am trying to have my HTML button outside the canvas create a rectangle on the canvas. Then I want the rectangle to fall. I have the canvas animated, I have the button set to create a rectangle at user inputted coordinates, but...the canvas won't animate it.
It won't fall like the statically created rectangles. I also am struggling with how to get my button to create a new rectangle each time instead of redrawing the same one? Hoping someone can explain more than just give me the code.
Thanks in advance.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
window.onload = addListeners;
function addListeners() {
document.getElementById('b1').addEventListener('click',btn1,false);
function btn1() {
var inputx = document.getElementById("work").value;
var inputy = document.getElementById("y").value;
var inputs = document.getElementById("s").value;
new Rectangle(inputx,inputy,inputs);
// rec.x = inputx;
//rec.y = inputy;
//rec.s = inputs;
}
}
var r2 = new Rectangle(500, 50, 50);
var rec = new Rectangle();
//animate
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0,0,1450,250);
r2.draw();
r2.update();
rec.draw();
rec.update();
}
code for rectangle:
function Rectangle(x,y,s){
this.x = x;
this.y = y;
this.s = s;
this.draw = function(){
//console.log('fuck');
ctx.fillStyle = "rgba(0,200,0,1)";
ctx.fillRect(this.x,this.y,this.s,this.s);
}
this.update = function(){
console.log(this.y);
if((this.y + this.s) <= 250){
this.y= this.y+2;
}
}
}
The button is not animating anything as the animate method was not being called. Also in your code when you called animate it ended in an infinite loop as requestAnimationFrame will continue to call animate repeatedly, so I've added a condition around requestAnimationFrame(animate) to check the squares height and stop running it when it reaches the bottom, similar to what you had in your update function.
To create a new square every time you click the button, I moved the creation of the Rectangles inside the btn1 function. If you want to keep the old squares while creating new ones, you will need to keep track of them outside the canvas and redraw them with everything else each animation.
I guessed what your html looks like, but you can run the code below it will drop two squares, but note that the stop condition is only on the hard coded one.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
document.getElementById("b1").addEventListener("click", btn1, false);
var r2;
var rec;
function btn1() {
var inputx = document.getElementById("work").value;
var inputy = document.getElementById("y").value;
var inputs = document.getElementById("s").value;
r2 = new Rectangle(500, 50, 50);
rec = new Rectangle(parseInt(inputx, 10), parseInt(inputy, 10), parseInt(inputs, 10));
animate();
}
//animate
function animate() {
if (r2.y + r2.s <= 400) {
requestAnimationFrame(animate);
}
ctx.clearRect(0,0,1450,400);
r2.draw();
r2.update();
rec.draw();
rec.update();
}
function Rectangle(x,y,s){
this.x = x;
this.y = y;
this.s = s;
this.draw = function(){
ctx.fillStyle = "rgba(0,200,0,1)";
ctx.fillRect(this.x,this.y,this.s,this.s);
}
this.update = function(){
this.y= this.y+2;
}
}
<div>
<input id='work'>
<input id='y'>
<input id='s'>
<button id="b1"> Create Sqaure</button>
</div>
<canvas id="myCanvas" width=600 height=400></canvas>
I have an imageCanvas with it's Transform matrix
Image = new image();
image.src = //stuff;
imageContext.drawImage(Image, 0, 0);
var t = imageContext.currentTransform;
that is drawn on another canvas
context.drawImage(imageCanvas, 0, 0);
on which I draw lines
context.moveTo(mousePos.X, mousePos.Y);
context.lineTo(currentPos.X, currentPos.Y);
context.stroke();
I save my lines into a vector of objects 'lines'.
I would like to join the two layers into the 'Image', but this function works only for traslation but not for rotation and scaling.
var saveCanvas = document.createElement('canvas');
var saveContext = saveCanvas.getContext('2d');
saveCanvas.width = Image.width;
saveCanvas.height = Image.height;
saveContext.drawImage(Image,0,0);
saveContext.save();
var t = imageContext.currentTransform;
saveContext.setTransform(1,0,0,1,-t.e,-t.f);
for(var i = 0; i < lines.length; i++){
saveContext.beginPath();
saveContext.moveTo(lines[i].from.X, lines[i].from.Y);
saveContext.lineTo(lines[i].to.X, lines[i].to.Y);
saveContext.stroke();
}
saveContext.restore();
Image.src = saveCanvas.toDataURL();
how can I modify the arguments of 'setTransform' to solve the problem ?
Just use the rest of the transforms attributes.
var t = imageContext.currentTransform;
saveContext.setTransform(
t.a,
t.b,
t.c,
t.d,
-t.e,
-t.f);
The Problem
I am finding it rather difficult to get my head around this, I am attempting to move an image using the mouse along the X axis only. I am finding it hard to even move the image at all and the many tutorials I have looked at arnt really helping me. Here is what I am trying to say:
As you can see by my beautiful image above I only want to image to move left and right at the bottom of the page.
The Code and the Question
Here is my first attempt, when I try this all the images loaded on the canvas no longer appear making it very hard for me to understand why it isnt working.
<script type="text/javascript">
//Referencing the canvas
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var width = canvas.getAttribute('width');
var height = canvas.getAttribute('height');
//Images
var bggameImage = new Image();
var playerImage = new Image();
var enemyImage = new Image();
var projectileImage = new Image();
var livesImage = new Image();
//Canvas dimensions
var width = 480;
var height = 320;
//Loading in the backgroundImage
bggameImage.src = "Images/bggameImage.png";
bggameImage.onload = function(){
context.drawImage(bggameImage, 0, 0);
}
//Loading in the playerImage
playerImage.src = "Images/playerImage.png";
playerImage.onload = function(){
context.drawImage(playerImage, 165, 240);
}
//Loading in the projectileImage
projectileImage.src = "Images/projectileImage.png";
projectileImage.onload = function(){
context.drawImage(projectileImage, 65, 240);
}
var playerImage = {
x:176,
y:74,
}
function init() {
playerImage.src = "Images/playerImage.png";
//Moving player
myCanvas.addEventListener("mousemove", function (e) {
var bounding_box = myCanvas.getBoundingClientRect();
playerImage = (e.clientX - bounding_box.left) * (myCanvas.width / bounding_box.width) - playerImage.width / 2;
playerImage = (e.clientY - bounding_box.top) * (myCanvas.height / bounding_box.height) - playerImage.height / 2;
}
)
</script>
The whole "function init()" part is what I have just tried but I thought I would include this anyway, I understand that I am loading in the playerImage twice.
You're using the same variable name twice (playerImage), so your image is being overwritten. You're using it for the image and also to store the position. Change the playerImage that's storing x and y to be playerPosition or something like that. Update that variable on your mouse event and then render the image according to that variable's values.
Ultimately, you're going to have to look at a game loop using setTimeout or requestAnimationFrame. So, this will become crucial at that stage. And yes, you shouldn't be loading the player image twice either. Do all of that at the start and only start your game when all your assets have successfully loaded.
For instance...
var playerImage;
var alienImage;
var bulletImage;
var assetCount = 0;
function loadAssets() {
playerImage = new Image();
playerImage.onload = checkAssetsLoaded;
playerImage.src = "assets/images/Brush01.png";
alienImage = new Image();
alienImage.onload = checkAssetsLoaded;
alienImage.src = "assets/images/Brush02.png";
bulletImage = new Image();
bulletImage.onload = checkAssetsLoaded;
bulletImage.src = "assets/images/Brush03.png";
}
function checkAssetsLoaded(event) {
assetCount++;
console.log("An asset has loaded!: " + assetCount);
if (assetCount == 3) {
startGame();
}
}
function startGame() {
// Start your game initialization logic here.
console.log("Game starting!");
}
I'm trying to get an event to work on an image when the user clicks on it.
var canvas = document.createElement("canvas");
canvas.width = 800;
canvas.height = 600;
canvas.style = "border:2px solid black";
canvas.addEventListener('click', clickReporter, false);
var ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
var clickhere = new Image();
clickhere.onload = function () {
draw();
};
clickhere.src = "clickhere.png";
function draw() {
ctx.drawImage(clickhere, 200, 200);
}
function clickReporter(e) {
alert("Thanks for clicking!");
}
Obviously all this code will just let the alert box go off as long as the user clicks in the canvas. The image is 100 by 100 pixels.
First off: You apparently have an error in you code in regards to the image (at least in the example you provide):
var button = new Image();
clickhere.onload = function () {
draw();
};
clickhere.src = "clickhere.png";
function draw() {
ctx.drawImage(clickhere, 200, 200);
}
Should be like this for the example to work:
var button = new Image();
/// use button for these as well -
button.onload = function () { /// here
draw();
};
button.src = "clickhere.png"; /// here
function draw() {
ctx.drawImage(button, 200, 200); /// and here (or use 'this' instead)
}
The next problem
Canvas doesn't know what we draw into it so we need to make sure we provide all the underlying logic ourselves to handle these sort of things.
For example: Here is one way to check if the region the image was drawn into is clicked:
function clickReporter(e) { /// assign event to some variable
/// adjust mouse click position to be relative to canvas:
var rect = this.getBoundingClientRect(),
x = e.clientX - rect.left,
y = e.clientY - rect.top;
/// check x/y coordinate against the image position and dimension
if (x >= 200 && x <= (200 + button.width) &&
y >= 200 && y <= (200 + button.height)) {
alert("Thanks for clicking!");
}
}
You might want to convert those semi-absolute bounds to something more dynamic by for example using an image with a custom object where you store its x and y position and so forth. But you should get the idea.
Update:
A modified fiddle here