【前端】(仅思路)如何在前端实现一个fc手柄,将手机作为游戏手柄设备。

文章目录

    • 背景
    • 界面demo
      • 原型图(没错,就是它,童年回忆)
    • 遇到的问题
    • 最终
    • 后端demo(甚至比前端逻辑更简单)

背景

突发奇想,想要在前端实现一个fc游戏手柄,然后控制电脑的nes模拟器玩玩魂斗罗。
思路很简单,前后端使用websocket通信,connected标识socket链接已建立, 为了操作的低延时采用ws通信。

  • 前端: 实现10个按钮:上下左右,选择,开始,AB短按,AB长按。
  • 后端:监听按钮事件,然后调用win32api模拟键盘输入。
  • nes模拟器配置键盘映射。比如上=>w, 下 =>s。
    在这里插入图片描述

界面demo

在这里插入图片描述

原型图(没错,就是它,童年回忆)

在这里插入图片描述

单个按钮事件非常简单,监听touchstart 和touchend就行

        // 获取按钮元素
const leftButton = document.getElementById('left');
const topButton = document.getElementById('top');
const downButton = document.getElementById('down');
const rightButton = document.getElementById('right');// 添加触摸按下事件监听器
leftButton.addEventListener('touchstart', function() {console.log('Left button touched!');// 在这里添加按下时的逻辑socket.send("a:down"); //
});topButton.addEventListener('touchstart', function() {console.log('Top button touched!');// 在这里添加按下时的逻辑socket.send("w:down"); //
});downButton.addEventListener('touchstart', function() {console.log('Down button touched!');// 在这里添加按下时的逻辑socket.send("s:down"); //
});rightButton.addEventListener('touchstart', function() {console.log('Right button touched!');// 在这里添加按下时的逻辑socket.send("d:down"); //
});// 添加触摸抬起事件监听器
leftButton.addEventListener('touchend', function() {console.log('Left button released!');// 在这里添加抬起时的逻辑socket.send("a:up"); //
});topButton.addEventListener('touchend', function() {console.log('Top button released!');// 在这里添加抬起时的逻辑socket.send("w:up"); //
});downButton.addEventListener('touchend', function() {console.log('Down button released!');// 在这里添加抬起时的逻辑socket.send("s:up"); //
});rightButton.addEventListener('touchend', function() {console.log('Right button released!');// 在这里添加抬起时的逻辑socket.send("d:up"); //
});

但是组合键位就有问题了, html5触发 右+下 操作时,需要用两个手指点击 right 和 down才行。
PS:玩个魂斗罗还得3指操作, 这不2b的很么。
理想操作是:大拇指按下right 和down的按钮区域,就能触发右+下,尝试让gpt帮我们解决。

遇到的问题

  1. 组合键的问题:right+down, 实体手柄可以实现向右下角瞄准。但是h5中,大拇指按下right和down两个按钮区域时,只会触发一个touch事件。(这玩意儿情况一般人还真不会碰到)

实现大拇指同时按下right和down按钮区域,触发右+下的 解决办法

    // 处理触摸事件, 给方向键4个按钮 touchstart绑定此函数function handleTouch(event) {event.preventDefault(); // 阻止默认行为,如页面滚动const touches = event.touches;// 获取所有触摸点的位置信息const touchPositions = Array.from(touches).map(touch => {return {x: touch.clientX,y: touch.clientY};});// 检查是否同时触摸了 right 和 downsdsdd 按钮const touchingRight = touchPositions.some(pos => {return isTouchingElement(pos, rightButton);});const touchingDown = touchPositions.some(pos => {return isTouchingElement(pos, downButton);});// dssdsdsddsdsdsdsdddsdssdsdsdsdsddddssssssssddssssssdssdssdif (touchingRight && touchingDown) {// 在这里执行同时按下 right 和 down 按钮时的逻辑socket.send("s+d:down")}else if (touchingRight) {socket.send("d:down")}else if(touchingDown) {socket.send('s:down')}}// 辅助函数:检查触摸点是否在指定元素上function isTouchingElement(touchPosition, element) {const rect = element.getBoundingClientRect();return (touchPosition.x >= rect.left &&touchPosition.x <= rect.right &&touchPosition.y >= rect.top &&touchPosition.y <= rect.bottom);}

最终

可以愉快的拿手机当手柄了, 甚至可以两个页面双人对战。再进一步甚至能远程双人联机。

