为何发射的子弹无法朝点击方向直线移动?
问题根源与修复方案
核心问题
子弹不朝点击方向直线移动的原因主要有两个:
1. 箭头中心位置未实时更新
页面加载时仅计算了一次arrowCenter,但之后修改了container的位置,导致箭头实际位置已改变,但计算角度和子弹方向时仍沿用初始的中心坐标,直接造成方向偏移。
2. 子弹初始位置设置错误
创建子弹时,用div.offsetTop + -3设置位置,但刚创建的子弹在容器中的初始偏移量并非箭头中心位置,导致子弹从错误起点出发,进一步加剧方向偏差。
修复后的完整代码
function getCenter(element) { const {left, top, width, height} = element.getBoundingClientRect(); return {x: left + width / 2, y: top + height / 2} } const arrow = document.getElementById("arrow"); const container = document.getElementById("container"); // 确保容器为相对定位,让子弹的绝对定位基于容器 container.style.position = "relative"; window.addEventListener("mousemove", getAngleOfArrow) function getAngleOfArrow(e) { // 每次计算角度时实时获取箭头中心 const arrowCenter = getCenter(arrow); const rads = Math.atan2(e.clientY - arrowCenter.y, e.clientX - arrowCenter.x); const angle = rads * 180 / Math.PI; arrow.style.transform = `rotate(${angle}deg)`; } window.addEventListener("click", function(e){ const shot = createShot(); moveShot(shot, e); }) function getRad(e){ // 实时获取箭头中心计算弧度 const arrowCenter = getCenter(arrow); return Math.atan2(e.clientY - arrowCenter.y, e.clientX - arrowCenter.x); } function createShot(){ const div = document.createElement("div"); div.setAttribute("class", "bullet"); container.appendChild(div); // 基于箭头当前中心设置子弹初始位置(适配6x6尺寸的子弹) const arrowCenter = getCenter(arrow); const containerRect = container.getBoundingClientRect(); div.style.position = "absolute"; div.style.top = `${arrowCenter.y - containerRect.top - 3}px`; div.style.left = `${arrowCenter.x - containerRect.left - 3}px`; return div; } function moveShot(circle, e){ const rad = getRad(e); const xshot = 7 * Math.cos(rad); const yshot = 7 * Math.sin(rad); const myInterval = setInterval(function () { // 解析数值避免字符串拼接异常 circle.style.left = `${parseFloat(circle.style.left) + xshot}px`; circle.style.top = `${parseFloat(circle.style.top) + yshot}px`; if(!isInViewport(circle)){ clearInterval(myInterval); circle.remove(); // 移除脱离视口的子弹,避免内存泄漏 } }, 16); } function isInViewport(element) { const rect = element.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); }
关键修改说明
- 实时获取箭头中心:在角度计算和弧度计算函数内,每次都调用
getCenter(arrow),确保使用箭头当前位置计算方向。 - 修正子弹初始位置:基于箭头实时中心和容器的视口坐标,计算子弹在容器内的绝对定位坐标,保证从箭头中心出发。
- 优化位置更新逻辑:用
parseFloat解析当前位置的数值,避免字符串相加导致的计算错误。 - 内存泄漏修复:子弹脱离视口后主动移除元素,避免累积无效DOM节点。
内容的提问来源于stack exchange,提问作者mackinonon
相关产品推荐
相关产品推荐

