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"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
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
clipPathUnits="userSpaceOnUse"
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
clipPathUnits="userSpaceOnUse"
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
clipPathUnits="userSpaceOnUse"
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
clipPathUnits="userSpaceOnUse"
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
clipPathUnits="userSpaceOnUse"
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>
<pattern
y="0"
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>
<mask
maskUnits="userSpaceOnUse"
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
maskUnits="userSpaceOnUse"
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>
<filter
style="color-interpolation-filters:sRGB;"
inkscape:label="Blur"
id="filter4188">
<feGaussianBlur
stdDeviation="2.35 2.34"
result="blur"
id="feGaussianBlur4190" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#aeffff"
bordercolor="#666666"
borderopacity="1"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="0.35742971"
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)" />
<?xml version="1.0"?>
<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">
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath4243">
<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"/>
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath7847">
<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"/>
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath4243-1">
<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"/>
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath7876">
<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"/>
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath14693">
<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"/>
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath14952">
<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)"/>
</clipPath>
<filter color-interpolation-filters="sRGB" id="filter4198">
<feGaussianBlur id="feGaussianBlur4200" result="blur" stdDeviation="2.51 2.51"/>
</filter>
<mask id="mask4216" 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"/>
</mask>
<mask id="mask4222" 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"/>
</mask>
<pattern height="6" id="EMFhbasepattern" patternUnits="userSpaceOnUse" width="6" x="0" y="0"/>
</defs>
<metadata id="metadata7">image/svg+xml</metadata>
<g class="layer">
<title>Layer 1</title>
<g id="layer1">
<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"/>
<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"/>
<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)"/>
</g>
</svg>
</g>
</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>
<script>
const loaderScript = new Set();
let currentScript = null;
function loadScript(scriptName) {
if (window.cleanup) {
window.cleanup();
}
const container = document.getElementById("canvasContainer");
container.innerHTML = `<canvas id="myCanvas" width="1000" height="1000"></canvas>`;
const timestamp = new Date().getTime();
const script = document.createElement("script");
script.type = "module";
script.src = `build/${scriptName}?t=${timestamp}`;
currentScript = document.createElement("script");
currentScript.type = "module";
currentScript.src = `build/${scriptName}?t=${timestamp}`;
script.onload = () => {};
document.body.appendChild(script);
document.body.appendChild(currentScript);
}
//script initial

View file

