|
|
@@ -239,7 +239,7 @@ class MapEditor {
|
|
|
this.isDragging = false;
|
|
|
this.lastMousePos = { x: 0, y: 0 };
|
|
|
this.selectedTile = null;
|
|
|
- this.tileSize = 30; // Taille de base d'une tuile hexagonale
|
|
|
+ this.tileSize = 40; // Rayon de l'hexagone (du centre au sommet)
|
|
|
|
|
|
this.init();
|
|
|
}
|
|
|
@@ -263,52 +263,83 @@ class MapEditor {
|
|
|
}
|
|
|
|
|
|
setupCanvas() {
|
|
|
- // Calculer la taille du canvas
|
|
|
- const hexWidth = this.tileSize * 1.5;
|
|
|
- const hexHeight = this.tileSize * Math.sqrt(3);
|
|
|
-
|
|
|
- const canvasWidth = (mapWidth + 0.5) * hexWidth;
|
|
|
- const canvasHeight = (mapHeight + 0.5) * hexHeight;
|
|
|
-
|
|
|
- this.canvas.style.width = canvasWidth + 'px';
|
|
|
- this.canvas.style.height = canvasHeight + 'px';
|
|
|
+ // La taille du canvas est définie dynamiquement dans renderMap() selon l'enveloppe.
|
|
|
this.canvas.style.transformOrigin = '0 0';
|
|
|
}
|
|
|
|
|
|
+ // Conversion axial -> pixels pour hexagones pointus (pointy-top)
|
|
|
+ axialToPixel(q, r) {
|
|
|
+ const size = this.tileSize; // rayon (centre -> sommet)
|
|
|
+ const x = size * Math.sqrt(3) * (q + r / 2);
|
|
|
+ const y = size * 1.5 * r; // 3/2 * size
|
|
|
+ return { x, y };
|
|
|
+ }
|
|
|
+
|
|
|
renderMap() {
|
|
|
this.canvas.innerHTML = '';
|
|
|
-
|
|
|
- for (let q = 0; q < mapWidth; q++) {
|
|
|
- for (let r = 0; r < mapHeight; r++) {
|
|
|
- this.renderHexagon(q, r);
|
|
|
+
|
|
|
+ // Dimensions d'un hexagone (boîte englobante)
|
|
|
+ const hexWidth = this.tileSize * Math.sqrt(3);
|
|
|
+ const hexHeight = this.tileSize * 2;
|
|
|
+
|
|
|
+ // Rayon de la carte hexagonale (en tuiles)
|
|
|
+ // On utilise le plus grand hexagone qui tient dans (mapWidth, mapHeight)
|
|
|
+ const radius = Math.floor((Math.min(mapWidth, mapHeight) - 1) / 2);
|
|
|
+ if (radius < 0) return;
|
|
|
+
|
|
|
+ // Première passe: calculer toutes les positions et les bornes pour dimensionner le canvas
|
|
|
+ const positions = [];
|
|
|
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
|
+
|
|
|
+ for (let q = -radius; q <= radius; q++) {
|
|
|
+ const rMin = Math.max(-radius, -q - radius);
|
|
|
+ const rMax = Math.min(radius, -q + radius);
|
|
|
+ for (let r = rMin; r <= rMax; r++) {
|
|
|
+ const { x, y } = this.axialToPixel(q, r);
|
|
|
+ positions.push({ q, r, x, y });
|
|
|
+ if (x < minX) minX = x;
|
|
|
+ if (y < minY) minY = y;
|
|
|
+ if (x > maxX) maxX = x;
|
|
|
+ if (y > maxY) maxY = y;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // Padding pour éviter des coupures visuelles
|
|
|
+ const padding = 20;
|
|
|
+
|
|
|
+ // Dimensionner le canvas d'après l'enveloppe + la taille d'un hex
|
|
|
+ const canvasWidth = (maxX - minX) + hexWidth + padding;
|
|
|
+ const canvasHeight = (maxY - minY) + hexHeight + padding;
|
|
|
+ this.canvas.style.width = canvasWidth + 'px';
|
|
|
+ this.canvas.style.height = canvasHeight + 'px';
|
|
|
+
|
|
|
+ // Seconde passe: rendre chaque hexagone avec un offset pour commencer à (padding/2, padding/2)
|
|
|
+ const offsetX = -minX + padding / 2;
|
|
|
+ const offsetY = -minY + padding / 2;
|
|
|
+ for (const pos of positions) {
|
|
|
+ this.renderHexagon(pos.q, pos.r, pos.x + offsetX, pos.y + offsetY, hexWidth, hexHeight);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- renderHexagon(q, r) {
|
|
|
+ renderHexagon(q, r, x, y, hexWidth, hexHeight) {
|
|
|
const hex = document.createElement('div');
|
|
|
hex.className = 'hexagon';
|
|
|
hex.dataset.q = q;
|
|
|
hex.dataset.r = r;
|
|
|
-
|
|
|
- // Positionner l'hexagone
|
|
|
- const x = q * this.tileSize * 1.5;
|
|
|
- const y = r * this.tileSize * Math.sqrt(3) + (q % 2) * this.tileSize * Math.sqrt(3) / 2;
|
|
|
-
|
|
|
+
|
|
|
+ // Positionnement et dimensions
|
|
|
hex.style.left = x + 'px';
|
|
|
hex.style.top = y + 'px';
|
|
|
- hex.style.width = this.tileSize + 'px';
|
|
|
- hex.style.height = this.tileSize + 'px';
|
|
|
+ hex.style.width = hexWidth + 'px';
|
|
|
+ hex.style.height = hexHeight + 'px';
|
|
|
|
|
|
// Style de base
|
|
|
hex.style.position = 'absolute';
|
|
|
- hex.style.border = '1px solid #ddd';
|
|
|
- hex.style.backgroundColor = '#fff';
|
|
|
hex.style.cursor = 'pointer';
|
|
|
hex.style.transition = 'background-color 0.2s';
|
|
|
|
|
|
- // Créer la forme hexagonale avec CSS
|
|
|
- hex.style.clipPath = 'polygon(50% 0%, 93.3% 25%, 93.3% 75%, 50% 100%, 6.7% 75%, 6.7% 25%)';
|
|
|
+ // Créer la forme hexagonale avec CSS (pointy-top)
|
|
|
+ hex.style.clipPath = 'polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%)';
|
|
|
|
|
|
// Gestionnaire de clic
|
|
|
hex.addEventListener('click', (e) => {
|
|
|
@@ -320,12 +351,14 @@ class MapEditor {
|
|
|
hex.addEventListener('mouseenter', () => {
|
|
|
if (!this.selectedTile || this.selectedTile.q !== q || this.selectedTile.r !== r) {
|
|
|
hex.style.backgroundColor = '#e3f2fd';
|
|
|
+ hex.style.transform = 'scale(1.02)';
|
|
|
}
|
|
|
});
|
|
|
|
|
|
hex.addEventListener('mouseleave', () => {
|
|
|
if (!this.selectedTile || this.selectedTile.q !== q || this.selectedTile.r !== r) {
|
|
|
- hex.style.backgroundColor = '#fff';
|
|
|
+ hex.style.backgroundColor = '#ffffff';
|
|
|
+ hex.style.transform = 'scale(1)';
|
|
|
}
|
|
|
});
|
|
|
|
|
|
@@ -337,8 +370,9 @@ class MapEditor {
|
|
|
if (this.selectedTile) {
|
|
|
const prevHex = this.canvas.querySelector(`[data-q="${this.selectedTile.q}"][data-r="${this.selectedTile.r}"]`);
|
|
|
if (prevHex) {
|
|
|
- prevHex.style.backgroundColor = '#fff';
|
|
|
- prevHex.style.borderColor = '#ddd';
|
|
|
+ prevHex.style.backgroundColor = '#ffffff';
|
|
|
+ prevHex.style.borderColor = '#666';
|
|
|
+ prevHex.style.transform = 'scale(1)';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -348,6 +382,7 @@ class MapEditor {
|
|
|
if (hex) {
|
|
|
hex.style.backgroundColor = '#2196f3';
|
|
|
hex.style.borderColor = '#1976d2';
|
|
|
+ hex.style.transform = 'scale(1.05)';
|
|
|
}
|
|
|
|
|
|
// Afficher les informations de la tuile
|