add layout, add class for frigo game and implement drag and rop

This commit is contained in:
lagaffe 2026-04-14 00:01:15 +02:00
parent 51228d14d4
commit 438c140de5
9 changed files with 257 additions and 21 deletions

View file

@ -3,14 +3,14 @@
we use podman
#### to develop
run rundev.sh and you should be able to modify the code and have live update
run rundev.sh, the site will be available at http://localhost:5173/ and you should be able to modify the code and have it update live
#### to deploy
run run.sh, it build the production image and starts a container
I will try to make a clean setup, so 2 docker files, one for quick tests during dev the other for production. It is not possible to merge the two dockerfiles because the dev one needs a bind volume to update code from host which we dont want in production
I tried to make a clean setup, so 2 docker files, one for quick tests during dev the other for production. It is not possible to merge the two dockerfiles because the dev one needs a bind volume to update code from host which we dont want in production
the dev docker uses vite live update feature. to do that, it has a volume bind to it containing the code (src). this allows to be able to modify live without rebuilding the image nore re launching the container.
note on package-lock.json: package lock contains the exact versions of all the dependencie tree, it is generated by npm, but it is important to not regenarate it every time otherwise a dependency update could fuck the project. The package lock file in src/ comes from the dev docker, since src is used for bind volume, so when package.json is updated, it is necessary to run the dev docker to update package lock.
note on package-lock.json: package lock contains the exact versions of all the dependencie tree, it is generated by npm, but it is important to not regenarate it every time, otherwise a dependency update could fuck the project. The package lock file in src/ is generated by the dev docker, since src is used for bind volume. So when package.json is updated, it is necessary to run the dev docker to update package lock.

BIN
src/assets/img/caisse.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

BIN
src/assets/img/clubmate.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 KiB

BIN
src/assets/img/frigo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

39
src/dragAndDrop.js Normal file
View file

@ -0,0 +1,39 @@
function onDragMove(node, event, shift = { x: 0, y: 0 }) {
// shift is a tuple representing the shift between the coords of the node and the pointer
const dragPoint = event.global;
dragPoint.x -= shift.x;
dragPoint.y -= shift.y;
node.parent.toLocal(dragPoint, null, node.position);
}
function onDragEnd(node, onDrop) {
console.log("drop");
node.off("pointerup");
node.off("pointerupoutside");
node.parent.off("mousemove");
onDrop();
}
function onDragStart(node, onDrop, event) {
console.log("start drag");
node.on("pointerup", () => onDragEnd(node, onDrop));
node.on("pointerupoutside", () => onDragEnd(node, onDrop));
node.parent.eventMode =
node.parent.eventMode == "dynamic" ? "dynamic" : "static";
const dragShift = node.parent.toLocal(event.global, null);
dragShift.x -= node.x;
dragShift.y -= node.y;
node.parent.on("mousemove", (event) => {
onDragMove(node, event, dragShift);
});
}
function makeDragable(node, onDrop = () => {}) {
console.log("make drag");
node.eventMode = "static";
node.on("pointerdown", (event) => {
onDragStart(node, onDrop, event);
});
}
export { makeDragable };

View file

@ -2,9 +2,9 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Pixi + Docker Hello World</title>
<title>uradibou</title>
</head>
<body>
<body style="margin: 0">
<script type="module" src="/main.js"></script>
</body>
</html>

View file

@ -1,10 +1,31 @@
// description: This example demonstrates how to use a Container to group and manipulate multiple sprites
import "@pixi/layout";
import { Application, Assets, Container, Sprite } from "pixi.js";
import { makeDragable } from "./dragAndDrop.js";
const app = new Application();
let root = new Container();
const backgroundLayout = {
width: "100%",
height: "100%",
objectFit: "cover",
position: "absolute",
};
async function setup() {
await app.init({ background: "#1099bb", resizeTo: window });
root = app.stage;
root.layout = {
width: app.screen.width,
height: app.screen.height,
};
app.renderer.on("resize", () => {
root.layout = {
width: app.screen.width,
height: app.screen.height,
};
});
document.body.appendChild(app.canvas);
}
@ -18,6 +39,18 @@ async function preload() {
alias: "opinator",
src: "assets/img/opinator.avif",
},
{
alias: "frigo",
src: "assets/img/frigo.jpg",
},
{
alias: "clubmate",
src: "assets/img/clubmate.png",
},
{
alias: "mate_caisse",
src: "assets/img/caisse.jpg",
},
];
await Assets.load(assets);
}
@ -77,30 +110,74 @@ class Opinator {
} //else ignore, not enough move to get some distance
}
});
backgroundSprite.layout = {
width: "100%",
height: "100%",
objectFit: "contain",
};
gameContainer.addChild(backgroundSprite);
}
}
class Fridge {
constructor(gameContainer) {
const fridgeContainer = new Container();
fridgeContainer.layout = { width: "50%" };
const fridge = Sprite.from("frigo");
fridge.layout = backgroundLayout;
fridgeContainer.addChild(fridge);
const bottleContainer = new Container();
bottleContainer.layout = {
width: "50%",
flexDirection: "row",
flexWrap: "wrap",
};
const crate = Sprite.from("mate_caisse");
crate.layout = backgroundLayout;
bottleContainer.addChild(crate);
gameContainer.addChild(fridgeContainer);
gameContainer.addChild(bottleContainer);
const bottleLayout = {
width: "12%",
height: "16%",
position: "absolute",
};
for (let i = 0; i < 12; i++) {
const newBottle = Sprite.from("clubmate");
newBottle.layout = bottleLayout;
makeDragable(newBottle);
gameContainer.addChild(newBottle);
newBottle.x = 0;
newBottle.y = 0;
}
}
}
function switchToGame(gameContainer, newGame) {
//empty previous container
//create new game and add
}
(async () => {
await setup();
await preload();
const background = Sprite.from("background");
background.layout = backgroundLayout;
if (app.screen.width > app.screen.height) {
background.width = app.screen.width * 1.2;
background.scale.y = background.scale.x;
} else {
background.height = app.screen.height * 1.2;
background.scale.x = background.scale.y;
}
app.stage.addChild(background);
root.addChild(background);
const gameContainter = new Container();
const opinator = new Opinator(gameContainter);
app.stage.addChild(gameContainter);
gameContainter.layout = {
position: "absolute",
width: "100%",
height: "100%",
};
//const opinator = new Opinator(gameContainter);
const fridge = new Fridge(gameContainter);
root.addChild(gameContainter);
})();

