Skip to content

Commit cf7c95e

Browse files
committed
Use pixi layout to make credits nicer and more adjustable.
2 parents a471ca5 + a3b2385 commit cf7c95e

File tree

3 files changed

+185
-94
lines changed

3 files changed

+185
-94
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@
1515
"vite": "^7.0.4"
1616
},
1717
"dependencies": {
18+
"@pixi/layout": "^3.1.0",
1819
"@pixi/sound": "^6.0.1",
1920
"culori": "^4.0.2",
2021
"lodash-es": "^4.17.21",
2122
"mathjs": "^14.5.3",
2223
"motion": "^12.23.12",
23-
"pixi.js": "^8.11.0"
24+
"pixi.js": "^8.11.0",
25+
"yoga-layout": "^3.2.1"
2426
}
2527
}

src/nodes/Credits.ts

Lines changed: 138 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,45 @@
1-
import { Point, Container, Graphics, HTMLText, Assets, Sprite } from "pixi.js";
1+
import "@pixi/layout";
2+
import { Container, HTMLText, Assets, Sprite, Texture } from "pixi.js";
23
import { HEIGHT, TEXT_FONT, theme, WIDTH } from "../constants";
3-
import { container } from "../util";
44
import GameNode from "./GameNode";
55
import ministryLogoPath from "../assets/img/ministry-logo.png";
66
import imaginaryLogoPath from "../assets/img/imaginary-logo.png";
77
import mpiLogoPath from "../assets/img/mpi-logo.png";
88
import { inputs } from "../inputs";
9+
import { LayoutContainer } from "@pixi/layout/components";
910

