I am creating a click and clear game. Once the user clicks some brick its adjacent bricks are checked for same color and all these bricks are bricks are cleared at once.
These are Cleared using clearRect() function.
Now this leaves a white patch right between the bricks above and bricks below leaving the above bricks hanging.
Now i want to bring these bricks above downward. How do i do this..?
Plz help
The question is quite vague, but based on the title, you'll need to clear your canvas before you can redraw. Otherwise, the drawn elements would simply stack on top of each other.
To do this, call the function clearRect on the canvas itself:
function clear() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, 500, 500);
}
Where canvas is the ID of your canvas, and 500, 500 the dimensions. Now you'll have an empty canvas where you can redraw everything again.
I once created a simple HTML5 canvas game as well, you might learn from the source code.
I think I understand what you're asking. If so then you're wanting to know how to move the blocks down when the blocks below have been removed.
This is just a matter of increasing the x position (remember the canvas starts at 0,0) with each iteration of your game loop.
How far to increase? Well that would be to where the highest "solid tower" is. I.E., say you have a column of 10 tokens and you remove the 7. The 3 below need all fall to the height of the remaining 6 - so that would be board height - (6*token height)
*
*
*
+ <- remove
* <- 6x token height (and less the board height)
*
*
*
*
*
I had success at redrawing the HTML Canvas by DOM.
var c = document.getElementsByName("myCanvas")[0];
if (c != null)
{
c.remove();
}
var c = document.createElement("canvas");
c.setAttribute("name", "myCanvas");
c.setAttribute("width", 900);
c.setAttribute("height", 600);
c.setAttribute("style", "border:1px solid #d3d3d3");
Related
I'm looking for a way to render graphics onto an HTML5 canvas using JavaScript, but I want to only render said graphics if they're inside a pre-defined mask.
I'm creating a GUI framework that can be used to easily and quickly create GUIs on an HTML5 canvas. I think that something that would be really nice to have is a way to render graphics inside an element, and make the element auto-crop the graphics so that they always stay inside of it. For example, I can make a rectangular element and animate a circular pulse inside of it, and as the circle extends past the outside of the element, those parts of he circle should just not render to keep it looking smooth and sharp. This is similar to what CSS does with overflow: hidden;
Now, I know that one option is to use a mask-like feature. For example, P5.js has mask(). However, this is very very slow. Masking a single element a single time using P5.js significantly reduces framerate, and I want to be doing this potentially hundreds of times per frame without frame drops. I know that CSS does this incredibly efficiently (from my own experience working with it), but I can't seem to think of any way to make it efficient on a canvas element.
I could do it pretty simply if it was just a rectangle, but I want to do this for any shape. For example, a circle, a star, a rectangle with rounded edges, or really any polygon at all.
How can this be done? I thought of potentially rendering to an off screen canvas (which is shrunken to the size of the element in question), then render the element onto that screen using one color (let's say the background color will be white, and the shape will be black), then rendering the image we want masked onto another off screen canvas that's the same width as our other OSC, then looping through one of their image data arrays and mapping one to the other based on whether said pixel is white or black on the mask canvas.
But........ I can't help but think that that's going to be incredibly slow for the computer to process. I assume that CSS somehow leverages the GPU to do this type of computation incredibly efficiently and that's why they get such an increase in performance. Is it possible for me to do the same or am I just dreaming?
Okay, so I have found two different means of doing this (huge thank you to #Kaiido). One method is to use ctx.clip() while one works with CanvasPattern.
This snippet shows both means in action:
<canvas id = "c" width = "400" height = "400"></canvas>
<canvas id = "c2" width = "400" height = "400"></canvas>
<script>
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "yellow";
ctx.fillRect(0,0,400,400);
ctx.beginPath();
ctx.arc(200,200,100,0,6);
ctx.clip();
ctx.beginPath();// This clears our previous arc from the path so that it doesn't render in when we `fill()`
ctx.fillStyle = "rgb(255,0,0)";
for(var i = 0;i < 20;i++){
for(var j = 0;j < 40;j++){
ctx.rect(i * 20 + j % 2 * 10,j * 10,10,10);
}
}
ctx.fill();
</script>
<script>
var canvas2 = document.getElementById("c2");
var ctx2 = canvas2.getContext("2d");
ctx2.fillStyle = "orange";
ctx2.fillRect(0,0,400,400);
var osc = new OffscreenCanvas(400,400);
var oscctx = osc.getContext("2d");
oscctx.fillStyle = "rgb(255,0,0)";
for(var i = 0;i < 20;i++){
for(var j = 0;j < 40;j++){
oscctx.rect(i * 20 + j % 2 * 10,j * 10,10,10);
}
}
oscctx.fill();
var pattern = ctx2.createPattern(osc,"no-repeat");
ctx2.fillStyle = pattern;
ctx2.arc(200,200,100,0,6);
ctx2.fill();
</script>
Which one is more efficient and better to be run hundreds of times per frame?
Another edit:
I spent about an hour messing around with it on a sandbox website, and I made this small project:
https://www.khanacademy.org/computer-programming/-/6446241383661568
There I run each one every millisecond and see how quickly each one updates to see which appears more efficient. clip() is on top while CanvasPattern is on the bottom. They both appear to be incredibly fast to me, and I feel that no matter which I chose I will have almost exactly the same results. However, clip() does still appear to be a bit faster as far as I can tell.
See for yourself and let me know what you think!
So I'm doing a project and I'm developing a fall down type game.
The problem seems to be on this line: createRect(20, 40, 25, 15, "red");
It looks like the rect is drawn but instantly disappears any idea on how to fix this? I'm not sure why this happens and I'm learning javascript so I don't have the experience to understand why this occurs
The problem is that you keep resetting the cavas size several times a second:
setInterval(function(){
canvas.width = 360;
canvas.height = 640;
createMenu();
}, 1000 / fps);
Resetting the size is a (bad) way to clear the canvas (see How to clear the canvas for redrawing), and thus the newly drawn rectangle disappears.
Here is my canvas on jsfiddle:
https://jsfiddle.net/vzrandom/fkho6grf/8/
I'm using simplex-noise.js and dat.GUI to create movement of particles. There is simulated click on canvas every 5 seconds. On click first animation is coming in background and new animation starts.
My problem is that animation on click starts too abruptly. I would like to have some kind of fade in of particles.
It seems like a simple problem but somehow I can't get it how to make fade in of elements that are inside the canvas - not entire canvas himself.
Entire code is on jsfiddle, here is part that handles the click:
function onCanvasClick(e) {
context.save();
context.globalAlpha = 1;
context.fillStyle = Configs.backgroundColor;
context.fillRect(0, 0, screenWidth, screenHeight);
context.restore();
simplexNoise = new SimplexNoise();
}
You need to render to an offscreen canvas.
Just create a second canvas
var canvas2 = document.createElement("canvas");
canvas2.width = canvas.width;
canvas2.height = canvas.height;
var ctx2 = canvas.getContext("2d");
Then for all your drawing calls use the background canvas 2dContext
To do the fade just render that canvas onto the display canvas setting alpha to make it fade.
The function called by requestAnimationFrame is passed a hi resolution time as the first argument. The code below is for the update function. Note that if you are using a polyfill for requestAnimationFrame you should use one that matches the standard.
var fadeTime = 1; // one second
var fadeTimeStart = undefined; // when undefined then this indicates start of fade
function update(time){
// render your particles to offscreen canvas
if(fadeTimeStart === undefined){ // get the current time as start
fadeTimeStart = time;
}
// get amount of fade
var fTime = (time - fadeTimeStart) / fadeTime;
// is it fading
if(fTime < 1){ // yes
ctx.globalAlpha = fTime;
clearRect(0,0,canvas.width,canvas.height); // clear last rendered scene
ctx.drawImage(canvas2,0,0); // draw the offscreen canvas
}else{
// you may or may not have to clear the canvas
ctx.drawImage(canvas2,0,0); // if no fade and assuming canvas is opaque then just draw the canvas onto the display.
}
requestAnimationFrame(update);
}
Then in the click event to start a new fade in just set the fadeTimeStart = undefined and it will start a new fade in.
I don't know if this is the effect you want to achieve, but you might get away with clearing the canvas a little on each iteration by filling it with a semi-transparent color in update function, instead of clearing it completely on each click.
See my fork here: https://jsfiddle.net/640e32ua/
Main change is changing Configs.backgroundColor to something semi-transparent and adding these two lines to update:
context.fillStyle = Configs.backgroundColor;
context.fillRect(0, 0, screenWidth, screenHeight);
I am trying to create my first website using the p5.js library, with the end goal being an online digital portfolio. I am currently working on a splash screen, in which I have some large title text filling the center of the screen on a simple black background, which actively resizes to fill the window.
I would like to place a simple doodle in the background to add some interest. My challenge is that I would not like this doodle to draw on top of my text, but instead place it underneath my text. Initially I was thinking of infinitely redrawing the text so it stays at the top, however I have deduced there is no way to do this while still animating something beneath it.
My knowledge of HTML / CSS is minimal, however I was thinking of making the background of the title sketch transparent, a separate sketch with the doodle, and use the z index property in CSS to place the doodle beneath the title, is this even possible?
Thanks!
Further edits based on recommendations:
function preload() {
myFont = loadFont('assets/HighTide.otf');
}
function setup() {
canvas = createCanvas(window.innerWidth, window.innerHeight);
title = text("Welcome", width/2, height/2);
background(30);
fsize = window.innerHeight/4;
pg = createGraphics(window.innerWidth, window.innerHeight);
}
function draw() {
background(30);
pg.fill(random(0,255), random(0,255), random(0,255));
//pg.translate(width/2, height/2);
pg.ellipse(random(window.innerWidth), random(window.innerHeight), 60, 60)
image(pg, 0, 0);
textFont(myFont);
textSize(fsize);
textAlign(CENTER);
fill(255);
text("Welcome", width/2, height/2);
}
window.onresize = function() {
var w = window.innerWidth;
var h = window.innerHeight;
canvas.size(w,h);
fsize = window.innerHeight/4;
title.textSize(fsize);
width = w;
height = h;
}
It depends on exactly how you're drawing everything, but if you're doing this all in P5.js then you've already described exactly what you need to do.
Step 1: Each frame, clear out old frames by calling the background() function.
Step 2: Then draw your doodle.
Step 3: Finally, draw your text. Since you're drawing the text after the doodle, it shows up "on top" of the doodle.
This is how most P5.js sketches work: every frame, you clear out the old frames and then draw the next frame.
Edit: If you need a sketch that doesn't clear out old frames but still shows two different layers (your doodle and your text), then what you could do is draw your doodle to a buffer, then draw that buffer each frame, then draw the text on top of the buffer. Check out the createGraphics() function in the reference.
I'm trying to make a screen shake in a game every time you shoot. I recall in Actionscript 3 you could set the x and y of your stage with the following:
stage.x = stx
I was wondering if there is a way to do this with an HTML Canvas 2D Context. I'm currently using the following:
ctx.save();
ctx.translate(0, shakeAmt);
ctx.restore();
(ctx is my HTML Canvas 2D Context)
This method isn't working for me due to the fact that resetting the canvas every time isn't as smooth as I'd want it to be. Along with this if a shake is called while another shake is running, the canvas will save and restore halfway through a shake.
Is there a JavaScript alternative to stage.x? If not, how could I go about this?
In this case I would recommend apply camera-shake (or machine gun shake perhaps?) to the element itself (which sort of represents the stage). This is because any transform to canvas context does only affect future drawing which means you will have redraw each frame, do-able but require an extra full draw-op per frame while using DOM can update the "stage" in the same cycle.
The problem with shaking the element on the other hand, is that it will move in the view-port, however, you can camouflage this by wrapping it in a div which has overflow set to hidden as well as applying a slight amount of scaling to the canvas element during the shake. You can additionally incorporate an overlap by using a slightly bigger canvas that is offset inside the div.
Conceptual Demo
Click on the image to apply camera shake.
var style = img.style; // cache style object
var amp = 7; // diameter of shake
var t = 0; // current shake [0, 1]
var step = 0.03; // progress step for each frame
img.onclick = function() {
if (t) t = 1; // continue loop, but reset
else {t = 1; shake()} // start loop
}
function shake() {
var a = (Math.random() * 2 - 1) * t; // random angle
var x = (Math.random() * amp * 2 - amp) * t; // random position, bias on x
var y = (Math.random() * amp - amp*0.5) * t;
var s = Math.max(1, 1.05 * t); // scale to compens. for movement
var b = 2 * t; // blur amount
// build transform for element
var tr = "rotate(" + a + "deg) translate(" + x + "px," + y + "px) scale(" + s + ")";
style.transform = style.webkitTransform = tr;
style.filter = "blur(" + b + "px)";
t -= step;
if (t > 0) requestAnimationFrame(shake);
else {
t = 0;
style.transform = "matrix(1,0,0,1,0,0)"; // reset transforms
style.filter = "blur(0)"; // remove blur
}
}
div {
display:block;
position:relative;
overflow:hidden;
width:600px;
height:340px;
background:rgba(121, 115, 117, 0.2);
}
#img {
position:absolute;
left:-5px;
top:-5px;
width:620px;
height:auto;
}
<div><img id=img src="//i.stack.imgur.com/XmnSd.jpg"></div>
Using more than one canvas.
You can create a stage by rendering to an offscreen canvas. Though I am ignorant of Actionscripts stage abstraction, having presentation and render canvases separate is a common technique when you need full page post render effects (like shake).
To implement just create 2 canvases, one for the page (presentation canvas) and the offscreen render canvas.
Render to the render canvas as normal, then at the end of frame draw the offscreen canvas onto the presentation canvas.
var rCanvas = document.createElement("canvas"); // render canvas
rCanvas.width = ?
rCanvas.height = ?
var pCanvas = rCanvas.cloneNode(); // presentation canvas
document.body.appendChild(pCanvas); // add to DOM
var ctx = rCanvas.getContext("2d");
var pCtx = rCanvas.getContext("2d"); // presentation context
Then render to the render canvas as normal, once the frame has been rendered you can change the position by rendering it offset onto the presentation canvas
pCtx.drawImage(rCanvas,x,y); // present canvas at x, and y
Depending on the type of game you may want to extend the render canvas's size so that when it shakes you do not lose pixels around the edge.
More than just shake.
Using offscreen canvases is not limited to just one. I convert all images, sprite sheets, UI panels, whatnot to canvases. Then present them to the onscreen canvas each frame. This opens up many extra FX not available if just using one canvas, and also reducing the render load, as I only need to re-render only what has changed per frame.
So for example if you have a UI panel separate from the playfield render you can give each a slightly different shake amount, adding a bit of depth to the display. You can brighten the whole play field as well by just rendering the playfield again with pCtx.globalCompositeOperation = "lighter" and pCtx.globalAlpha = amount` to control the level. The flash will add to the shake FX giving a more immersive experience.
You may even have the final presentation canvas as a webGL context opening up unlimited FX possibilities not possible using the DOM while still allowing you to use the 2D API for the main rendering of the game.