119
src/package-lock.json generated
View file

@ -8,6 +8,7 @@
"name": "uradibou",
"version": "0.0.0",
"dependencies": {
"@pixi/layout": "^3.2.0",
"pixi.js": "^8.0.0"
},
"devDependencies": {
@ -83,6 +84,41 @@
"integrity": "sha512-nezytU2pw587fQstUu1AsJZDVEynjskwOL+kibwcdxsMBFqPsFFNA7xl0ii/gXuDi6M0xj3mfRJj8pBSc2jCfA==",
"license": "MIT"
},
"node_modules/@pixi/layout": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@pixi/layout/-/layout-3.2.0.tgz",
"integrity": "sha512-7TtDLHfaF65sTnYjrvRNqNJSQHMH109b04RtNgoy//BjR+pKWFUCgDMnUhs13fdNM0AkGccQW3UqCdylHuGvbA==",
"license": "MIT",
"workspaces": [
"src",
"docs"
],
"optionalDependencies": {
"@pixi/react": "^8.0.0"
},
"peerDependencies": {
"pixi.js": "^8",
"yoga-layout": "^3"
}
},
"node_modules/@pixi/react": {
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/@pixi/react/-/react-8.0.5.tgz",
"integrity": "sha512-Z1VRdnv9Gh+lTLzNKjpS7GaTNDjUxRVJNtIdtK2i0sCpigvjx5mvJ72EPLhBFgepB6j3ZCkL0YBb6BqgTGbhGA==",
"license": "MIT",
"optional": true,
"workspaces": [
"docs"
],
"dependencies": {
"its-fine": "^2.0.0",
"react-reconciler": "0.31.0"
},
"peerDependencies": {
"pixi.js": "^8.2.6",
"react": ">=19.0.0"
}
},
"node_modules/@rolldown/binding-android-arm64": {
"version": "1.0.0-rc.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz",
@ -364,6 +400,27 @@
"integrity": "sha512-k/9fOUGO39yd2sCjrbAJvGDEQvRwRnQIZlBz43roGwUZo5SHAmyVvSFyaVVZkicRVCaDXPKlbxrUcBuJoSWunQ==",
"license": "MIT"
},
"node_modules/@types/react": {
"version": "19.2.14",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
},
"node_modules/@types/react-reconciler": {
"version": "0.28.9",
"resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz",
"integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==",
"license": "MIT",
"optional": true,
"peerDependencies": {
"@types/react": "*"
}
},
"node_modules/@webgpu/types": {
"version": "0.1.69",
"resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.69.tgz",
@ -379,6 +436,14 @@
"node": ">=10.0.0"
}
},
"node_modules/csstype": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
@ -449,6 +514,19 @@
"integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw==",
"license": "MIT"
},
"node_modules/its-fine": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/its-fine/-/its-fine-2.0.0.tgz",
"integrity": "sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng==",
"license": "MIT",
"optional": true,
"dependencies": {
"@types/react-reconciler": "^0.28.9"
},
"peerDependencies": {
"react": "^19.0.0"
}
},
"node_modules/js-binary-schema-parser": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/js-binary-schema-parser/-/js-binary-schema-parser-2.0.3.tgz",
@ -816,6 +894,33 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/react": {
"version": "19.2.5",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz",
"integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==",
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-reconciler": {
"version": "0.31.0",
"resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.31.0.tgz",
"integrity": "sha512-7Ob7Z+URmesIsIVRjnLoDGwBEG/tVitidU0nMsqX/eeJaLY89RISO/10ERe0MqmzuKUUB1rmY+h1itMbUHg9BQ==",
"license": "MIT",
"optional": true,
"dependencies": {
"scheduler": "^0.25.0"
},
"engines": {
"node": ">=0.10.0"
},
"peerDependencies": {
"react": "^19.0.0"
}
},
"node_modules/rolldown": {
"version": "1.0.0-rc.15",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz",
@ -850,6 +955,13 @@
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15"
}
},
"node_modules/scheduler": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz",
"integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==",
"license": "MIT",
"optional": true
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@ -971,6 +1083,13 @@
"optional": true
}
}
},
"node_modules/yoga-layout": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz",
"integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==",
"license": "MIT",
"peer": true
}
}
}

View file

@ -9,7 +9,8 @@
"preview": "vite preview"
},
"dependencies": {
"pixi.js": "^8.0.0"
"pixi.js": "^8.0.0",
"@pixi/layout": "^3.2.0"
},
"devDependencies": {
"vite": "^8.0.4"