A little confused with one moment, appreciate any help.
I'm making an app, that uses canvas for rendering game board.
And I faced a problem that its not optimal, rendering canvas for each little change.
Here's what the structure is at the moment:
function renderCanvas() {
// calling for each row
}
function renderRow() {
// calling for each cell
}
function renderCell() {
// Here i use FillRect and StrokeRect both
}
Functions cooperate with passing context to each other.
Now it renders each cell. And using beginPath appears to deal only with stroke.
I wonder if i can startPath (like beginPath) somehow in renderCanvas function and after all operations with context are done - i could render that all once?
You can only do one styling per beginPath...
So if your cells require different colors, fonts, opacities then you must do a beginPath for each different style (but you can group same-styles together into one beginPath).
Related
I am using the p5.js library to create Tetris. When someone gets a line clear (that is, a full line has been filled with Tetris blocks) then the tiles that made that line fill up should be removed/turned off.
What would be the best way to do this? For all visibility aspects of a tile, I use a show() function that draws a rectangle to show the tile. Should I add a variable to the object and check if that is true because executing the show function? Or is there a built-in method or function that makes removing an object easy? I can't seem to find anything like this online
It is hard to answer if we do not know how your tiles are represented in your program.
The method I recommend is to remove the tile from it's container structure altogether.
For example, if the state of your game is stored in a matrix, simply empty the cells that constitute a line. This way, your show() function should not be called at all.
Removing the tile from the container will work, but if its difficult then there is another way.
Have a variable to track whether the tile is being used and have its default be true e.g this.inPlay = true
Only update and show a tile if its inplay is true:
if (tile.inPlay == true) {
tile.update()
tile.show()
}
'''
If you want to remove it, just set its inplay to false
PS. a great tutorial for p5.js is on youtube (made by the coding train)
PPS. just search 'coding train p5.js tutorial' on youtube
first of all im not only new in HTML5 or Canvas im new in the whole Coding Process. I used this Example http://rectangleworld.com/demos/DustySphere/DustySphere.html and tried to modify it in a way i can use it for my needs.
At the moment it looks like this.
code is on codepen
Now i tried to to combine different settings and generate 2 different Particle Animations at the same time. For example: the Particles on 2050 and 2070 should appear on 2090 combined. Is there any easy solution for this problem? I appreciate every help.
Draw particles with differing settings by using a function
Since you're new to coding, I'm wondering if you know about functions.
A function is a reusable block of code.
You can send arguments for a function to use.
Arguments can make the function apply different setting while executing its code.
Here's a quick example using a single function that accepts different arguments to draw your particles with different settings.
In general, you can apply different setting by creating a function that accepts parameters to draw the varied settings. That way you can call that same function multiple times with different setting.
// draw a small red circle at [x=50,y=50] with full alpha
drawParticle(50,50,10,'red',1.00);
// draw a large green circle at [x=150,y=100] with half alpha
drawParticle(150,100,50,'green',0.50);
function drawParticle(cx,cy,radius,color,alpha){
ctx.beginPath();
ctx.arc(cx,cy,radius,0,Math.PI*2);
ctx.fillStyle=color;
ctx.globalAlpha=alpha;
ctx.fill();
}
For more complex settings you can use if statements to draw the varied settings
For example, this function lets you draw a particle that "ages" from 0 to 100.
Pass in the particle's age as an argument and the function uses if statements to reduce the particle's alpha as it ages.
function drawParticle(cx,cy,radius,color,age){
ctx.beginPath();
ctx.arc(cx,cy,radius,0,Math.PI*2);
ctx.fillStyle=color;
if(age<25){
ctx.globalAlpha=1.00;
}else if(age<50){
ctx.globalAlpha=.75;
}else if(age<75){
ctx.globalAlpha=.50;
}else{
ctx.globalAlpha=.25;
}
ctx.fill();
}
I have tried following the suggestions given as answer to this questions but I still can't figure out how the "rendering flow" of a WebGL program really works.
I am simply trying to draw two triangles on a canvas, and it works in a rather non-deterministic way: sometimes both triangles are rendered, sometimes only the second one (second as in the last one drawn) is rendered.
(it appears to depend on rendering time: strangely enough, the longer it takes, the better the odds of ending up with both triangles rendered). EDIT: not true, tried refreshing over and over and the two triangles sometimes show up on very rapid renders (~55ms), sometimes on longer-running ones (~120ms). What does seem to be a recurring pattern is that on the very first time the page is rendered, the two triangles show, and on subsequent repeated refreshes the red one either shows for good or for a very short lapse of time, then flickers away.
Apparently I'm missing something here, let me explain my program's flow in pseudo-code (can include the real code if need be) to see if I'm doing something wrong:
var canvas = new Canvas(/*...*/);
var redTriangle = new Shape(/* vertex positions & colors */);
var blueTriangle = new Shape(/* vertex positions & colors */);
canvas.add(redTriangle, blueTriangle);
canvas.init(); //compiles and links shaders, calls gl.enableVertexAttribArray()
//for vertex attributes "position" and "color"
for(shape in canvas) {
for(bufferType in [PositionBuffer, ColorBuffer]) {
shape.bindBuffer(bufferType); //calls gl.bindBuffer() and gl.bufferData()
//This is equivalent to the initBuffers()
//function in the tutorial
}
}
for(shape in canvas) {
shape.draw();
//calls:
//-gl.bindBuffer() and gl.vertexAttribPointer() for each buffer (position & color),
//-setMatrixUniforms()
//-drawArrays()
//This is equivalent to the drawScene() function in the tutorial
}
Despite the fact I've wrapped the instructions inside object methods in my attempt to make the use of WebGLs slightly more OO, it seems to me I have fully complied to the instructions on this lesson (comparing the lesson's source and my own code), hence I cannot figure out what I'm doing wrong.
I've even tried to use only one for(shape in canvas) loop, as so:
for(shape in canvas) {
for(bufferType in [PositionBuffer, ColorBuffer]) {
shape.bindBuffer(bufferType); //calls gl.bindBuffer() and gl.bufferData()
//This is equivalent to the initBuffers()
//function in the tutorial
}
shape.draw();
//calls:
//-gl.bindBuffer() and gl.vertexAttribPointer() for each buffer (position & color),
//-setMatrixUniforms()
//-drawArrays()
//This is equivalent to the drawScene() function in the tutorial
}
but it doesn't seem to have any effect.
Any clues?
I'm guessing the issue is that by default WebGL canvases are cleared everytime they are composited
Try changing your WebGL context creation to
var gl = someCanvas.getContext("webgl", { preserveDrawingBuffer: true });
I'm just guessing your app is doing things asynchronously which means each triangle is drawn in response to some event? So, if both events happen to come in quick enough (between a single composite) then you get both triangles. If they come on different composites then you'll only see the second one.
preserveDrawingBuffer: true says "don't clear after each composite". Clearing is the default because it allows certain optimizations for certain devices, specifically iOS, and the majority of WebGL apps clear at the beginning of each draw operation. Those few apps that don't clear can set preserveDrawingBuffer: true
In your particular case line 21 of angulargl-canvas.js
options = {alpha: false, premultipliedAlpha: false};
try changing it to
options = {alpha: false, premultipliedAlpha: false, preserveDrawingBuffer: true};
I'm wondering if there's a way to take existing images and "stack" them to create a single asset in Javascript.
http://imgur.com/a/ajkBh
The above image album shows what I'd like to do.
Basically, for the game I'm making, I want to procedurally generate enemy NPC's and the like, drawing from a pool of different body parts. Each potential body part would have stats and a spritesheet attached to it, so when the character is randomly generated, I want to stack all of the necessary images together into a single asset that I can then use.
Is there any way to do this?
Canvas is a very basic drawing API with the ability to draw a few basic shapes, strokes and fills. Other than filling with the background color, and/or clearing the whole canvas, there's no way to animate scenes with "sprites" or any complete objects sitting on top of each other, using only the basic canvas API. Copying images in is possible, but then you need to clear them every single frame and replace them, which is a lot of code overhead, if you want them to animate.
You should look into http://createjs.com or a similar "screen graph" type framework, something that sits on top of the canvas and lets you easily load up sprite sheets and move them around. It does the drawing, clearing, rotation, animation etc. of the canvas for you (basically making it a bit like Flash).
In terms of purely stacking or drawing on the canvas, yes you can grab an image and copy it directly onto the canvas using the context2d.drawImage method, but this is probably not going to achieve the effect you want by itself.
You can build up your animation out of existing parts, if think the main issue is organizing the base artworks and having the drawing done to fit one with another.
Let's say :
You want an idle (line 1), walk (line 2), run (line 3)
on each line you have a constant number of frames, say 5.
Say also that your parts are : legs, body, arms, head.
Then you have to build the image by yourself, by stacking those images :
function buildAnimation(legs, body, arms, head) {
var resImg = document.createElement('canvas');
resImg.width = legs.width; resImg.height = legs.height;
var resCtx = resImg.getContext('2d');
resCtx.drawImage(legs,0,0);
resCtx.drawImage(body,0,0);
resCtx.drawImage(arms,0,0);
resCtx.drawImage(head,0,0);
return resImg;
}
then you can feed your game framework with this image, that will be used for an
animation.
The drawback of this method is that you have to draw all animations of all parts
at the same places each time.
Issues :
1) for the head for instance, you might not want to animate it.
2) you might want different height for different characters.
3) it's a lot of work !!
So you might decide of conventions to know where the parts should be drawn, and have
less part to prepare in an image, but a more complex way to build them.
Short example : the file name of the image parts ends with their height, so you can retrieve them
easily. (bodyMonster48.png, bodyHead12.png, ...)
Writing everything would be too much work here, but just a short example :
say we have animWidth, animHeight the size of each anim, and five frames in each
of the 3 anims. Now we just have one head that we want to copy everywhere :
function buildAnimation(animWidth, animHeight, legs, body, arms, head) {
var resImg = document.createElement('canvas');
resImg.width = legs.width; resImg.height = legs.height;
var resCtx = resImg.getContext('2d');
resCtx.drawImage(legs,0,0);
resCtx.drawImage(body,0,0);
resCtx.drawImage(arms,0,0);
// copy the head in all frames of all anims
for (var animLine=0; animLine<3; animLine++) { // iterate in idle, walk, run
for (var animFrame= 0; animFrame<5; animFrame++) { // iterate in images of the animation
resCtx.drawImage(head, animFrame*animWidth, animLine*animHeight);
}
}
return resImg;
}
To be able to build any combination with variable height, you'll
have to carefully parametrize everything, use file naming and positioning conventions,
and you'll surely need a whole helper class not to get lost in all combinations.
I'm implementing a menu system for my game using canvas (for certain performance reasons I cannot use HTML/CSS to make the menus). I have the menu configured using JSON and menuComponent objects are created with their respective properties (x, y, width, height, imagePath, etc). I have a menu loader which then iterates over the component objects and calls the componentObjects' draw method (all images wait for their onload event to fire first, of course).
Anyway, I expect my images to be drawn in the order that their draw method is called so that they overlap in the correct order. The majority of the time this behaviour is correct but occasionally they will draw in the wrong order.
My question is - can I trust Canvas to draw images in the order the drawMethod is called for those images? Say I have image A which is, for example, 10MB and image B which is 10kb. If I call draw image A and then draw image B then is there a chance that image B will load first because it's a smaller image?
I was trying to be smart with my code (having nested components inside my component objects and recursively call draw methods) so it's possible there's some race conditions in my code, I just want to confirm the above behaviour is correct. If I add logic to force my objects to wait until a ready flag is set then it seems to work. But unfortunately that slows up my menus load time.
To put a formal answer to this post -
In the end I simplified my solution to use one menuLoader object which has an array of hashes for each image to be drawn (containing x, y, imagePath, ready flag). I call a create components method which builds up these hashes with the ready flag set to false by default. I set an onload event for each image to set its respective ready flag to true.
After create components has finished executing I use setInterval to spin until all flags have been set to true. Once this condition is met I iterate through my array of hashes again and call the draw method for each image.
Man I've faced same problem and have been stucked with it for about three days. And I figured one interseting thing. Please look though this code snippet and supply me with your thoghts on it.
final ResourceManager rm = new ResourceManager(1000, 1000);
rm.loadImgResource(LandCardResources.INSTANCE.getMeadow(), "meadow", 0, 0);
rm.loadImgResource(LandCardResources.INSTANCE.getHellHorseKnight(), "knight", 150, 150);
Resource manager is an object representing BackBufferCanvas that holds all images in its context (like simple image sprite). Constructor is also responsible for adding this Backbuffer to RootPanel, so we can determine thats everything worked like we expected. After that I'm adding my main canvas to root trying to draw on it from backBufferCanvas using perfectly working ResourceManager instance.
canvas.setWidth(500 + "px");
canvas.setHeight(500 + "px");
canvas.setCoordinateSpaceWidth(500);
canvas.setCoordinateSpaceHeight(500);
RootPanel.get().add(canvas);
rm.drawImageFromMetaDb(ctx, 0, 0, 100, 100, 0, 0, 100, 100);
rm.drawImageFromMetaDb(ctx, 150, 150, 100, 100, 50, 50, 100, 100);
And it never works. But if I for example add Button to rootPanel with handler that is responsible for rm.drawImage..... It will work perfectly when clicking this Button. Can't really understand why this is happening as backBufferCanvas is attached before mainCanvas so logic must be already delayed.