
本文旨在解决JavaScript游戏中将键盘事件转换为触控事件时常见的错误。通过分析e.code属性在不同事件类型中的适用性,我们将深入探讨touchstart事件的正确处理方式,并提供示例代码和最佳实践,确保您的游戏在移动设备上提供无缝的交互体验。
理解事件类型与事件对象属性
在开发javascript游戏时,将原本基于键盘输入的交互逻辑适配到触控设备是一个常见需求。然而,许多开发者在尝试将keypress或keydown事件直接替换为touchstart时,会遇到意料之外的问题。这通常源于对不同事件类型所附带的事件对象(event object)属性的误解。
以Flappy Bird为例,当我们需要将小鸟的跳跃动作从按下空格键(Space)改为触摸屏幕时,直观地将document.addEventListener(“keypress”, handleJump)改为document.addEventListener(“touchstart”, handleJump),并将handleJump函数中的条件判断从e.code !== “Space”改为e.code !== “touchstart”,看似合理,实则不然。
问题的核心在于e.code属性。e.code是KeyboardEvent(键盘事件)对象特有的属性,用于表示触发事件的物理按键代码,例如”Space”、”KeyA”等。而touchstart事件属于TouchEvent(触控事件)类型,其事件对象不包含code属性。因此,当touchstart事件触发时,e.code将是undefined。将undefined !== “touchstart”作为条件判断,实际上是试图比较一个不存在的属性与一个字符串,这会导致条件始终为真(或在严格模式下抛出错误),从而阻止了后续逻辑的执行。
正确处理触控事件
对于touchstart这类触控事件,我们通常不需要检查特定的“代码”来判断事件的来源,因为事件本身就代表了用户在屏幕上的触摸行为。如果事件监听器已经明确绑定到touchstart事件,那么当handleJump函数被调用时,我们就可以确信这是一个触摸事件。
因此,解决问题的关键在于移除或修改不适用于触控事件的条件判断。
立即学习“Java免费学习笔记(深入)”;
原始(错误)的 handleJump 函数:
function handleJump(e) { if (e.code !== "touchstart") return; // 错误:e.code 不适用于 touchstart 事件 timeSinceLastJump = 0;}
修正后的 handleJump 函数:
function handleJump(e) { // 对于 touchstart 事件,无需检查 e.code // 如果需要防止默认的滚动/缩放行为,可以添加 e.preventDefault(); // e.preventDefault(); timeSinceLastJump = 0;}
通过移除if (e.code !== “touchstart”) return;这一行,handleJump函数在touchstart事件触发时将直接执行timeSinceLastJump = 0;,从而正确地触发小鸟的跳跃动作。
示例代码:Flappy Bird 触控适配
以下是基于原始代码进行修改的示例,展示了如何正确地将Flappy Bird游戏适配为触控友好型。
f.js (主页面逻辑):
import { updateBird, setupBird, getBirdRect } from "./Bird.js";import { updatePipes, setupPipes, getPassedPipesCount, getPipesRects,} from "./Pipe.js";// 监听 touchstart 事件来启动游戏document.addEventListener("touchstart", handleStart, { once: true });const title = document.querySelector("[data-title]");const subtitle = document.querySelector("[data-subtitle]");let lastTime;function updateLoop(time) { if (lastTime == null) { lastTime = time; window.requestAnimationFrame(updateLoop); return; } const delta = time - lastTime; updateBird(delta); updatePipes(delta); if (checkLose()) return handleLose(); lastTime = time; window.requestAnimationFrame(updateLoop);}function checkLose() { const birdRect = getBirdRect(); const insidePipe = getPipesRects().some((rect) => isCollision(birdRect, rect) ); const outsideWorld = birdRect.top window.innerHeight; return outsideWorld || insidePipe;}function isCollision(rect1, rect2) { return ( rect1.left < rect2.right && rect1.top rect2.left && rect1.bottom > rect2.top );}function handleStart() { title.classList.add("hide"); setupBird(); setupPipes(); lastTime = null; window.requestAnimationFrame(updateLoop);}function handleLose() { setTimeout(() => { title.classList.remove("hide"); subtitle.classList.remove("hide"); subtitle.textContent = `${getPassedPipesCount()} Pipes`; // 游戏结束后,再次监听 touchstart 来重新开始游戏 document.addEventListener("touchstart", handleStart, { once: true }); }, 100);}
Bird.js (小鸟逻辑):
const birdElem = document.querySelector("[data-bird");const BIRD_SPEED = 0.5;const JUMP_DURATION = 120;let timeSinceLastJump = Number.POSITIVE_INFINITY;export function setupBird() { setTop(window.innerHeight / 2); // 移除旧的事件监听器,确保只添加一次 document.removeEventListener("touchstart", handleJump); // 监听 touchstart 事件来触发跳跃 document.addEventListener("touchstart", handleJump);}export function updateBird(delta) { if (timeSinceLastJump < JUMP_DURATION) { setTop(getTop() - BIRD_SPEED * delta); } else { setTop(getTop() + BIRD_SPEED * delta); } timeSinceLastJump += delta;}export function getBirdRect() { return birdElem.getBoundingClientRect();}function setTop(top) { birdElem.style.setProperty("--bird-top", top);}function getTop() { return parseFloat(getComputedStyle(birdElem).getPropertyValue("--bird-top"));}function handleJump(e) { // 修正:移除对 e.code 的错误判断 // 建议:对于游戏中的触控事件,通常需要阻止默认行为以防止页面滚动或缩放 e.preventDefault(); timeSinceLastJump = 0;}
注意事项与最佳实践
e.preventDefault(): 在处理触控事件时,尤其是在游戏中,强烈建议调用e.preventDefault()。这可以阻止浏览器执行与触摸相关的默认行为,例如页面滚动、缩放或触发上下文菜单。如果您的游戏不阻止这些默认行为,用户可能会在尝试玩游戏时意外地滚动页面。事件监听器的管理: 在setupBird函数中,先removeEventListener再addEventListener是一个好习惯,可以防止重复添加相同的事件监听器,尤其是在游戏重置或重新开始时。click事件与touchstart/touchend:touchstart:当用户触摸屏幕时立即触发。适合需要即时响应的动作(如跳跃、射击)。touchend:当用户从屏幕上抬起手指时触发。适合需要释放动作的场景。click:在touchstart和touchend之后,如果触摸没有移动且持续时间短,浏览器会模拟触发click事件。对于简单的“点击”交互,click事件可能更方便,因为它已经处理了触摸和鼠标事件的兼容性。但对于需要精确控制触摸生命周期的游戏,touchstart和touchend更合适。多点触控: 如果您的游戏需要支持多点触控(例如,同时控制多个角色或执行组合操作),您需要利用TouchEvent对象的e.touches、e.targetTouches和e.changedTouches属性来获取当前所有触摸点的信息。性能优化: 频繁触发的触控事件(如touchmove)可能会影响性能。如果不需要实时追踪触摸点的移动,尽量避免在这些事件上执行复杂的计算。
总结
将JavaScript游戏从键盘控制转换为触控控制时,理解不同事件类型(如KeyboardEvent和TouchEvent)的事件对象属性至关重要。e.code是键盘事件特有的属性,不适用于触控事件。对于touchstart事件,我们只需监听事件并执行相应的逻辑,同时考虑使用e.preventDefault()来优化用户体验。通过遵循这些原则和最佳实践,您可以确保您的JavaScript游戏在移动设备上提供流畅、响应迅速的触控交互。
以上就是掌握JavaScript游戏触控事件:从键盘到触摸的平滑过渡的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1575201.html
微信扫一扫
支付宝扫一扫