@ -1,4 +1,5 @@
import { Tile } from "./tile"
import { Hand } from "./hand"
export class Deck {
private tiles: Array<Tile>;
@ -15,13 +16,13 @@ export class Deck {
size: number,
xOffset: number = 0,
yOffset: number = 0
): undefined {
): void {
let posX = x;
let posY = y;
for (let i = 1; i < 6; i++) {
if (i < 4) { // ordinaire
if (i < 4) { // famille
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);
posX += (75 + xOffset) * size;
}
@ -29,7 +30,7 @@ export class Deck {
posY += (100 + yOffset) * size;
} else if (i === 4) { //vent
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);
posX += (75 + xOffset) * size;
}
@ -37,7 +38,7 @@ export class Deck {
posY += (100 + yOffset) * size;
} else if (i === 5) { //vent
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);
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 {
for (let i = 1; i < 6; i++) {
if (i < 4) { // ordinaire
for (let j = 1; i < 10; i++) {
if (i < 4) { // famille
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));
@ -58,13 +126,13 @@ export class Deck {
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 k = 0; k < 4; k++) {
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 k = 0; k < 4; k++) {
this.tiles.push(new Tile(i, j, false));

View file

@ -1,91 +1,111 @@
import { Tile } from "../tile"
import { Deck } from "../deck"
const canvas = document.getElementById("myCanvas") as HTMLCanvasElement;
if (canvas) {
const ctx = canvas.getContext("2d");
if (ctx) {
// tapis
ctx.fillStyle = "#007730";
ctx.fillRect(50, 50, 1000, 1000);
// tuiles
let x = 180;
let y = 80;
let size = 0.75;
let xos = 50;
let yos = 100;
const deck = new Deck(false);
deck.displayFamilies(ctx, x, y, size, xos, yos);
// texte
ctx.fillStyle = "#DFDFFF";
ctx.font = "30px serif";
let delta = 50 * size;
let eps = 30 * size;
ctx.fillText("Caractère:", 55, y + delta + eps);
ctx.fillText("Rond:", 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
ctx.fillText(
"Est",
x + 0 * (xos + 75) * size,
y + 3 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Sud",
x + 1 * (xos + 75) * size,
y + 3 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Ouest",
x + 2 * (xos + 75) * size,
y + 3 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Nord",
x + 3 * (xos + 75) * size,
y + 3 * (yos + 100) * size + 150 * size
);
// dragon
ctx.fillText(
"Rouge",
x + 0 * (xos + 75) * size,
y + 4 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Vert",
x + 1 * (xos + 75) * size,
y + 4 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Blanc",
x + 2 * (xos + 75) * size,
y + 4 * (yos + 100) * size + 150 * size
);
} else {
console.error("Impossible d'obtenir le contexte du canvas.");
}
} else {
console.error("Canvas introuvable dans le DOM.");
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;
if (canvas) {
const ctx = canvas.getContext("2d");
if (ctx) {
// tapis
ctx.fillStyle = "#007730";
ctx.fillRect(50, 50, 1000, 1000);
// tuiles
let x = 180;
let y = 80;
let size = 0.75;
let xos = 50;
let yos = 100;
const deck = new Deck(false);
await preloadDeck(deck);
deck.displayFamilies(ctx, x, y, size, xos, yos);
// texte
ctx.fillStyle = "#DFDFFF";
ctx.font = "30px serif";
let delta = 50 * size;
let eps = 30 * size;
ctx.fillText("Caractère:", 55, y + delta + eps);
ctx.fillText("Rond:", 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
ctx.fillText(
"Est",
x + 0 * (xos + 75) * size,
y + 3 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Sud",
x + 1 * (xos + 75) * size,
y + 3 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Ouest",
x + 2 * (xos + 75) * size,
y + 3 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Nord",
x + 3 * (xos + 75) * size,
y + 3 * (yos + 100) * size + 150 * size
);
// dragon
ctx.fillText(
"Rouge",
x + 0 * (xos + 75) * size,
y + 4 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Vert",
x + 1 * (xos + 75) * size,
y + 4 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Blanc",
x + 2 * (xos + 75) * size,
y + 4 * (yos + 100) * size + 150 * size
);
window.cleanup = () => {
deck.cleanup();
}
} else {
console.error("Impossible d'obtenir le contexte du canvas.");
}
} else {
console.error("Canvas introuvable dans le DOM.");
}
}
display()

View file

@ -1,91 +1,131 @@
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;
if (canvas) {
const ctx = canvas.getContext("2d");
if (ctx) {
// tapis
ctx.fillStyle = "#007730";
ctx.fillRect(50, 50, 1000, 1000);
// tuiles
let x = 180;
let y = 80;
let size = 0.75;
let xos = 50;
let yos = 100;
const deck = new Deck(false);
deck.displayFamilies(ctx, x, y, size, xos, yos);
// texte
ctx.fillStyle = "#DFDFFF";
ctx.font = "30px serif";
let delta = 50 * size;
let eps = 30 * size;
ctx.fillText("Caractère:", 55, y + delta + eps);
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
ctx.fillText(
"Est",
x + 0 * (xos + 75) * size,
y + 3 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Sud",
x + 1 * (xos + 75) * size,
y + 3 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Ouest",
x + 2 * (xos + 75) * size,
y + 3 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Nord",
x + 3 * (xos + 75) * size,
y + 3 * (yos + 100) * size + 150 * size
);
// dragon
ctx.fillText(
"Rouge",
x + 0 * (xos + 75) * size,
y + 4 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Vert",
x + 1 * (xos + 75) * size,
y + 4 * (yos + 100) * size + 150 * size
);
ctx.fillText(
"Blanc",
x + 2 * (xos + 75) * size,
y + 4 * (yos + 100) * size + 150 * size
);
} else {
console.error("Impossible d'obtenir le contexte du canvas.");
}
} else {
console.error("Canvas introuvable dans le DOM.");
async function preloadDeck(deck: Deck) {
await deck.preload();
}
async function display () {
if (canvas) {
const ctx = canvas.getContext("2d") as NonNullable<CanvasRenderingContext2D>;
if (ctx) {
// double buffering
const offScreenCanvas = document.createElement('canvas') as HTMLCanvasElement;
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
let x = 150;
let y = 150;
let os = 75;
let size = 0.75;
const deck = new Deck(false);
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
offScreenCtx.fillStyle = "#DFDFFF";
offScreenCtx.font = "50px serif";
offScreenCtx.fillText("Exemples de main:", 65, 100);
// example hands
for (let i = 0; i < hands.length; i++) {
hands[i].drawHand(offScreenCtx, x, y + i * size * (100 + os), 5, size);
}
// dynamic hand
ehand.drawHand(offScreenCtx, x, 800, 5, size, selectedTile);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(offScreenCanvas, 0, 0);
}
const animationLoop = (currentTime: number) => {
const deltaTime = currentTime - lastTime;
if (deltaTime >= interval) {
lastTime = currentTime;
drawCanvas();
}
requestAnimationFrame(animationLoop);
}
// mouse event
canvas.addEventListener(
"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;
}
}
);
requestAnimationFrame(animationLoop);
window.cleanup = () => {
deck.cleanup();
hands.forEach(hand => hand.cleanup());
hands = [];
edeck.cleanup();
ehand.cleanup();
ctx.clearRect(0, 0, canvas.width, canvas.height);
offScreenCtx.clearRect(0, 0, offScreenCanvas.width, offScreenCanvas.height);
selectedTile = undefined;
}
} else {
console.error("Impossible d'obtenir le contexte du canvas.");
}
} else {
console.error("Canvas introuvable dans le DOM.");
}
}
display();

View file

@ -1,10 +1,24 @@
import { Tile } from "./tile"
export class hand {
export class Hand {
private tiles: Array<Tile>;
public constructor(tiles: Array<Tile> = []) {
this.tiles = tiles;
public constructor(stiles: string = "") {
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 {
@ -13,5 +27,53 @@ export class hand {
public pop(): Tile|undefined {
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 value: number;
private red: boolean;
private loadded: boolean;
private imgSrc: string;
private imgFront: HTMLImageElement;
private imgBack: HTMLImageElement;
private img: HTMLImageElement;
public constructor(family: number, value: number , red: boolean) {
this.family = family;
this.value = value;
this.red = red;
this.loadded = false;
this.imgSrc = "";
this.imgFront = new Image();
this.imgBack = new Image();
this.img = new Image();
this.setImgSrc();
}
@ -29,21 +37,31 @@ export class Tile {
x: number,
y: number,
size: number
): undefined {
const imgFront = new Image();
imgFront.src = "/img/Regular/Front.svg";
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);
};
): void {
ctx.drawImage(this.imgFront, x, y, 75 * size, 100 * size);
ctx.drawImage(this.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/"
if (this.family <= 3) {
this.imgSrc += ["", "Man", "Pin", "Sou"][this.family];
@ -58,4 +76,20 @@ export class Tile {
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;
});
}
}