Aperçu de la boîte de collision dans l'éditeur + blocage physique au jeu
Deux retours utilisateur sur la boîte de collision (ajoutée précédemment) : - Visible et réglable directement dans l'éditeur de scène : pour l'objet sélectionné, un contour pointillé (rectangle/cercle) se superpose sur le canevas — glisser son corps ajuste le décalage, glisser sa poignée (coin bas-droit) ajuste la taille, les deux se répercutent dans le panneau "🧱 Collision" et inversement (édition des champs -> aperçu à jour). static/js/scenes/scene-editor.js::onCollisionBoxMouseDown/ onCollisionBoxResizeMouseDown, mirror des poignées de position/taille déjà existantes pour l'objet lui-même. - Bloque désormais RÉELLEMENT le déplacement au clavier : avant chaque pas, personnage-controller.js teste si la position candidate chevaucherait la boîte de collision d'un autre objet solide (jamais un "fond", jamais un objet à collision désactivée) et annule ce pas — par AXE séparément, pour permettre de glisser le long d'un mur en diagonale plutôt qu'un blocage total au moindre contact. Réutilise forgeShapesOverlap (conditions.js, factorisé depuis elementsOverlap pour ne jamais dupliquer la règle "qu'est-ce qui se touche"). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
bc3feb5080
commit
a231bcf2fa
@@ -163,23 +163,112 @@ function saveSceneObjectRole(role) {
|
||||
// static/js/play/conditions.js::elementsOverlap) : disponible pour TOUT
|
||||
// objet de scène (pas seulement "personnage") — même patron AJAX que les
|
||||
// fonctions ci-dessus, sur routes/scenes/scene_object_collision.py.
|
||||
// Recale aussi l'aperçu (#collisionBoxOverlay, seulement présent pour
|
||||
// l'objet sélectionné) pour rester en phase avec les champs, qu'ils
|
||||
// viennent d'être tapés à la main ou ajustés au glisser (voir
|
||||
// onCollisionBoxMouseDown/onCollisionBoxResizeMouseDown plus bas).
|
||||
function saveSceneObjectCollision() {
|
||||
var body = document.getElementById('collisionPanelBody');
|
||||
if (!body) return;
|
||||
var objectId = parseInt(body.dataset.elementId, 10);
|
||||
var enabled = document.getElementById('collision-enabled').checked;
|
||||
var shape = document.getElementById('collision-shape').value;
|
||||
var width = parseFloat(document.getElementById('collision-width').value) || 0;
|
||||
var height = parseFloat(document.getElementById('collision-height').value) || 0;
|
||||
var offsetX = parseFloat(document.getElementById('collision-offset-x').value) || 0;
|
||||
var offsetY = parseFloat(document.getElementById('collision-offset-y').value) || 0;
|
||||
|
||||
var overlay = document.getElementById('collisionBoxOverlay');
|
||||
var objEl = document.getElementById('el-' + objectId);
|
||||
if (overlay && objEl) {
|
||||
var objWidth = parseFloat(objEl.style.width) || 0, objHeight = parseFloat(objEl.style.height) || 0;
|
||||
overlay.style.width = width + 'px';
|
||||
overlay.style.height = height + 'px';
|
||||
overlay.style.left = ((objWidth - width) / 2 + offsetX) + 'px';
|
||||
overlay.style.top = ((objHeight - height) / 2 + offsetY) + 'px';
|
||||
overlay.classList.toggle('is-circle', shape === 'cercle');
|
||||
overlay.classList.toggle('is-disabled', !enabled);
|
||||
}
|
||||
|
||||
fetch('/game/' + GAME_SLUG + '/scene-objects/' + objectId + '/collision', {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
enabled: document.getElementById('collision-enabled').checked,
|
||||
shape: document.getElementById('collision-shape').value,
|
||||
width: document.getElementById('collision-width').value,
|
||||
height: document.getElementById('collision-height').value,
|
||||
offset_x: document.getElementById('collision-offset-x').value,
|
||||
offset_y: document.getElementById('collision-offset-y').value,
|
||||
}),
|
||||
body: JSON.stringify({ enabled: enabled, shape: shape, width: width, height: height, offset_x: offsetX, offset_y: offsetY }),
|
||||
});
|
||||
}
|
||||
|
||||
function updateCollisionFields(width, height, offsetX, offsetY) {
|
||||
var wEl = document.getElementById('collision-width'), hEl = document.getElementById('collision-height');
|
||||
var oxEl = document.getElementById('collision-offset-x'), oyEl = document.getElementById('collision-offset-y');
|
||||
if (wEl) wEl.value = Math.round(width);
|
||||
if (hEl) hEl.value = Math.round(height);
|
||||
if (oxEl) oxEl.value = Math.round(offsetX);
|
||||
if (oyEl) oyEl.value = Math.round(offsetY);
|
||||
}
|
||||
|
||||
// Glisser le CORPS de l'aperçu ajuste son décalage (offset_x/offset_y) —
|
||||
// mirror d'onSceneObjectMouseDown ci-dessus, mais sur la boîte de
|
||||
// collision plutôt que l'objet lui-même (jamais le même geste : cliquer
|
||||
// l'objet EN DEHORS de la boîte de collision continue de le déplacer
|
||||
// normalement, la boîte est un enfant plus petit posé par-dessus).
|
||||
function onCollisionBoxMouseDown(e, id) {
|
||||
e.stopPropagation();
|
||||
if (e.target.classList.contains('collisionResizeHandle')) return;
|
||||
e.preventDefault();
|
||||
var overlay = document.getElementById('collisionBoxOverlay');
|
||||
var objEl = document.getElementById('el-' + id);
|
||||
var objWidth = parseFloat(objEl.style.width) || 0, objHeight = parseFloat(objEl.style.height) || 0;
|
||||
var startX = e.clientX, startY = e.clientY;
|
||||
var startLeft = parseFloat(overlay.style.left) || 0, startTop = parseFloat(overlay.style.top) || 0;
|
||||
var boxWidth = parseFloat(overlay.style.width) || 0, boxHeight = parseFloat(overlay.style.height) || 0;
|
||||
|
||||
function onMove(ev) {
|
||||
overlay.style.left = (startLeft + (ev.clientX - startX)) + 'px';
|
||||
overlay.style.top = (startTop + (ev.clientY - startY)) + 'px';
|
||||
}
|
||||
function onUp() {
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onUp);
|
||||
var offsetX = (parseFloat(overlay.style.left) || 0) - (objWidth - boxWidth) / 2;
|
||||
var offsetY = (parseFloat(overlay.style.top) || 0) - (objHeight - boxHeight) / 2;
|
||||
updateCollisionFields(boxWidth, boxHeight, offsetX, offsetY);
|
||||
saveSceneObjectCollision();
|
||||
}
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('mouseup', onUp);
|
||||
}
|
||||
|
||||
// Glisser la poignée (coin bas-droit) redimensionne la boîte de collision
|
||||
// — mirror d'onSceneObjectResizeMouseDown, ancré sur son coin haut-gauche
|
||||
// (le centre se déplace donc légèrement à chaque redimensionnement, sauf
|
||||
// à recalculer l'offset pour le garder fixe : on choisit de garder le
|
||||
// COIN fixe, plus prévisible au glisser qu'un centre qui "fuit").
|
||||
function onCollisionBoxResizeMouseDown(e, id) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
var overlay = document.getElementById('collisionBoxOverlay');
|
||||
var objEl = document.getElementById('el-' + id);
|
||||
var objWidth = parseFloat(objEl.style.width) || 0, objHeight = parseFloat(objEl.style.height) || 0;
|
||||
var startX = e.clientX, startY = e.clientY;
|
||||
var startWidth = parseFloat(overlay.style.width) || 0, startHeight = parseFloat(overlay.style.height) || 0;
|
||||
var left = parseFloat(overlay.style.left) || 0, top = parseFloat(overlay.style.top) || 0;
|
||||
|
||||
function onMove(ev) {
|
||||
overlay.style.width = Math.max(4, startWidth + (ev.clientX - startX)) + 'px';
|
||||
overlay.style.height = Math.max(4, startHeight + (ev.clientY - startY)) + 'px';
|
||||
}
|
||||
function onUp() {
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onUp);
|
||||
var newWidth = parseFloat(overlay.style.width), newHeight = parseFloat(overlay.style.height);
|
||||
var offsetX = left - (objWidth - newWidth) / 2;
|
||||
var offsetY = top - (objHeight - newHeight) / 2;
|
||||
updateCollisionFields(newWidth, newHeight, offsetX, offsetY);
|
||||
saveSceneObjectCollision();
|
||||
}
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('mouseup', onUp);
|
||||
}
|
||||
|
||||
// "Commandes" (voir static/js/play/personnage-controller.js) : touches de
|
||||
// déplacement/interaction + blocage d'axe + touches supplémentaires d'un
|
||||
// personnage — un seul formulaire, enregistré en AJAX à chaque
|
||||
|
||||
Reference in New Issue
Block a user