[ts][phaser-v3][phaser-v4] Fixed gameobject position when it is rotated.

This commit is contained in:
Davide Tantillo 2025-04-23 17:00:21 +02:00
parent 878a658ea9
commit 15766e8ef2
4 changed files with 130 additions and 14 deletions

View File

@ -13,12 +13,15 @@
<body class="p-4 flex flex-col items-center"> <body class="p-4 flex flex-col items-center">
<h1>Move origin</h1> <h1>Move origin</h1>
<h2>Demonstrate moving origin of Spine Gameobject, behaves like a sprite</h2> <h2>Demonstrate moving origin of Spine Gameobject, behaves like a sprite</h2>
<h2>When you use matter physics, origin is reset, because the body always stays around the game object.
Change game object size only after the object has been added to matter.</h2>
</body> </body>
<script> <script>
let cursors; let cursors;
let spineboy; let spineboy;
const levelWidth = 800; const levelWidth = 800;
const levelHeight = 600; const levelHeight = 600;
const gameobjects = []
class BasicExample extends Phaser.Scene { class BasicExample extends Phaser.Scene {
preload() { preload() {
@ -51,6 +54,7 @@
} }
} }
const physicsCells = cells.splice(cells.length - 2, 2);
let animations = undefined; let animations = undefined;
let prevWidth = 0; let prevWidth = 0;
@ -80,6 +84,8 @@
prevHeight = gameobject.displayHeight; prevHeight = gameobject.displayHeight;
} }
gameobjects.push(gameobject)
// moving origin at the center of the cell, we're still able to align spineboy and keep gameobject bounds align with the drawn skeleton // moving origin at the center of the cell, we're still able to align spineboy and keep gameobject bounds align with the drawn skeleton
const origin = 1 / (cells.length / 2 - 1) * Math.floor(i / 2) const origin = 1 / (cells.length / 2 - 1) * Math.floor(i / 2)
@ -122,17 +128,69 @@
gameobject.on("pointerout", () => defaultGraphicsElements()); gameobject.on("pointerout", () => defaultGraphicsElements());
}) })
const [physicsCell1, physicsCell2] = physicsCells;
const spineboy = this.add.spine(0, 0, "spineboy-data", "spineboy-atlas");
this.matter.add.gameObject(spineboy);
spineboy.displayWidth = (spineboy.width / spineboy.height) * height * .5;
spineboy.displayHeight = height * .5;
spineboy.x = physicsCell1.x + spineboy.displayWidth;
spineboy.y = physicsCell1.y + spineboy.displayHeight;
spineboy.setInteractive();
this.input.enableDebug(spineboy, 0xff00ff);
spineboy.on("pointerover", () => {
spineboy.y -= 50;
spineboy.x += 10;
});
const block = this.add.image(0, 0, "block");
this.matter.add.gameObject(block);
block.displayWidth = (block.width / block.height) * height * .5;
block.displayHeight = height * .5;
block.x = physicsCell2.x + block.displayWidth;
block.y = physicsCell2.y + block.displayHeight;
block.setInteractive();
this.input.enableDebug(block, 0xff00ff);
block.on("pointerover", () => {
block.y -= 50;
block.x += 10;
});
this.matter.add.rectangle(levelWidth - width, levelHeight - height, levelWidth, 1, { isStatic: true });
this.matter.add.rectangle(levelWidth - width, levelHeight - 2 * height, levelWidth, 1, { isStatic: true });
this.matter.add.rectangle(levelWidth - width, levelHeight, levelWidth, 1, { isStatic: true });
this.matter.add.rectangle(levelWidth - width, levelHeight - 2 * height, 1, height * 4, { isStatic: true });
this.matter.add.rectangle(levelWidth, levelHeight - 2 * height, 1, height * 4, { isStatic: true });
}
update(params) {
gameobjects.forEach((go) => {
go.angle += 0.05;
})
} }
} }
new Phaser.Game({ new Phaser.Game({
type: Phaser.AUTO, type: Phaser.AUTO,
width: levelWidth, width: levelWidth,
height: levelHeight, height: levelHeight,
type: Phaser.WEBGL, type: Phaser.WEBGL,
scene: [BasicExample], scene: [BasicExample],
physics: {
default: 'matter',
matter: {
debug: true,
gravity: { y: .15 },
},
},
plugins: { plugins: {
scene: [ scene: [
{ {

View File

@ -369,8 +369,8 @@ export class SpineGameObject extends DepthMixin(
tx = transform.tx, tx = transform.tx,
ty = transform.ty; ty = transform.ty;
let offsetX = (src.offsetX - src.displayOriginX) * src.scaleX; let offsetX = src.offsetX - src.displayOriginX;
let offsetY = (src.offsetY - src.displayOriginY) * src.scaleY; let offsetY = src.offsetY - src.displayOriginY;
sceneRenderer.drawSkeleton( sceneRenderer.drawSkeleton(
src.skeleton, src.skeleton,
@ -379,10 +379,10 @@ export class SpineGameObject extends DepthMixin(
-1, -1,
(vertices, numVertices, stride) => { (vertices, numVertices, stride) => {
for (let i = 0; i < numVertices; i += stride) { for (let i = 0; i < numVertices; i += stride) {
let vx = vertices[i]; let vx = vertices[i] + offsetX;
let vy = vertices[i + 1]; let vy = vertices[i + 1] + offsetY;
vertices[i] = vx * a + vy * c + tx + offsetX; vertices[i] = vx * a + vy * c + tx;
vertices[i + 1] = vx * b + vy * d + ty + offsetY; vertices[i + 1] = vx * b + vy * d + ty;
} }
} }
); );

View File

@ -13,12 +13,15 @@
<body class="p-4 flex flex-col items-center"> <body class="p-4 flex flex-col items-center">
<h1>Move origin</h1> <h1>Move origin</h1>
<h2>Demonstrate moving origin of Spine Gameobject, behaves like a sprite</h2> <h2>Demonstrate moving origin of Spine Gameobject, behaves like a sprite</h2>
<h2>When you use matter physics, origin is reset, because the body always stays around the game object.
Change game object size only after the object has been added to matter.</h2>
</body> </body>
<script> <script>
let cursors; let cursors;
let spineboy; let spineboy;
const levelWidth = 800; const levelWidth = 800;
const levelHeight = 600; const levelHeight = 600;
const gameobjects = []
class BasicExample extends Phaser.Scene { class BasicExample extends Phaser.Scene {
preload() { preload() {
@ -51,6 +54,7 @@
} }
} }
const physicsCells = cells.splice(cells.length - 2, 2);
let animations = undefined; let animations = undefined;
let prevWidth = 0; let prevWidth = 0;
@ -80,6 +84,8 @@
prevHeight = gameobject.displayHeight; prevHeight = gameobject.displayHeight;
} }
gameobjects.push(gameobject)
// moving origin at the center of the cell, we're still able to align spineboy and keep gameobject bounds align with the drawn skeleton // moving origin at the center of the cell, we're still able to align spineboy and keep gameobject bounds align with the drawn skeleton
const origin = 1 / (cells.length / 2 - 1) * Math.floor(i / 2) const origin = 1 / (cells.length / 2 - 1) * Math.floor(i / 2)
@ -122,17 +128,69 @@
gameobject.on("pointerout", () => defaultGraphicsElements()); gameobject.on("pointerout", () => defaultGraphicsElements());
}) })
const [physicsCell1, physicsCell2] = physicsCells;
const spineboy = this.add.spine(0, 0, "spineboy-data", "spineboy-atlas");
this.matter.add.gameObject(spineboy);
spineboy.displayWidth = (spineboy.width / spineboy.height) * height * .5;
spineboy.displayHeight = height * .5;
spineboy.x = physicsCell1.x + spineboy.displayWidth;
spineboy.y = physicsCell1.y + spineboy.displayHeight;
spineboy.setInteractive();
this.input.enableDebug(spineboy, 0xff00ff);
spineboy.on("pointerover", () => {
spineboy.y -= 50;
spineboy.x += 10;
});
const block = this.add.image(0, 0, "block");
this.matter.add.gameObject(block);
block.displayWidth = (block.width / block.height) * height * .5;
block.displayHeight = height * .5;
block.x = physicsCell2.x + block.displayWidth;
block.y = physicsCell2.y + block.displayHeight;
block.setInteractive();
this.input.enableDebug(block, 0xff00ff);
block.on("pointerover", () => {
block.y -= 50;
block.x += 10;
});
this.matter.add.rectangle(levelWidth - width, levelHeight - height, levelWidth, 1, { isStatic: true });
this.matter.add.rectangle(levelWidth - width, levelHeight - 2 * height, levelWidth, 1, { isStatic: true });
this.matter.add.rectangle(levelWidth - width, levelHeight, levelWidth, 1, { isStatic: true });
this.matter.add.rectangle(levelWidth - width, levelHeight - 2 * height, 1, height * 4, { isStatic: true });
this.matter.add.rectangle(levelWidth, levelHeight - 2 * height, 1, height * 4, { isStatic: true });
}
update(params) {
gameobjects.forEach((go) => {
go.angle += 0.05;
})
} }
} }
new Phaser.Game({ new Phaser.Game({
type: Phaser.AUTO, type: Phaser.AUTO,
width: levelWidth, width: levelWidth,
height: levelHeight, height: levelHeight,
type: Phaser.WEBGL, type: Phaser.WEBGL,
scene: [BasicExample], scene: [BasicExample],
physics: {
default: 'matter',
matter: {
debug: true,
gravity: { y: .15 },
},
},
plugins: { plugins: {
scene: [ scene: [
{ {

View File

@ -388,8 +388,8 @@ export class SpineGameObject extends DepthMixin(
tx = transform.tx, tx = transform.tx,
ty = transform.ty; ty = transform.ty;
let offsetX = (src.offsetX - src.displayOriginX) * src.scaleX; let offsetX = src.offsetX - src.displayOriginX;
let offsetY = (src.offsetY - src.displayOriginY) * src.scaleY; let offsetY = src.offsetY - src.displayOriginY;
sceneRenderer.drawSkeleton( sceneRenderer.drawSkeleton(
src.skeleton, src.skeleton,
@ -398,10 +398,10 @@ export class SpineGameObject extends DepthMixin(
-1, -1,
(vertices, numVertices, stride) => { (vertices, numVertices, stride) => {
for (let i = 0; i < numVertices; i += stride) { for (let i = 0; i < numVertices; i += stride) {
let vx = vertices[i]; let vx = vertices[i] + offsetX;
let vy = vertices[i + 1]; let vy = vertices[i + 1] + offsetY;
vertices[i] = vx * a + vy * c + tx + offsetX; vertices[i] = vx * a + vy * c + tx;
vertices[i + 1] = vx * b + vy * d + ty + offsetY; vertices[i + 1] = vx * b + vy * d + ty;
} }
} }
); );