Why are these drawn rectangles conflicting with eachother?

Question:
I’m making a Scenexe.io or Diep.io like game called Celinexe, and I’m tryna render the barrels, but rn their drawing conflicts which eachother for some reason and also conflict with the entity drawing itself. The code is spread over alot of lines and I may not be able to put it here, so just look for the draw() method of the Entity class. Note that I tried setTimeout there, but normally I would only include the function. I also tried a forEach and for loop.

Using console.log, the printed result was A,B,A,B,A,B,C.
A is start of barrel render
B is end of barrel render
C is after all barrels are rendered, AKA when the player is drawn(or in this case, the barrels are rendered on top the player for testing. As you can see because of this, there’s a second gray circle rendering because of barrels and player conflicting I think)
Repl link:
https://replit.com/@Bedrockminer/CELINEXE-ported-here-for-testing?s=app

Additional note: intentionally, only one frame is rendered.

You have to consider the way canvas rendering works along with the asynch nature of javascript.
For example, setTimeout in the rendering can cause some timing issues, since the rendering of each frame should be a synchronous process (after all you want all elements to be drawn in a specific order).
You have to control the rendering order, because you want to render the base entity first and then render its barrels.

So, as an example, you could remove the setTimeout, and try to control more of the rendering process (line 238 in your code):

draw(context, overrideColor, color, strokeColor, facingDirection){
    const weapon = this.definition[0];
    const body = this.definition[1];

    // Like I said, first draw the entity itself
    this.defHelper.shapePath(body.sides, context, this.xPos, this.yPos, body.size * (this.client.gridSize / 4), body.angle + facingDirection);
    if (!overrideColor) {
        this.defHelper.fillPath(body.color, body.strokeColor, body.strokeWidth, context);
    } else {
        this.defHelper.fillPath(color, strokeColor, body.strokeWidth, context);
    }

    // And then draw the barrels
    this.drawBarrels(context, this.barrels, facingDirection, this.client, this.xPos, this.yPos, body.size);

    console.log("C");
}
3 Likes

Firstly, the entity should be drawn on top of the barrels. Secondly, setTimeout was there for testing, and I just forgot to remove it. Also, the rectangles are still rendering weirdly along with the entity rendering again barrel colored for some reason.

Just reverse what I said

draw(context, overrideColor, color, strokeColor, facingDirection){
    const body = this.definition[1];

    // Draw barrels first
    this.drawBarrels(context, this.barrels, facingDirection, this.client, this.xPos, this.yPos, body.size);

    // Then draw the entity
    this.defHelper.shapePath(body.sides, context, this.xPos, this.yPos, body.size * (this.client.gridSize / 4), body.angle + facingDirection);
    if (!overrideColor) {
        this.defHelper.fillPath(body.color, body.strokeColor, body.strokeWidth, context);
    } else {
        this.defHelper.fillPath(color, strokeColor, body.strokeWidth, context);
    }
}

One less problem!

When you use transformations like translate and rotate , you should use context.save() before the transformation and context.restore() after drawing. This will cause that each barrel’s transformations don’t affect others or the main entity.

2 Likes

Those were already there in the Barrel class’s draw() method. Is there any chance that context.restore() in that method runs before fillPath() finishes?

draw() method for Barrel class:

context.save();
context.translate(masterX, masterY);
context.rotate((this.angle + Math.PI) + facingAngle);
context.rect(this.x, this.y - (tankWidth / 2), tankLength, tankWidth:
this.defHelper.fillPath(this.color, this.strokeColor, this.strokeWidth, context);
context.restore();

Inside fillPath():

changeFillStyle(color);
changeStrokeStyle(strokeColor);
changeLineWidth(strokeWidth);
context.fill()
context.stroke()

the change functions just check whether the new value was the same as it was before, and if not, then change the value to the new value. I did it because I heard that changing context values all the time can cause performance issues.

No way. In JavaScript, (in the context of canvas drawing) the operations are synchronous. This means that the commands you issue to the canvas context are executed in the order you write them, and each command completes before the next one starts.

So, when context.restore() is called, all the drawing operations, including those inside fillPath() , have already been completed.

In your case…
Try to simplify your drawing logic (just for a bit). Like, draw one barrel at a time, or the entity without barrels until you isolate the issue.

3 Likes