1
\$\begingroup\$

What does all the position properties and functions on a pixi.js sprite / DisplayObject actually do? You can access sprite.x, sprite.width, sprite.getBounds(), sprite.toLocal(), sprite.toGlobal(), sprite.getGlobalPosition(), sprite.getLocalBounds().

And how are they affected by scale, pivot, position and parent properties?


I was very confused with all the various ways to get positioning from PIXI.js sprites, and didn't find the documentation helpful, so I created an example, to help me get an overview (at the end of this post).

This example also creates a camera, that can be used to center the view on selectable sprites.

// Size of the rectangles
const rectSize = 10;
// Rotation of the rotated rectangle
const rotation = 45;
// Zoom level of the camera, higher is closer
const zoomLevel = 2;
// Resolution of the app
const resolution = 1;









// Create the pixi app
const app = new PIXI.Application({
  width: 100,
  height: 100,
  backgroundColor: 0x000000,
  interactive: true,
  resolution: resolution
});
// HTML elements
const $body = $('body');
const $pixi = $('#pixi');
const $info = $('#info').find('tbody');

$pixi.append(app.view);

// Camera controls what we see
const camera = new PIXI.Container();
camera.scale.set(zoomLevel, zoomLevel);
app.stage.addChild(camera);

// Origin is the stage position - never move the stage
const origin = app.stage.position;

// Create some sprites
const rect = new PIXI.Graphics();
rect.beginFill(0xffffff);
rect.drawRect(0, 0, rectSize, rectSize);
const texture = app.renderer.generateTexture(rect);
const zeroedChild = PIXI.Sprite.from(texture);

const positionedChild = PIXI.Sprite.from(texture);
positionedChild.tint = 0xd83131
positionedChild.position.set(rectSize, rectSize);

const rotatedChild = PIXI.Sprite.from(texture);
rotatedChild.tint = 0x34d839;
rotatedChild.position.set(rectSize, rectSize);
rotatedChild.rotation = rotation * Math.PI / 180;

const scaledChild = PIXI.Sprite.from(texture);
scaledChild.tint = 0x4065d6;
scaledChild.position.set(rectSize, rectSize);
scaledChild.scale.set(2, 2);

const pivotedChild = PIXI.Sprite.from(texture);
pivotedChild.tint = 0xb637d6;
pivotedChild.position.set(rectSize, rectSize);
pivotedChild.pivot.set(pivotedChild.width / 2, pivotedChild.height / 2);

// Add all sprites to the camera
camera.addChild(zeroedChild, positionedChild, rotatedChild, scaledChild, pivotedChild);

updateInfo();

function updateInfo() {
  $info.html('');
  $info.append(info('Camera', camera, origin));
  $info.append(info('Zeroed Child', zeroedChild, origin));
  $info.append(info('Positioned Child', positionedChild, origin));
  $info.append(info(`Rotated Child (${rotation})`, rotatedChild, origin));
  $info.append(info('Scaled Child (2)', scaledChild, origin));
  $info.append(info('Pivoted Child (center)', pivotedChild, origin));
}

function info(name, sprite, origin) {
  const $row = $('<tr></tr>');
  if (sprite.parent) {
    if (!sprite.originalTint) {
      sprite.originalTint = sprite.tint;
    }

    $row.on('mouseenter', () => {
      const parent = sprite.parent;
      sprite.tint = 0xf4ff2b;
      parent.removeChild(sprite);
      parent.addChild(sprite);
    });
    $row.on('mouseleave', () => {
      sprite.tint = sprite.originalTint;
    });
    $row.on('click', () => {
      centerOn(sprite);
      sprite.parent.children.forEach((child) => {
        child.tint = child.originalTint;
      });
      sprite.tint = 0xf4ff2b;
    })
  }
  $row.append(`<td><b>${name}</b></td>`);
  $row.append(`<td>(${r(sprite.x)}, ${r(sprite.y)})</td>`);
  $row.append(`<td>(${r(sprite.toLocal(origin).x)}, ${r(sprite.toLocal(origin).y)})</td>`);
  $row.append(`<td>(${r(sprite.toGlobal(origin).x)}, ${r(sprite.toGlobal(origin).y)})</td/>`);
  $row.append(`<td>(${r(sprite.getGlobalPosition().x)}, ${r(sprite.getGlobalPosition().y)})</td>`);
  $row.append(`<td> (${r(sprite.scale.x)}, ${r(sprite.scale.y)})</td>`);
  $row.append(`<td>(${r(sprite.width)}, ${r(sprite.height)})</td>`);
  $row.append(`<td>(${r(sprite.getBounds().x)}, ${r(sprite.getBounds().y)}) | w: ${r(sprite.getBounds().width)}, h: ${r(sprite.getBounds().height)})</td>`);
  $row.append(`<td>(${r(sprite.getLocalBounds().x)}, ${r(sprite.getLocalBounds().y)}) | (${r(sprite.getLocalBounds().width)}, ${r(sprite.getLocalBounds().height)})</td></tr>`);


  return $row;
}


function r(n) {
  return Math.round(n * 100) / 100;
}

// Centers the camera on the given sprite
function centerOn(sprite) {
  if (sprite === camera) {
    camera.position.set(0, 0)
    updateInfo();
    return;
  }

	// Find the center of the renderer = canvas
  const centerRendererX = (app.renderer.width / resolution) / 2;
  const centerRendererY = (app.renderer.height / resolution) / 2;
  // Get the bounds of the sprite
  const bounds = sprite.getBounds();
  // Get the current position of the camera
  const cPos = camera.getGlobalPosition();
  // The bounds of the sprite is affected by the position of the camera (parent)
  // Subtract the camera position from the sprite position to put the sprite at it's original location
  // Then center it in the renderer/canvas, and find the middle of the sprite
  const x = centerRendererX - ((bounds.x - cPos.x) + bounds.width / 2);
  const y = centerRendererY - ((bounds.y - cPos.y) + bounds.height / 2);

  camera.position.set(x, y);
  updateInfo();
}
html,
body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
  font-size: 13px;
  font-family: courier;
}

b {
  display: block;
  font-size: 15px;
  width: 100%;
  text-align: center;
}


#info {
  width: 100%;
  border: 1px solid #fff;
  color: #fff;
  background-color: #000;
}

#info td {
  border: 1px solid #fff;
}

#info tr:hover {
  cursor: default;
  background-color: #252525;
  color: red !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.7.0/pixi.min.js"></script>
<table id="info">
  <thead>
    <tr>
      <th>Name</th>
      <th>(x, y)</th>
      <th>toLocal(stage)</th>
      <th>toGlobal(stage)</th>
      <th>getGlobalPosition()</th>
      <th>scale</th>
      <th>width/height</th>
      <th>getBounds()</th>
      <th>getLocalBounds()</th>
    </tr>
  </thead>
  <tbody></tbody>
</table>

<div id="pixi">

</div>

(Source)

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

In PIXI.js v4:

I found the documentation unhelpful as there are subtleties to getting a global position when there are local transformations like .pivot and .rotations. I found that the easiest way to get a global position when you only want some local transformations is to do something like.

let oldRot = sprite.rotation; 
sprite.rotation = 0;
let globalPosition = this.toGlobal(new PIXI.Point(0,0));
sprite.rotation = oldRot;

This will unapply the .rotation transformation when the matrix is rebuilt in toGlobal allowing you to get a position only affect by .pivot

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.