HTML5 Toile ensemble z-index

Est-il possible de définir l'index z d'un objet dessiné dans le canevas HTML5?

J'essaie de l'obtenir pour qu'un objet puisse être en face d'un " joueur "et un autre objet est derrière le"Joueur"

30
demandé sur j0k 2012-02-06 23:10:16

5 réponses

Oui..oui. Vous pouvez utiliser la composition pour "dessiner derrière" les pixels existants.

ctx.globalCompositeOperation='destination-over';

Voici un exemple et une Démo:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");

var cx=100;

drawCircle()
cx+=20;

ctx.globalCompositeOperation='destination-over';

$("#test").click(function(){
  drawCircle();
  cx+=20;
});

function drawCircle(){
  ctx.beginPath();
  ctx.arc(cx,150,20,0,Math.PI*2);
  ctx.closePath();
  ctx.fillStyle=randomColor();
  ctx.fill();
}

function randomColor(){ 
  return('#'+Math.floor(Math.random()*16777215).toString(16));
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id="test">Draw new circle behind.</button><br>
<canvas id="canvas" width=300 height=300></canvas>
40
répondu markE 2014-09-26 17:06:46

Une solution que j'ai trouvée fonctionne pour moi (et se débarrasse du scintillement, hourra!) consiste à utiliser deux toiles. (ou plus)

Je suppose que vous faites un jeu quelconque (puisque vous mentionnez un joueur) et que vous l'utilisez comme exemple.

Vous pouvez prendre une page de la façon dont windows fonctionne et mettre un canevas en premier comme arrière-plan avec un autre canevas au-dessus comme canevas de votre lecteur. Vous pouvez marquer le canevas du Joueur comme "sale" ou modifié chaque fois qu'il a été modifié et seulement redessiner le modifié couche en cas de besoin. Cela signifie que vous ne mettez à jour le second canevas que lorsque votre lecteur se déplace ou effectue une action.

Cette méthode peut être prise encore plus loin et vous pouvez ajouter une troisième toile pour un HUD avec des statistiques de gameplay qui ne sont modifiées que lorsque les statistiques du joueur changent.

Le code html peut ressembler à ceci:

<canvas id="background-canvas" height="500" width="1000" style="border:1px solid #000000;"></canvas>
<canvas id="player-canvas" height="500" width="1000" style="border:1px solid #000000;"></canvas>
<canvas id="hud-canvas" height="500" width="1000" style="border:1px solid #000000;"></canvas>
4
répondu nicholeous 2015-12-03 13:12:49

Dessinez d'abord les choses derrière, puis la chose, puis les autres objets.

Pour effectuer des tests hit, vous devrez peut-être parcourir votre liste d'affichage en arrière, en testant chaque objet. Cela fonctionnera si vous connaissez très bien les limites de l'objet.

Ou vous pouvez essayer quelques astuces graphiques standard comme dessiner les mêmes objets sur un autre canevas en mémoire avec des couleurs uniques pour chaque objet dessiné: pour tester cela, il suffit de vérifier la couleur du pixel sur le canevas en mémoire. Soigné ;-)

3
répondu Joe Parry 2012-02-06 22:12:10

Ou vous pouvez simplement utiliser un tableau contenant vos objets à dessiner puis trier ce tableau en utilisant la propriété zIndex de chaque enfant. Ensuite, vous jist itérer ce tableau et dessiner.

var canvas = document.querySelector('#game-canvas');
var ctx = canvas.getContext('2d');

// Define our shape "class".
var Shape = function (x, y, z, width, height) {
  this.x = x;
  this.y = y;
  this.zIndex = z;
  this.width = width;
  this.height = height;
};
// Define the shape draw function.
Shape.prototype.draw = function () {
  ctx.fillStyle = 'lime';
  ctx.fillRect(this.x, this.y, this.width, this.height);
};

// let's store the objects to be drawn.
var objects = [
  new Shape(10, 10, 0, 30, 30), // should be drawn first.
  new Shape(50, 10, 2, 30, 30), // should be drawn third.
  new Shape(90, 10, 1, 30, 30)  // should be drawn second.
];

// For performance reasons, we will first map to a temp array, sort and map the temp array to the objects array.
var map = objects.map(function (el, index) {
  return { index : index, value : el.zIndex };
});

// Now we need to sort the array by z index.
map.sort(function (a, b) {
  return a - b;
});

// We finaly rebuilt our sorted objects array.
var objectsSorted = map.map(function (el) {
  return objects[el.index];
});

// Now that objects are sorted, we can iterate to draw them.
for (var i = 0; i < objectsSorted.length; i++) {
  objectsSorted[i].draw();
}

// Enjoy !

Notez que je n'ai pas testé ce code et l'ai écrit sur mon téléphone portable, donc il pourrait y avoir des fautes de frappe, mais cela devrait permettre de comprendre le principe, j'espère.

3
répondu SkyzohKey 2016-08-25 21:35:16

Désolé, mais non, l'élément canvas aura son index z et tout ce qui y sera dessiné sera sur ce calque.

Si vous faites référence à des choses différentes sur la toile alors oui, tout ce qui est dessiné est dessiné au-dessus de ce qui était là avant.

1
répondu Andrew 2012-02-06 19:12:47