1011
export default class Credits extends GameNode {
1112
onFinish?: () => void;
1213

1314
constructor() {
1415
super();
1516
document.addEventListener("keydown", this.handleKeyDown);
16-
this.view.position.x = WIDTH / 2;
17-
this.view.position.y = HEIGHT / 2;
18-
19-
const boxHeight = HEIGHT * 0.9;
20-
const boxWidth = WIDTH * 0.9;
21-
this.view.addChild(
22-
container(
23-
new Graphics().roundRect(
24-
-boxWidth / 2,
25-
-boxHeight / 2,
26-
boxWidth,
27-
boxHeight - 350
28-
)
29-
)
30-
);
31-
this.view.addChild(
32-
container(
33-
new Graphics().roundRect(
34-
-boxWidth / 2,
35-
boxHeight / 2 - 350,
36-
boxWidth,
37-
350
38-
)
39-
).fill("white")
40-
);
17+
this.view.layout = {
18+
width: WIDTH,
19+
height: HEIGHT,
20+
display: "flex",
21+
flexDirection: "column",
22+
justifyContent: "center",
23+
alignItems: "center",
24+
gap: 50,
25+
};
26+
const credits = new LayoutContainer({
27+
layout: {
28+
padding: 50,
29+
borderRadius: 20,
30+
backgroundColor: "#0008",
31+
borderColor: "white",
32+
borderWidth: 2,
33+
display: "flex",
34+
flexDirection: "column",
35+
alignItems: "center",
36+
gap: 20,
37+
},
38+
});
39+
this.view.addChild(credits);
40+
4141
const titleText = new HTMLText({
42+
layout: true,
4243
text: "Credits",
4344
style: {
4445
align: "center",
@@ -48,49 +49,65 @@ export default class Credits extends GameNode {
4849
fontSize: 72,
4950
},
5051
});
51-
titleText.anchor = { x: 0.5, y: 0.5 };
52-
titleText.position.y = -HEIGHT / 2 + 144;
53-
this.view.addChild(titleText);
54-
55-
const width = WIDTH * 0.2;
56-
this.drawCredit(
57-
new Point(-width, -HEIGHT * 0.3),
58-
"Concept & Development",
59-
"Nat Alison"
60-
);
52+
credits.addChild(titleText);
6153

62-
this.drawCredit(
63-
new Point(-width, -HEIGHT * 0.2),
64-
"Content & Coordination",
65-
"Christian Stussak",
66-
"Andreas Matt",
67-
"Skye Rothstein"
68-
);
69-
this.drawCredit(new Point(-width, HEIGHT * 0), "Music", "Landis Seralian");
70-
this.drawCredit(
71-
new Point(width, -HEIGHT * 0.3),
72-
"Support",
73-
"Karla Schön",
74-
"Oliver Schön"
75-
);
76-
this.drawCredit(
77-
new Point(width, -HEIGHT * 0.125),
78-
"Arcade Machine Graphic Design",
79-
"Eric Londaits"
80-
);
81-
this.drawCredit(
82-
new Point(width, HEIGHT * 0),
83-
"Arcade Machine Building",
84-
"Retr-O-Mat"
54+
const columns = new Container({
55+
layout: {
56+
display: "flex",
57+
gap: 75,
58+
},
59+
});
60+
credits.addChild(columns);
61+
62+
const column1 = new Container({
63+
layout: {
64+
display: "flex",
65+
flexDirection: "column",
66+
gap: 20,
67+
},
68+
});
69+
const column2 = new Container({
70+
layout: {
71+
display: "flex",
72+
flexDirection: "column",
73+
gap: 20,
74+
},
75+
});
76+
77+
columns.addChild(column1);
78+
columns.addChild(column2);
79+
80+
column1.addChild(this.drawCredit("Concept & Development", "Nat Alison"));
81+
82+
column1.addChild(
83+
this.drawCredit(
84+
"Content & Coordination",
85+
"Christian Stussak",
86+
"Andreas Matt",
87+
"Skye Rothstein"
88+
)
8589
);
86-
// this.drawCredit(new Point(0, HEIGHT * 0.1), "Funded by", "BMFTR");
90+
column1.addChild(this.drawCredit("Music", "Landis Seralian"));
91+
92+
column2.addChild(this.drawCredit("Support", "Karla Schön", "Oliver Schön"));
93+
column2.addChild(
94+
this.drawCredit("Arcade Machine Graphic Design", "Eric Londaits")
95+
),
96+
column2.addChild(
97+
this.drawCredit("Arcade Machine Building", "Retr-O-Mat")
98+
);
8799
}
88100

89-
drawCredit(position: Point, title: string, ...names: string[]) {
90-
const credit = new Container();
91-
credit.position = position;
92-
this.view.addChild(credit);
101+
drawCredit(title: string, ...names: string[]) {
102+
const credit = new Container({
103+
layout: {
104+
display: "flex",
105+
flexDirection: "column",
106+
alignItems: "center",
107+
},
108+
});
93109
const titleText = new HTMLText({
110+
layout: true,
94111
text: title,
95112
style: {
96113
align: "center",
@@ -100,11 +117,11 @@ export default class Credits extends GameNode {
100117
fontSize: 40,
101118
},
102119
});
103-
titleText.anchor = { x: 0.5, y: 0 };
104120
credit.addChild(titleText);
105121

106-
for (let [i, name] of names.entries()) {
122+
for (let [_i, name] of names.entries()) {
107123
const nameText = new HTMLText({
124+
layout: true,
108125
text: name,
109126
style: {
110127
align: "center",
@@ -114,10 +131,9 @@ export default class Credits extends GameNode {
114131
fontSize: 40,
115132
},
116133
});
117-
nameText.anchor = { x: 0.5, y: 0 };
118-
nameText.position.y = (i + 1) * 50;
119134
credit.addChild(nameText);
120135
}
136+
return credit;
121137
}
122138

123139
handleKeyDown = (e: KeyboardEvent) => {
@@ -133,10 +149,26 @@ export default class Credits extends GameNode {
133149
};
134150

135151
async load() {
136-
const fundedBy = new Container();
137-
fundedBy.position = { x: -WIDTH * 0.3, y: HEIGHT * 0.2 };
152+
const logos = new LayoutContainer({
153+
layout: {
154+
backgroundColor: "white",
155+
borderRadius: 20,
156+
display: "flex",
157+
gap: 100,
158+
padding: 50,
159+
},
160+
});
161+
162+
const fundedBy = new Container({
163+
layout: {
164+
display: "flex",
165+
flexDirection: "column",
166+
alignItems: "center",
167+
},
168+
});
138169
const ministryLogoTexture = await Assets.load(ministryLogoPath);
139170
const titleText = new HTMLText({
171+
layout: true,
140172
text: "Funded by",
141173
style: {
142174
align: "center",
@@ -146,20 +178,22 @@ export default class Credits extends GameNode {
146178
fontSize: 40,
147179
},
148180
});
149-
titleText.anchor = { x: 0.5, y: 0 };
150181
fundedBy.addChild(titleText);
151-
const sprite = new Sprite(ministryLogoTexture);
152-
sprite.anchor = { x: 0.5, y: 0 };
153-
sprite.position.y = 50;
154-
sprite.scale = 0.3;
155-
fundedBy.addChild(sprite);
156-
this.view.addChild(fundedBy);
157-
158-
const partOf = new Container();
159-
partOf.position = { x: WIDTH * 0.1, y: HEIGHT * 0.2 };
182+
fundedBy.addChild(this.drawImage(ministryLogoTexture, 250));
183+
logos.addChild(fundedBy);
184+
185+
const partOf = new Container({
186+
layout: {
187+
display: "flex",
188+
flexDirection: "column",
189+
alignItems: "center",
190+
gap: 20,
191+
},
192+
});
160193
const imaginaryLogoTexture = await Assets.load(imaginaryLogoPath);
161194
const mpiLogoTexture = await Assets.load(mpiLogoPath);
162195
const titleText2 = new HTMLText({
196+
layout: true,
163197
text: "Part of quantum-arcade.org by",
164198
style: {
165199
align: "center",
@@ -169,18 +203,29 @@ export default class Credits extends GameNode {
169203
fontSize: 40,
170204
},
171205
});
172-
titleText2.anchor = { x: 0.5, y: 0 };
173206
partOf.addChild(titleText2);
174-
const sprite1 = new Sprite(imaginaryLogoTexture);
175-
sprite1.anchor = { x: 0.5, y: 0 };
176-
sprite1.position = { x: -300, y: 100 };
177-
sprite1.scale = 0.5;
178-
const sprite2 = new Sprite(mpiLogoTexture);
179-
sprite2.anchor = { x: 0.5, y: 0 };
180-
sprite2.position = { x: 300, y: 50 };
181-
sprite2.scale = 0.5;
182-
partOf.addChild(sprite1);
183-
partOf.addChild(sprite2);
184-
this.view.addChild(partOf);
207+
const partOfSprites = new Container({
208+
layout: {
209+
display: "flex",
210+
alignItems: "center",
211+
justifyContent: "center",
212+
gap: 20,
213+
},
214+
});
215+
partOfSprites.addChild(this.drawImage(imaginaryLogoTexture, 300));
216+
partOfSprites.addChild(this.drawImage(mpiLogoTexture, 500));
217+
partOf.addChild(partOfSprites);
218+
logos.addChild(partOf);
219+
this.view.addChild(logos);
220+
}
221+
222+
drawImage(texture: Texture, width: number) {
223+
return new Sprite({
224+
texture,
225+
layout: {
226+
width,
227+
height: (width * texture.height) / texture.width,
228+
},
229+
});
185230
}
186231
}

0 commit comments

Comments
 (0)