deux pages (presque)

This commit is contained in:
Didictateur 2025-03-07 17:50:37 +01:00
parent 44c3717796
commit 84aeb36f83
9 changed files with 475 additions and 487 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,281 +1,42 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0"?>
<!-- Created with Inkscape (http://www.inkscape.org/) --> <svg width="300" height="400" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" version="1.1">
<defs id="defs4">
<svg <clipPath clipPathUnits="userSpaceOnUse" id="clipPath4243">
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" <circle cx="-264.66" cy="-198.21" fill="#000000" fill-opacity="0.3" fill-rule="nonzero" id="circle4245" r="293.95" stroke="#000000" stroke-dashoffset="0" stroke-linejoin="round" stroke-miterlimit="4" stroke-width="19.13"/>
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="300"
height="400"
viewBox="0 0 300 400"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="Back.svg"
inkscape:export-filename="C:\Users\Fluffy\Documents\Projects\ExtraRiichi\Tiles\Export\Regular\Back.png"
inkscape:export-xdpi="180"
inkscape:export-ydpi="180">
<defs
id="defs4">
<inkscape:path-effect
effect="skeletal"
id="path-effect7963"
is_visible="true"
pattern="m -90.825902,-314.06958 23.03016,41.38503 13.798268,-41.38503 z"
copytype="repeated_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0"
pattern-nodetypes="cccc" />
<inkscape:path-effect
effect="skeletal"
id="path-effect7830"
is_visible="true"
pattern="M -12.828427,33.715729 -17,-11 l 9.0000001,0 z"
copytype="repeated_stretched"
prop_scale="-1"
scale_y_rel="false"
spacing="5.1"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0"
pattern-nodetypes="cccc" />
<linearGradient
id="linearGradient10055"
osb:paint="solid">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop10057" />
</linearGradient>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4978"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ff5c00;stroke-width:1pt;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath4243">
<circle
style="opacity:1;fill:#000000;fill-opacity:0.29670332;fill-rule:nonzero;stroke:#000000;stroke-width:19.13299942;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="circle4245"
cx="-264.65997"
cy="-198.20665"
r="293.95438" />
</clipPath> </clipPath>
<clipPath <clipPath clipPathUnits="userSpaceOnUse" id="clipPath7847">
clipPathUnits="userSpaceOnUse" <ellipse cx="394" cy="552.36" fill="#822600" fill-rule="nonzero" id="ellipse7849" rx="349.5" ry="216" stroke-dashoffset="0" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="4" stroke-width="12"/>
id="clipPath7847">
<ellipse
style="opacity:1;fill:#822600;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:12;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="ellipse7849"
cx="394"
cy="552.36218"
rx="349.49533"
ry="216" />
</clipPath> </clipPath>
<clipPath <clipPath clipPathUnits="userSpaceOnUse" id="clipPath4243-1">
clipPathUnits="userSpaceOnUse" <circle cx="-264.66" cy="-198.21" fill="#000000" fill-opacity="0.3" fill-rule="nonzero" id="circle4245-4" r="293.95" stroke="#000000" stroke-dashoffset="0" stroke-linejoin="round" stroke-miterlimit="4" stroke-width="19.13"/>
id="clipPath4243-1">
<circle
style="opacity:1;fill:#000000;fill-opacity:0.29670332;fill-rule:nonzero;stroke:#000000;stroke-width:19.13299942;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="circle4245-4"
cx="-264.65997"
cy="-198.20665"
r="293.95438" />
</clipPath> </clipPath>
<clipPath <clipPath clipPathUnits="userSpaceOnUse" id="clipPath7876">
clipPathUnits="userSpaceOnUse" <circle cx="-264.66" cy="-198.21" fill="#000000" fill-opacity="0.3" fill-rule="nonzero" id="circle7878" r="293.95" stroke="#000000" stroke-dashoffset="0" stroke-linejoin="round" stroke-miterlimit="4" stroke-width="19.13"/>
id="clipPath7876">
<circle
style="opacity:1;fill:#000000;fill-opacity:0.29670332;fill-rule:nonzero;stroke:#000000;stroke-width:19.13299942;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="circle7878"
cx="-264.65997"
cy="-198.20665"
r="293.95438" />
</clipPath> </clipPath>
<clipPath <clipPath clipPathUnits="userSpaceOnUse" id="clipPath14693">
clipPathUnits="userSpaceOnUse" <rect fill="#a53c3c" fill-rule="nonzero" height="168.82" id="rect14695" rx="1.26" ry="3.75" stroke-dashoffset="0" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="4" stroke-width="8" transform="matrix(0.99939083,-0.03489951,0.03489951,0.99939083,0,0)" width="131.78" x="-332.6" y="383.5"/>
id="clipPath14693">
<rect
style="opacity:1;fill:#a53c3c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect14695"
width="131.78395"
height="168.82127"
x="-332.59583"
y="383.49765"
rx="1.2551664"
ry="3.7514515"
transform="matrix(0.99939083,-0.03489951,0.03489951,0.99939083,0,0)" />
</clipPath> </clipPath>
<clipPath <clipPath clipPathUnits="userSpaceOnUse" id="clipPath14952">
clipPathUnits="userSpaceOnUse" <ellipse cx="-271.34" cy="647.26" fill="#a53c3c" fill-rule="nonzero" id="ellipse14954" rx="69.06" ry="116.91" stroke-dashoffset="0" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="4" stroke-width="7" transform="matrix(0.99939083,-0.03489951,0.03489951,0.99939083,0,0)"/>
id="clipPath14952">
<ellipse
style="opacity:1;fill:#a53c3c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="ellipse14954"
cx="-271.34384"
cy="647.25604"
rx="69.057365"
ry="116.91089"
transform="matrix(0.99939083,-0.03489951,0.03489951,0.99939083,0,0)" />
</clipPath> </clipPath>
<pattern <filter color-interpolation-filters="sRGB" id="filter4198">
y="0" <feGaussianBlur id="feGaussianBlur4200" result="blur" stdDeviation="2.51 2.51"/>
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern" />
<filter
style="color-interpolation-filters:sRGB;"
inkscape:label=""
id="filter4198">
<feGaussianBlur
stdDeviation="2.51 2.51"
result="blur"
id="feGaussianBlur4200" />
</filter> </filter>
<mask <mask id="mask4216" maskUnits="userSpaceOnUse">
maskUnits="userSpaceOnUse" <rect fill="#ff3737" fill-rule="nonzero" height="400.78" id="rect4218" ry="40" stroke-dashoffset="0" stroke-linejoin="round" stroke-miterlimit="4" stroke-width="10" transform="scale(-1,-1)" width="300.06" x="-451.94" y="-1325.6"/>
id="mask4216">
<rect
ry="40"
y="-1325.6035"
x="-451.93805"
height="400.77808"
width="300.05896"
id="rect4218"
style="opacity:1;fill:#ff3737;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
transform="scale(-1,-1)" />
</mask> </mask>
<mask <mask id="mask4222" maskUnits="userSpaceOnUse">
maskUnits="userSpaceOnUse" <rect fill="#ff3737" fill-rule="nonzero" height="400.78" id="rect4224" ry="40" stroke-dashoffset="0" stroke-linejoin="round" stroke-miterlimit="4" stroke-width="10" width="300.06" x="0" y="652.28"/>
id="mask4222">
<rect
ry="40"
y="652.28351"
x="0"
height="400.77808"
width="300.05896"
id="rect4224"
style="opacity:1;fill:#ff3737;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</mask> </mask>
<filter <pattern height="6" id="EMFhbasepattern" patternUnits="userSpaceOnUse" width="6" x="0" y="0"/>
style="color-interpolation-filters:sRGB;"
inkscape:label="Blur"
id="filter4188">
<feGaussianBlur
stdDeviation="2.35 2.34"
result="blur"
id="feGaussianBlur4190" />
</filter>
</defs> </defs>
<sodipodi:namedview <metadata id="metadata7">image/svg+xml</metadata>
id="base" <g class="layer">
pagecolor="#aeffff" <title>Layer 1</title>
bordercolor="#666666" <g id="layer1">
borderopacity="1" <rect fill="#b268e8" fill-rule="nonzero" height="400.78" id="rect4164" ry="40" stroke-dashoffset="0" stroke-linejoin="round" stroke-miterlimit="4" stroke-width="10" width="300.06" y="-0.08"/>
inkscape:pageopacity="0" <path d="m-4.77,122.71c-4.88,-33.08 -12.08,-100.83 3.49,-123.01c20.28,-26.12 234.78,-20.43 264.59,1.85c12.9,8.74 -204.15,2.57 -227.4,31.19c-22.71,27.37 -35.26,133.09 -40.68,89.97z" fill="#b268e8" fill-opacity="0.78" fill-rule="evenodd" filter="url(#filter4198)" id="path4166" mask="url(#mask4222)" stroke-width="1px"/>
inkscape:pageshadow="2" <path d="m151.74,1677.38c-3.33,-9.32 -10.25,-68.46 5.31,-90.63c20.28,-26.12 219.44,-16.46 231.56,-9.93c11.07,5.32 -178.6,0.06 -204.85,34.87c-21.6,30 -26.5,82.17 -32.02,65.69z" fill="#b268e8" fill-opacity="0.39" fill-rule="evenodd" filter="url(#filter4198)" id="path4221" mask="url(#mask4216)" stroke-width="1px" transform="matrix(-1, 0, 0, -1, 451.938, 1977.89)"/>
inkscape:zoom="0.35742971" </g>
inkscape:cx="-92.256393"
inkscape:cy="-195.52606"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
showguides="true"
inkscape:guide-bbox="true"
units="px">
<inkscape:grid
type="xygrid"
id="grid4774"
visible="true"
dotted="false"
color="#3f3fff"
opacity="0.03921569"
empcolor="#3f3fff"
empopacity="0.07843137"
enabled="false" />
<sodipodi:guide
position="150,200"
orientation="0,1"
id="guide8231"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
<sodipodi:guide
position="150,200"
orientation="1,0"
id="guide8233"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-652.36216)">
<rect
style="opacity:1;fill:#ff3737;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4164"
width="300.05896"
height="400.77808"
x="0"
y="652.28351"
ry="40" />
<path
style="fill:#ffffff;fill-opacity:0.78431373;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4198)"
d="M -4.7687833,775.07096 C -9.6501835,741.99485 -16.84552,674.23676 -1.2788716,652.0641 18.998297,625.94378 233.50094,631.63117 263.31435,653.90999 276.21398,662.64856 59.158568,656.47658 35.908342,685.10013 13.199947,712.46776 0.65060847,818.18718 -4.7687833,775.07096 Z"
id="path4166"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc"
mask="url(#mask4222)" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4221"
d="m 151.73588,1025.0177 c -3.32683,-9.3138 -10.24843,-68.45389 5.31821,-90.62655 20.27717,-26.12032 219.43558,-16.45796 231.55506,-9.93184 11.07433,5.31702 -178.60366,0.0589 -204.85126,34.86646 -21.59349,30.0006 -26.50086,82.17843 -32.02201,65.69193 z"
style="fill:#000000;fill-opacity:0.39215687;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4198)"
transform="matrix(-1,0,0,-1,451.93806,1977.887)"
mask="url(#mask4216)" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

