app area resizes, cards dynamically fan and lift on hover
This commit is contained in:
		@ -1,39 +1,75 @@
 | 
				
			|||||||
import { Assets, Container, Size, Sprite } from "pixi.js";
 | 
					import { Assets, Container, Size, PointData, Sprite } from "pixi.js";
 | 
				
			||||||
import { Card } from "./Card";
 | 
					import { Card } from "./Card";
 | 
				
			||||||
 | 
					import { CARD_HEIGHT, CARD_WIDTH } from "./constants";
 | 
				
			||||||
const CARD_WIDTH = 144;
 | 
					 | 
				
			||||||
const CARD_HEIGHT = 224;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const spritesheet = await Assets.load("/public/assets/cards.json");
 | 
					const spritesheet = await Assets.load("/public/assets/cards.json");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class Hand {
 | 
					export class Hand {
 | 
				
			||||||
	cards: Container;
 | 
						#cards: Sprite[];
 | 
				
			||||||
	#containerSize: Size;
 | 
						#container: Container;
 | 
				
			||||||
	#offset: number;
 | 
						#maxWidth: number;
 | 
				
			||||||
	#roomRemaining: number;
 | 
						#parent: Size & PointData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	constructor(maxWidth: number, cards: Card[] = []) {
 | 
						constructor(maxWidth: number, cards: Card[] = []) {
 | 
				
			||||||
		if (maxWidth < CARD_WIDTH) {
 | 
							if (maxWidth < CARD_WIDTH) {
 | 
				
			||||||
			throw new Error("hand cannot be narrower than a single card");
 | 
								throw new Error("hand cannot be narrower than a single card");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		this.#roomRemaining = maxWidth;
 | 
							this.#maxWidth = maxWidth;
 | 
				
			||||||
		this.#containerSize = { width: maxWidth, height: CARD_HEIGHT };
 | 
							this.#container = new Container();
 | 
				
			||||||
		this.#offset = CARD_WIDTH;
 | 
							this.#parent = { x: 0, y: 0, width: 0, height: 0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const sprites: Container = new Container();
 | 
							if (cards.length > 0) {
 | 
				
			||||||
		sprites.position.set(0, 0);
 | 
								const sprites: Sprite[] = [];
 | 
				
			||||||
 | 
								for (const card of cards) {
 | 
				
			||||||
 | 
									this.add(card);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		let x = 0;
 | 
								this.#cards = sprites;
 | 
				
			||||||
		for (const card of cards) {
 | 
								this.#container.addChild(...sprites);
 | 
				
			||||||
			const sprite = new Sprite(spritesheet.textures[card]);
 | 
								this.fanCards();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
			sprite.x = x;
 | 
								this.#cards = [];
 | 
				
			||||||
			x += this.#offset;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			sprites.addChild(sprite);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		this.cards = sprites;
 | 
						add(card: Card) {
 | 
				
			||||||
 | 
							const sprite = new Sprite(spritesheet.textures[card]);
 | 
				
			||||||
 | 
							sprite.eventMode = "dynamic";
 | 
				
			||||||
 | 
							sprite.onmouseenter = () => {
 | 
				
			||||||
 | 
								sprite.y -= 50;
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							sprite.onmouseleave = () => {
 | 
				
			||||||
 | 
								sprite.y += 50;
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							this.#cards.push(sprite);
 | 
				
			||||||
 | 
							this.#container.addChild(sprite);
 | 
				
			||||||
 | 
							this.fanCards();
 | 
				
			||||||
 | 
							this.repositionContainer();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						parentArea(x: number, y: number, width: number, height: number) {
 | 
				
			||||||
 | 
							this.#parent = { x, y, width, height };
 | 
				
			||||||
 | 
							this.repositionContainer();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repositionContainer() {
 | 
				
			||||||
 | 
							this.#container.pivot.set(this.#container.width / 2, CARD_HEIGHT);
 | 
				
			||||||
 | 
							this.#container.position.set(this.#parent.width / 2, this.#parent.height);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fanCards() {
 | 
				
			||||||
 | 
							const count = this.#cards.length;
 | 
				
			||||||
 | 
							const max = this.#maxWidth;
 | 
				
			||||||
 | 
							const offset = count * CARD_WIDTH > max ? max / count : CARD_WIDTH;
 | 
				
			||||||
 | 
							let x = 0;
 | 
				
			||||||
 | 
							for (const card of this.#cards) {
 | 
				
			||||||
 | 
								card.x = x;
 | 
				
			||||||
 | 
								x += offset;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						getContainer(): Container {
 | 
				
			||||||
 | 
							return this.#container;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								client/src/constants.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								client/src/constants.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					export const CARD_WIDTH = 144;
 | 
				
			||||||
 | 
					export const CARD_HEIGHT = 224;
 | 
				
			||||||
@ -1,37 +1,59 @@
 | 
				
			|||||||
import { Application, Assets, Sprite } from "pixi.js";
 | 
					import { Application } from "pixi.js";
 | 
				
			||||||
import { Hand } from "./Hand";
 | 
					import { Hand } from "./Hand";
 | 
				
			||||||
 | 
					import { Card } from "./Card";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const cards: Card[] = [
 | 
				
			||||||
 | 
						"threeOfClubs",
 | 
				
			||||||
 | 
						"twoOfDiamonds",
 | 
				
			||||||
 | 
						"aceOfClubs",
 | 
				
			||||||
 | 
						"eightOfDiamonds",
 | 
				
			||||||
 | 
						"nineOfSpades",
 | 
				
			||||||
 | 
						"sixOfClubs",
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(async () => {
 | 
					(async () => {
 | 
				
			||||||
	// Create a new application
 | 
					 | 
				
			||||||
	const app = new Application();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Initialize the application
 | 
					 | 
				
			||||||
	await app.init({ background: "#1099bb", resizeTo: window });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Append the application canvas to the document body
 | 
					 | 
				
			||||||
	document.getElementById("pixi-container")!.appendChild(app.canvas);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	try {
 | 
						try {
 | 
				
			||||||
		const hand = new Hand(1000, [
 | 
							// Create and initialize a new application
 | 
				
			||||||
			"fourOfDiamonds",
 | 
							const app = new Application();
 | 
				
			||||||
			"eightOfDiamonds",
 | 
							await app.init({
 | 
				
			||||||
			"threeOfClubs",
 | 
								background: "#338140",
 | 
				
			||||||
			"kingOfSpades",
 | 
								width: window.innerWidth,
 | 
				
			||||||
		]);
 | 
								height: window.innerHeight,
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		app.stage.addChild(hand.cards);
 | 
							// Append the application canvas to the document body
 | 
				
			||||||
 | 
							document.getElementById("pixi-container")!.appendChild(app.canvas);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		hand.cards.position.set(app.screen.width / 2, 0);
 | 
							const hand = new Hand(350, []);
 | 
				
			||||||
		hand.cards.pivot.set(hand.cards.width / 2, 0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Listen for animate update
 | 
							hand.parentArea(0, 0, app.screen.width, app.screen.height);
 | 
				
			||||||
		// app.ticker.add((time) => {
 | 
					
 | 
				
			||||||
		// 	// Just for fun, let's rotate mr rabbit a little.
 | 
							app.stage.addChild(hand.getContainer());
 | 
				
			||||||
		// 	// * Delta is 1 if running at 100% performance *
 | 
					
 | 
				
			||||||
		// 	// * Creates frame-independent transformation *
 | 
							// When the user resizes the window, resize the app. There is a plugin
 | 
				
			||||||
		// 	bunny.rotation += 0.1 * time.deltaTime;
 | 
							// for doing this automatically, but it doesn't reposition stage's
 | 
				
			||||||
		// });
 | 
							// children. Since I need those repositioned, I am handling all the
 | 
				
			||||||
 | 
							// resizing myself. Does handling it myself create some kind of strange
 | 
				
			||||||
 | 
							// issues? I sure hope not!
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							// If strange issues are encountered, check out how coordinates work in
 | 
				
			||||||
 | 
							// PixiJS:
 | 
				
			||||||
 | 
							// https://pixijs.com/8.x/guides/concepts/scene-graph#local-vs-global-coordinates
 | 
				
			||||||
 | 
							window.addEventListener?.("resize", () => {
 | 
				
			||||||
 | 
								app.renderer.resize(window.innerWidth, window.innerHeight);
 | 
				
			||||||
 | 
								hand.parentArea(0, 0, app.screen.width, app.screen.height);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let ms = 0;
 | 
				
			||||||
 | 
							let elapsed = 0;
 | 
				
			||||||
 | 
							app.ticker.add((time) => {
 | 
				
			||||||
 | 
								elapsed += time.elapsedMS;
 | 
				
			||||||
 | 
								if (cards.length && elapsed >= ms) {
 | 
				
			||||||
 | 
									ms += 300;
 | 
				
			||||||
 | 
									hand.add(cards.pop()!);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
	} catch (err) {
 | 
						} catch (err) {
 | 
				
			||||||
		console.log(err);
 | 
							console.error(err);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
})();
 | 
					})();
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user