基于jQuery UI的战舰网格拖拽功能优化技术问询
战舰游戏拖拽网格功能解决方案
分步问题解决
1. 限制船只仅可放置在grid-square内,禁止指针区域放置
当前代码的containment: grid会将指针区域也纳入拖拽范围,需调整为仅允许在网格方块上放置,无效区域释放时自动回退。
修改拖拽与放置配置:
$(ships).draggable({ start: function(event, ui) { // 记录初始位置用于回退 $(this).data('originalPosition', $(this).position()); }, stop: function(event, ui) { // 未放置到有效区域则返回初始位置 if (!$(this).data('dropped')) { $(this).animate($(this).data('originalPosition'), 200); } $(this).removeData('dropped'); } }); // 仅给网格方块绑定放置事件 $(squares).droppable({ accept: '.ship', drop: function(event, ui) { ui.draggable.data('dropped', true); } });
2. 允许拖拽穿过空白区域但不能放置,拖拽开始不立即进入网格
移除containment: grid后,船只可自由拖拽穿过列表与网格间的空白区域,只有grid-square是有效放置目标,空白区域释放时会触发回退逻辑,自然满足需求。
3. 拖拽结束自动对齐到最近网格方块
通过计算网格方块的尺寸,将船只位置对齐到网格坐标,禁止放置在方块间隙:
// 获取网格方块的统一尺寸 let squareSize = $('.grid-square').outerWidth(); $(ships).draggable({ // ... 保留之前的start/stop基础逻辑 stop: function(event, ui) { let ship = $(this); if (!ship.data('dropped')) { ship.animate(ship.data('originalPosition'), 200); return; } // 计算相对于网格的坐标 let gridOffset = $('#setupgrid').offset(); let shipOffset = ship.offset(); let relativeX = shipOffset.left - gridOffset.left; let relativeY = shipOffset.top - gridOffset.top; // 对齐到最近的网格方块左上角 let alignedX = Math.round(relativeX / squareSize) * squareSize; let alignedY = Math.round(relativeY / squareSize) * squareSize; // 确保船只不超出网格边界 let gridWidth = $('#setupgrid').width(); let gridHeight = $('#setupgrid').height(); let shipWidth = ship.outerWidth(); let shipHeight = ship.outerHeight(); if (alignedX + shipWidth > gridWidth) alignedX = gridWidth - shipWidth; if (alignedY + shipHeight > gridHeight) alignedY = gridHeight - shipHeight; if (alignedX < 0) alignedX = 0; if (alignedY < 0) alignedY = 0; // 应用对齐后的位置 ship.offset({ left: gridOffset.left + alignedX, top: gridOffset.top + alignedY }); } });
完整修改后的JavaScript代码
$(function() { let ships = document.getElementsByClassName('ship'); let squares = document.getElementsByClassName('grid-square'); let squareSize = $('.grid-square').outerWidth(); $(ships).draggable({ start: function(event, ui) { $(this).data('originalPosition', $(this).position()); $(this).data('dropped', false); }, stop: function(event, ui) { let ship = $(this); if (!ship.data('dropped')) { ship.animate(ship.data('originalPosition'), 200); return; } let gridOffset = $('#setupgrid').offset(); let shipOffset = ship.offset(); let relativeX = shipOffset.left - gridOffset.left; let relativeY = shipOffset.top - gridOffset.top; let alignedX = Math.round(relativeX / squareSize) * squareSize; let alignedY = Math.round(relativeY / squareSize) * squareSize; let gridWidth = $('#setupgrid').width(); let gridHeight = $('#setupgrid').height(); let shipWidth = ship.outerWidth(); let shipHeight = ship.outerHeight(); if (alignedX + shipWidth > gridWidth) alignedX = gridWidth - shipWidth; if (alignedY + shipHeight > gridHeight) alignedY = gridHeight - shipHeight; if (alignedX < 0) alignedX = 0; if (alignedY < 0) alignedY = 0; ship.offset({ left: gridOffset.left + alignedX, top: gridOffset.top + alignedY }); } }); $(squares).droppable({ accept: '.ship', drop: function(event, ui) { ui.draggable.data('dropped', true); } }); });
额外优化方向
- 添加拖拽时半透明效果:在
draggable配置中加入opacity: 0.7 - 禁止船只重叠:放置前检查目标网格区域是否已被占用,若占用则触发回退
- 支持船只旋转:添加切换按钮,动态调整船只尺寸与对齐逻辑
内容的提问来源于stack exchange,提问作者Christophoros Anthoulakis
相关产品推荐
相关产品推荐