@ -72,20 +72,23 @@
<div id="canvasContainer"></div> <div id="canvasContainer"></div>
<script> <script>
const loaderScript = new Set(); let currentScript = null;
function loadScript(scriptName) { function loadScript(scriptName) {
if (window.cleanup) {
window.cleanup();
}
const container = document.getElementById("canvasContainer"); const container = document.getElementById("canvasContainer");
container.innerHTML = `<canvas id="myCanvas" width="1000" height="1000"></canvas>`; container.innerHTML = `<canvas id="myCanvas" width="1000" height="1000"></canvas>`;
const timestamp = new Date().getTime(); const timestamp = new Date().getTime();
const script = document.createElement("script"); currentScript = document.createElement("script");
script.type = "module"; currentScript.type = "module";
script.src = `build/${scriptName}?t=${timestamp}`; currentScript.src = `build/${scriptName}?t=${timestamp}`;
script.onload = () => {}; document.body.appendChild(currentScript);
document.body.appendChild(script);
} }
//script initial //script initial

View file

@ -1,4 +1,5 @@
import { Tile } from "./tile" import { Tile } from "./tile"
import { Hand } from "./hand"
export class Deck { export class Deck {
private tiles: Array<Tile>; private tiles: Array<Tile>;
@ -15,13 +16,13 @@ export class Deck {
size: number, size: number,
xOffset: number = 0, xOffset: number = 0,
yOffset: number = 0 yOffset: number = 0
): undefined { ): void {
let posX = x; let posX = x;
let posY = y; let posY = y;
for (let i = 1; i < 6; i++) { for (let i = 1; i < 6; i++) {
if (i < 4) { // ordinaire if (i < 4) { // famille
for (let j = 1; j < 10; j++) { for (let j = 1; j < 10; j++) {
const tile = new Tile(i, j, false); const tile = this.find(i, j) as NonNullable<Tile>;
tile.drawTile(ctx, posX, posY, size); tile.drawTile(ctx, posX, posY, size);
posX += (75 + xOffset) * size; posX += (75 + xOffset) * size;
} }
@ -29,7 +30,7 @@ export class Deck {
posY += (100 + yOffset) * size; posY += (100 + yOffset) * size;
} else if (i === 4) { //vent } else if (i === 4) { //vent
for (let j = 1; j < 5; j++) { for (let j = 1; j < 5; j++) {
const tile = new Tile(i, j, false); const tile = this.find(i, j) as NonNullable<Tile>;
tile.drawTile(ctx, posX, posY, size); tile.drawTile(ctx, posX, posY, size);
posX += (75 + xOffset) * size; posX += (75 + xOffset) * size;
} }
@ -37,7 +38,7 @@ export class Deck {
posY += (100 + yOffset) * size; posY += (100 + yOffset) * size;
} else if (i === 5) { //vent } else if (i === 5) { //vent
for (let j = 1; j < 4; j++) { for (let j = 1; j < 4; j++) {
const tile = new Tile(i, j, false); const tile = this.find(i, j) as NonNullable<Tile>;
tile.drawTile(ctx, posX, posY, size); tile.drawTile(ctx, posX, posY, size);
posX += (75 + xOffset) * size; posX += (75 + xOffset) * size;
} }
@ -45,10 +46,77 @@ export class Deck {
} }
} }
public pop(): Tile {
if (this.tiles.length === 0) {
}
return this.tiles.pop() as NonNullable<Tile>;
}
public find(family: number, value: number): Tile | undefined {
let n = undefined;
for (let i = 0; i < this.tiles.length; i++) {
if (
this.tiles[i].getFamily() === family &&
this.tiles[i].getValue() === value
) {
n = i;
}
}
if (n !== undefined) {
[this.tiles[n as NonNullable<number>], this.tiles[0]] = [this.tiles[0], this.tiles[n as NonNullable<number>]];
return this.tiles.shift();
} else {
return undefined;
}
}
public count(family: number, value: number): number {
let n = 0;
for (let i = 0; i < this.tiles.length; i++) {
if (
this.tiles[i].getFamily() === family &&
this.tiles[i].getValue() === value
) {
n++;
}
}
return n;
}
public shuffle(): undefined {
let newArray: Array<Tile> = [];
while (this.tiles.length > 0) {
let n = Math.floor(Math.random() * this.tiles.length);
[this.tiles[n], this.tiles[0]] = [this.tiles[0], this.tiles[n]];
newArray.push(this.tiles.shift() as NonNullable<Tile>);
}
this.tiles = newArray;
}
public getRandomHand(): Hand {
let hand = new Hand();
this.shuffle();
for (let i = 0; i < 13; i++) {
hand.push(this.pop());
}
return hand;
}
public cleanup(): void {
this.tiles.forEach(tile => tile.cleanup());
this.tiles = [];
}
public async preload(): Promise<void> {
for (let i = 0; i < this.tiles.length; i++) {
await this.tiles[i].preloadImg();
}
}
private initTiles(allowRed: boolean): undefined { private initTiles(allowRed: boolean): undefined {
for (let i = 1; i < 6; i++) { for (let i = 1; i < 6; i++) {
if (i < 4) { // ordinaire if (i < 4) { // famille
for (let j = 1; i < 10; i++) { for (let j = 1; j < 10; j++) {
this.tiles.push(new Tile(i, j, false)); this.tiles.push(new Tile(i, j, false));
this.tiles.push(new Tile(i, j, false)); this.tiles.push(new Tile(i, j, false));
this.tiles.push(new Tile(i, j, false)); this.tiles.push(new Tile(i, j, false));
@ -58,13 +126,13 @@ export class Deck {
this.tiles.push(new Tile(i, j, false)); this.tiles.push(new Tile(i, j, false));
} }
} }
} else if (i === 5) { //vent } else if (i === 4) { // vent
for (let j = 1; j < 5; j++) { for (let j = 1; j < 5; j++) {
for (let k = 0; k < 4; k++) { for (let k = 0; k < 4; k++) {
this.tiles.push(new Tile(i, j, false)); this.tiles.push(new Tile(i, j, false));
} }
} }
} else if (i === 6) { //vent } else if (i === 5) { // dragon
for (let j = 1; j < 4; j++) { for (let j = 1; j < 4; j++) {
for (let k = 0; k < 4; k++) { for (let k = 0; k < 4; k++) {
this.tiles.push(new Tile(i, j, false)); this.tiles.push(new Tile(i, j, false));

View file

@ -1,6 +1,18 @@
import { Tile } from "../tile"
import { Deck } from "../deck" import { Deck } from "../deck"
declare global {
interface Window {
clanup: () => void;
}
}
export {};
async function preloadDeck(deck: Deck) {
await deck.preload();
}
async function display() {
const canvas = document.getElementById("myCanvas") as HTMLCanvasElement; const canvas = document.getElementById("myCanvas") as HTMLCanvasElement;
if (canvas) { if (canvas) {
@ -18,6 +30,7 @@ if (canvas) {
let xos = 50; let xos = 50;
let yos = 100; let yos = 100;
const deck = new Deck(false); const deck = new Deck(false);
await preloadDeck(deck);
deck.displayFamilies(ctx, x, y, size, xos, yos); deck.displayFamilies(ctx, x, y, size, xos, yos);
// texte // texte
@ -82,10 +95,17 @@ if (canvas) {
y + 4 * (yos + 100) * size + 150 * size y + 4 * (yos + 100) * size + 150 * size
); );
window.cleanup = () => {
deck.cleanup();
}
} else { } else {
console.error("Impossible d'obtenir le contexte du canvas."); console.error("Impossible d'obtenir le contexte du canvas.");
} }
} else { } else {
console.error("Canvas introuvable dans le DOM."); console.error("Canvas introuvable dans le DOM.");
} }
}
display()

View file

@ -1,86 +1,124 @@
import { Tile } from "../tile" import { Deck } from "../deck";
import { Deck } from "../deck" import { Hand } from "../hand"
declare global {
interface Window {
cleanup: () => void;
}
}
export {}
const canvas = document.getElementById("myCanvas") as HTMLCanvasElement; const canvas = document.getElementById("myCanvas") as HTMLCanvasElement;
async function preloadDeck(deck: Deck) {
await deck.preload();
}
async function display () {
if (canvas) { if (canvas) {
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d") as NonNullable<CanvasRenderingContext2D>;
if (ctx) { if (ctx) {
// tapis // double buffering
ctx.fillStyle = "#007730"; const offScreenCanvas = document.createElement('canvas') as HTMLCanvasElement;
ctx.fillRect(50, 50, 1000, 1000); offScreenCanvas.width = canvas.width;
offScreenCanvas.height = canvas.height;
const offScreenCtx = offScreenCanvas.getContext('2d') as NonNullable<CanvasRenderingContext2D>;
//animation parameter
let lastTime = 0;
const FPS = 30;
const interval = 1000 / FPS;
// tuiles // tuiles
let x = 180; let x = 150;
let y = 80; let y = 150;
let os = 75;
let size = 0.75; let size = 0.75;
let xos = 50;
let yos = 100;
const deck = new Deck(false); const deck = new Deck(false);
deck.displayFamilies(ctx, x, y, size, xos, yos); await preloadDeck(deck);
let hands: Array<Hand> = [];
for (let i = 0; i < 4; i++) {
const hand = deck.getRandomHand();
hand.sort();
hands.push(hand);
}
// interactive hand
const edeck = new Deck(false);
await edeck.preload();
const ehand = edeck.getRandomHand();
ehand.sort();
let selectedTile: number|undefined = undefined;
// function to draw
const drawCanvas = async () => {
// clean screeen
offScreenCtx.clearRect(0, 0, canvas.width, canvas.height);
// tapis
offScreenCtx.fillStyle = "#007730";
offScreenCtx.fillRect(50, 50, 1000, 1000);
// texte // texte
ctx.fillStyle = "#DFDFFF"; offScreenCtx.fillStyle = "#DFDFFF";
ctx.font = "30px serif"; offScreenCtx.font = "50px serif";
offScreenCtx.fillText("Exemples de main:", 65, 100);
let delta = 50 * size; // example hands
let eps = 30 * size; for (let i = 0; i < hands.length; i++) {
ctx.fillText("Caractère:", 55, y + delta + eps); hands[i].drawHand(offScreenCtx, x, y + i * size * (100 + os), 5, size);
ctx.fillText("Pin:", 55, y + 3 * delta + yos * size + eps);
ctx.fillText("Bambou:", 55, y + 5 * delta + 2 * yos * size + eps);
ctx.fillText("Vent:", 55, y + 7 * delta + 3 * yos * size + eps);
ctx.fillText("Dragon:", 55, y + 9 * delta + 4 * yos * size + eps);
// familles
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 9; j++) {
ctx.fillText(
String(j+1),
x + j * (xos + 75) * size + 30 * size,
y + i * (yos + 100) * size + 150 * size
);
}
} }
// vent // dynamic hand
ctx.fillText( ehand.drawHand(offScreenCtx, x, 800, 5, size, selectedTile);
"Est",
x + 0 * (xos + 75) * size, ctx.clearRect(0, 0, canvas.width, canvas.height);
y + 3 * (yos + 100) * size + 150 * size ctx.drawImage(offScreenCanvas, 0, 0);
); }
ctx.fillText(
"Sud", const animationLoop = (currentTime: number) => {
x + 1 * (xos + 75) * size, const deltaTime = currentTime - lastTime;
y + 3 * (yos + 100) * size + 150 * size
); if (deltaTime >= interval) {
ctx.fillText( lastTime = currentTime;
"Ouest", drawCanvas();
x + 2 * (xos + 75) * size, }
y + 3 * (yos + 100) * size + 150 * size requestAnimationFrame(animationLoop);
); }
ctx.fillText(
"Nord", // mouse event
x + 3 * (xos + 75) * size, canvas.addEventListener(
y + 3 * (yos + 100) * size + 150 * size "mousemove",
(event) => {
const rect = canvas.getBoundingClientRect();
const mouseX = event.clientX - rect.left - x;
const mouseY = event.clientY - rect.top;
let q = Math.floor(mouseX / (80 * size));
let r = mouseX - q * 80 * size;
if (r <= 75 && q >= 0 && q < 14 && mouseY >= 800 && mouseY <= 800 + 100*size) {
selectedTile = q;
} else {
selectedTile = undefined;
}
}
); );
// dragon requestAnimationFrame(animationLoop);
ctx.fillText(
"Rouge", window.cleanup = () => {
x + 0 * (xos + 75) * size, deck.cleanup();
y + 4 * (yos + 100) * size + 150 * size hands.forEach(hand => hand.cleanup());
); hands = [];
ctx.fillText( edeck.cleanup();
"Vert", ehand.cleanup();
x + 1 * (xos + 75) * size, ctx.clearRect(0, 0, canvas.width, canvas.height);
y + 4 * (yos + 100) * size + 150 * size offScreenCtx.clearRect(0, 0, offScreenCanvas.width, offScreenCanvas.height);
); selectedTile = undefined;
ctx.fillText( }
"Blanc",
x + 2 * (xos + 75) * size,
y + 4 * (yos + 100) * size + 150 * size
);
} else { } else {
console.error("Impossible d'obtenir le contexte du canvas."); console.error("Impossible d'obtenir le contexte du canvas.");
@ -88,4 +126,6 @@ if (canvas) {
} else { } else {
console.error("Canvas introuvable dans le DOM."); console.error("Canvas introuvable dans le DOM.");
} }
}
display();

View file

@ -1,10 +1,24 @@
import { Tile } from "./tile" import { Tile } from "./tile"
export class hand { export class Hand {
private tiles: Array<Tile>; private tiles: Array<Tile>;
public constructor(tiles: Array<Tile> = []) { public constructor(stiles: string = "") {
this.tiles = tiles; this.tiles = [];
for (let i = 0; 2 * i + 1 < stiles.length; i++) {
let ss = stiles.substring(2*i, 2*(i+1));
if (ss[0] === "m") {
this.tiles.push(new Tile(1, Number(ss[1]), false));
} else if (ss[0] === "p") {
this.tiles.push(new Tile(2, Number(ss[1]), false));
} else if (ss[0] === "s") {
this.tiles.push(new Tile(3, Number(ss[1]), false));
} else if (ss[0] === "w") {
this.tiles.push(new Tile(4, Number(ss[1]), false));
} else if (ss[0] === "d") {
this.tiles.push(new Tile(5, Number(ss[1]), false));
} else {}
}
} }
public push(tile: Tile): undefined { public push(tile: Tile): undefined {
@ -14,4 +28,52 @@ export class hand {
public pop(): Tile|undefined { public pop(): Tile|undefined {
return this.tiles.pop(); return this.tiles.pop();
} }
public sort(): undefined {
for (let i = 0; i < this.tiles.length; i++) {
for (let j = 0; j < this.tiles.length-1; j++) {
if (!this.tiles[j].isLessThan(this.tiles[j+1])) {
[this.tiles[j], this.tiles[j+1]] = [this.tiles[j+1], this.tiles[j]];
}
}
}
}
public drawHand (
ctx: CanvasRenderingContext2D,
x: number,
y: number,
offset: number,
size: number,
focusedTiled: number|undefined = undefined
): void {
for (var i = 0; i < this.tiles.length; i++) {
if (i === focusedTiled) {
this.tiles[i].drawTile(
ctx,
x + i * 75 * size + i * offset * size,
y - 25 * size,
size
);
} else {
this.tiles[i].drawTile(
ctx,
x + i * 75 * size + i * offset * size,
y,
size
);
}
}
}
public async preload(): Promise<void> {
for (let i = 0; i < this.tiles.length; i++) {
await this.tiles[i].preloadImg();
}
}
public cleanup(): void {
this.tiles.forEach(tile => tile.cleanup());
this.tiles = [];
}
} }

View file

@ -2,13 +2,21 @@ export class Tile {
private family: number; private family: number;
private value: number; private value: number;
private red: boolean; private red: boolean;
private loadded: boolean;
private imgSrc: string; private imgSrc: string;
private imgFront: HTMLImageElement;
private imgBack: HTMLImageElement;
private img: HTMLImageElement;
public constructor(family: number, value: number , red: boolean) { public constructor(family: number, value: number , red: boolean) {
this.family = family; this.family = family;
this.value = value; this.value = value;
this.red = red; this.red = red;
this.loadded = false;
this.imgSrc = ""; this.imgSrc = "";
this.imgFront = new Image();
this.imgBack = new Image();
this.img = new Image();
this.setImgSrc(); this.setImgSrc();
} }
@ -29,21 +37,31 @@ export class Tile {
x: number, x: number,
y: number, y: number,
size: number size: number
): undefined { ): void {
const imgFront = new Image(); ctx.drawImage(this.imgFront, x, y, 75 * size, 100 * size);
imgFront.src = "/img/Regular/Front.svg"; ctx.drawImage(this.img, x, y, 75 * size, 100 * size);
imgFront.onload = () => {
ctx.drawImage(imgFront, x, y, 75 * size, 100 * size);
};
const img = new Image();
img.src = this.imgSrc;
img.onload = () => {
ctx.drawImage(img, x, y, 75 * size, 100 * size);
};
} }
private setImgSrc(): undefined { public isLessThan(t: Tile): boolean {
if (this.family < t.family) {
return true;
} else if (this.family === t.family && this.value <= t.value) {
return true;
} else {
return false;
}
}
public cleanup(): void {
this.imgFront.onload = null;
this.imgFront.onerror = null;
this.imgBack.onload = null;
this.imgBack.onerror = null;
this.img.onload = null;
this.img.onerror = null;
}
private setImgSrc(): void {
this.imgSrc = "/img/Regular/" this.imgSrc = "/img/Regular/"
if (this.family <= 3) { if (this.family <= 3) {
this.imgSrc += ["", "Man", "Pin", "Sou"][this.family]; this.imgSrc += ["", "Man", "Pin", "Sou"][this.family];
@ -58,4 +76,20 @@ export class Tile {
this.imgSrc += ["", "Chun", "Hatsu", "Haku"][this.value] + ".svg"; this.imgSrc += ["", "Chun", "Hatsu", "Haku"][this.value] + ".svg";
} }
} }
public async preloadImg(): Promise<void> {
await Promise.all([
this.loadImg(this.imgFront, "/img/Regular/Front.svg"),
this.loadImg(this.imgBack, "/img/Regular/Back.svg"),
this.loadImg(this.img, this.imgSrc)
]);
}
private loadImg(img: HTMLImageElement, src: string): Promise<void> {
return new Promise((resolve, reject) => {
img.onload = () => resolve();
img.onerror = () => reject();
img.src = src;
});
}
} }