后端demo(甚至比前端逻辑更简单)

package mainimport ("fmt""log""net/http""text/template""github.com/go-vgo/robotgo""github.com/gorilla/websocket"
)var upgrader = websocket.Upgrader{ReadBufferSize:  1024,WriteBufferSize: 1024,
}func main() {fmt.Println("Starting server on port 18080...")http.HandleFunc("/", handler)http.HandleFunc("/ws", wsHandler)log.Fatal(http.ListenAndServe(":18080", nil))
}// 页面返回
func handler(w http.ResponseWriter, r *http.Request) {tmpl, err := template.ParseFiles("index.html")if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}err = tmpl.Execute(w, nil)if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)}
}
// wsHandler写的太2b了, 就不放出来了,让gpt给写写吧
func wsHandler(w http.ResponseWriter, r *http.Request) {}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/392522.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【编程笔记】解决移动硬盘无法访问文件或目录损坏且无法读取

解决移动硬盘无法访问文件或目录损坏且无法读取 只解决&#xff1a;移动硬盘无法访问文件或目录损坏且无法读取 问题 由于频繁下载数据&#xff0c;多次安装虚拟机导致磁盘无法被系统识别。磁盘本身是好的&#xff0c;只是不能被识别&#xff0c;如果将磁盘格式化&#xff0c…

Chainlit快速实现AI对话应用1 分钟内实现聊天数据的持久化保存

概述 默认情况下&#xff0c;Chainlit 应用不会保留其生成的聊天和元素。即网页一刷新&#xff0c;所有的聊天记录&#xff0c;页面上的所有聊天记录都会消失。但是&#xff0c;存储和利用这些数据的能力可能是您的项目或组织的重要组成部分。 一旦启用&#xff0c;数据持久性…

Unlikely argument type for equals(): int seems to be unrelated to Long

代码审查不规范&#xff1a; Unlikely argument type for equals(): int seems to be unrelated to Long check package code_check;public class Obj {public Obj(){}private Long mail;public Long getMail(){return mail;}public void setMail(Long mail){this.mail mail;…

【零基础实战】基于物联网的人工淡水湖养殖系统设计

文章目录 一、前言1.1 项目介绍1.1.1 开发背景1.1.2 项目实现的功能1.1.3 项目硬件模块组成1.1.4 ESP8266工作模式配置 1.2 系统设计方案1.2.1 关键技术与创新点1.2.2 功能需求分析1.2.3 现有技术与市场分析1.2.4 硬件架构设计1.2.5 软件架构设计1.2.6 上位机开发思路 1.3 系统…

Java | Leetcode Java题解之第324题摆动排序II

题目&#xff1a; 题解&#xff1a; class Solution {Random random new Random();public void wiggleSort(int[] nums) {int n nums.length;int x (n 1) / 2;int mid x - 1;int target findKthLargest(nums, n - mid);for (int k 0, i 0, j n - 1; k < j; k) {if…

DAMA学习笔记(十)-数据仓库与商务智能

1.引言 数据仓库&#xff08;Data Warehouse&#xff0c;DW&#xff09;的概念始于20世纪80年代。该技术赋能组织将不同来源的数据整合到公共的数据模型中去&#xff0c;整合后的数据能为业务运营提供洞察&#xff0c;为企业决策支持和创造组织价值开辟新的可能性。与商务智能&…

使用Go语言绘制柱状图教程

使用Go语言绘制柱状图教程 本文将介绍如何使用Go语言及gg包绘制柱状图&#xff0c;并将图表保存为PNG格式的图片。gg包是一个功能强大的2D图形库&#xff0c;适合用于绘制各种图表。 安装gg包 首先&#xff0c;确保你已经安装了gg包。如果还没有安装&#xff0c;可以使用以下…

【安当产品应用案例100集】005-安当ASP实现Exchange双因素登录认证

Exchange双因素登录通过增加额外的安全验证层&#xff0c;可以有效提高企业邮箱系统的安全性&#xff0c;减少了数据泄露和账号被盗的风险&#xff0c;同时也符合了日益严格的安全合规要求。 其必要性主要体现在以下几个方面&#xff1a; 提高安全性&#xff1a;传统的用户名…

1.MySQL面试题之innodb如何解决幻读

1. 写在前面 在数据库系统中&#xff0c;幻读&#xff08;Phantom Read&#xff09;是指在一个事务中&#xff0c;两次读取同一范围的数据集时&#xff0c;由于其他事务的插入操作&#xff0c;导致第二次读取结果集发生变化的问题。InnoDB 作为 MySQL 的一个存储引擎&#xff…

【期货】收盘点评。昨天说的,p2409棕榈油在今天或者周一会走出行情

收盘点评 昨天说的&#xff0c;p2409棕榈油在今天或者周一会走出行情。事实就是如此。震荡了几天了&#xff0c;波幅不大的来回震荡&#xff0c;其实主力是不想震荡的&#xff0c;但是不震荡自己的货和行情走不出来。所以我昨天就说&#xff0c;应该就是这一两天会走出一波小行…

Linux中的无人值守安装脚本Kickstart

目录 一.kickstart自动安装脚本的作用 在企业中安装多台操作系统时面临的问题 如何解决以上问题&#xff1f; 二.实验环境 三.kickstart自动安装脚本的制作 通过模板生成kickstart文件 1.安装图形化生成kickstart自动安装脚本的工具 2.图形化工具配置流程 3.配置文件详…

力扣热题100_二叉树_94_二叉树的中序遍历

文章目录 题目链接解题思路解题代码 题目链接 94. 二叉树的中序遍历 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2] 示例 2&#xff1a; 输入&#xff1a;root [] 输…

C#中重写tospring方法

在C#中&#xff0c;重写ToString方法允许你自定义对象的字符串表示形式。当你想要打印对象或者在调试时查看对象的状态时&#xff0c;重写ToString方法非常有用。 默认情况下&#xff0c;ToString方法返回对象的类型名称。通过重写这个方法&#xff0c;你可以返回一个更有意义…

sqli 1- 10

sql靶场 第一关 首先我们需要判断是否存在sql注入点&#xff0c;前端界面提示我使用ID作为参数,在url地址栏输入?id1 通过输入不同的id值查询数据库相对应的内容&#xff0c;之后判断为数字型还是字符型 根据查询内容判断为字符型且有注入点&#xff0c;再通过联合查询&…

#71结构体案例2(三国游戏,冒泡排序)

效果&#xff1a; 代码&#xff1a; #include <iostream> #include <string> using namespace std;//英雄结构体 struct Hero {string name;int age;string gender; };//冒泡排序 void bubbleSort(struct Hero hArray[],int len) {for(int i0;i<len-1;i){for(i…

首届中文NL2SQL挑战赛亚军比赛攻略_BugCreater

关联比赛: 首届中文NL2SQL挑战赛 1. 任务描述 本次比赛的任务&#xff1a;根据Question、表格信息&#xff08;包含列名、列类型、内容&#xff09;&#xff0c;预测对应的SQL语句&#xff08;下图黄色部分&#xff09;。比赛只涉及单表查询&#xff0c;需要预测的有4部分&a…

什么是DDoS攻击?怎么防御DDoS攻击?

在网络安全领域&#xff0c;DDoS 攻击一直是热门话题&#xff0c;随着网络技术的不断发展和网络环境的复杂化演变&#xff0c;DDoS 攻击变得愈加频繁、更具破坏性。根据 2023 年网络安全态势研判分析年度综合报告&#xff0c;全年全网网络层的 DDoS 攻击次数达 2.51 亿次&#…

【Kubernetes】k8s集群的pod基础

目录 一.Pod概述 1.什么是pod 2.k8s中pod的两种使用方式 3.pod容器的常规使用流程 4.创建pod的3种方式 二.Pod中容器概述 1.容器分类 2.Pod容器的3种镜像拉取策略 3.Pod容器的3种重启策略 4.pod的dns策略 一.Pod概述 1.什么是pod Pod是kubernetes中最小的资源管理组…

MySQL深分页和浅分页

前言 最近有面试过也遇到了问关于深分页问题&#xff0c;在这里简单从MySQL、ES等方面分享一下自己对该问题认识和总结。 一、深分页定义 可以从ES定义上来划分浅分页和深分页的边界&#xff0c;即页数超过10000页为深分页&#xff0c;少于10000页为浅分页。 二、MySQL深分…

初学Ubuntu及遇到的问题

初学Ubuntu及遇到的问题 Ubuntu的安装 1.安装VMware Workstation Pro&#xff08;网上有很多资料&#xff0c;本文就不细说啦~~~&#xff09; 2.在Ubuntu官网下载iso文件>https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/20.04/ iso文件随便放在哪个位置&#xff…