
本帖最后由 点点&木木 于 2019-4-12 12:20 编辑 故事 本教程将向您展示如何将手部动作(以及巧妙掌握的Photon)作为游戏控制器,通过本地WiFi在Android或iOS设备上运行Pac-Man应用程序。还记得第一颗死星上那些垃圾捣蛋鬼吗?一个潜在的目的是向您介绍混合应用程序开发,并为您提供一个基于WiFi和Photon创建自己的项目的起点。我们将微控制器与IMU叠在一起,用于在游戏中控制吃豆人。 + |" y/ X% G3 h _为了充分利用本教程,您需要一个粒子光子和智能手机(iOS / Android)。基本的Pac-Man应用程序(使用基于PC的浏览器上的箭头键控制)完全由HTML5由pacman-canvas 应用程序开发人员 Platzh1rsch 重写 。 ![]() 硬件组件 Sparkfun Photon IMU Shoeld × 1 面包板(通用) × 1 粒子光子 × 1 介绍 早期版本的Photon的更新包括一个120 MHz(STM32F205 )微处理器和一个6x RAM(以前是128 KB)。开发板还配备了DAC和CAN,这种开发板的功能相当不同。 / v- ], {( f4 N4 h w) D( a简而言之,Particle背后的团队开发了令人印象深刻的产品,其中开发环境主要基于云(粒子构建),尽管更有经验的用户可能选择选择加入“离线”粒子开发软件。 SparkFun 非常友好地提供了一个Photon和几个盾牌。我拿到的盾牌中有电池护罩和IMU护罩。自从我开始使用Evothings开发示例以来,我一直认为尝试将连接和外部控件添加到现有的,通常是独立的移动应用程序中会很有趣。用HTML5 / JavaScript编写,使用EvothingsStudio软件在Android和iOS上运行是很好的。 源代码 您可以在Evothings GitHub存储库中浏览本教程的源代码。或者您还可以pacman-canvas 在他的GitHub存储库中找到Platzh1rsch 的原始版本。 ; @* d: W. J# H5 U: }你需要什么 一个 粒子光子(星火核心应该工作,虽然我没有测试过) 一个 SparkFun光子IMU盾 可选 - 1个 SparkFun Photon电池护罩 iOS或Android智能手机 具有DHCP服务器的本地网络 标准的试验板 / q1 Y1 D2 \, w+ u! r5 I: Q+ x第1步 - 硬件 本教程中第一个也是最简单的步骤是硬件准备。然后,您就可以开始编码了。在硬件准备中,我更喜欢将堆叠放在面包板上,以最大限度地降低无意中切断任何外露引脚的风险。您可以在下面的图片中查看我的堆栈。 ![]() 第2步 - 嵌入式软件 制备 我们将直接深入研究代码。可以在Github存储库中找到下面描述的完整源代码。 - H6 c# S% {& |5 Z( h# i9 ^0 [目标是在Photon上构建一个小型服务器。当客户端连接到设备时,它将开始以包含加速度值的JSON格式向连接的客户端发送数据。我们还需要配置校验码,以便它使用I2C总线进行通信。在本教程中,我将假设Photon和智能手机连接到同一本地网络。然而,通过一些额外的网络技能,我们的示例可以扩展为可以在公共互联网上使用,如果有人对此感兴趣的话。 // This#include statement was automatically // added by theParticle IDE #include"SparkFunLSM9DS1/SparkFunLSM9DS1.h" // ConfigureSparkFun Photon IMU Shield #defineLSM9DS1_M 0x1E #defineLSM9DS1_AG 0x6B // Configureexample#define DELAY_BETWEEN_TRANSFERS 50 // (milliseconds) #defineSERVER_PORT 23 #defineRGB_BRIGHTNESS 128 #define RGB_R 0 #define RGB_G255 #define RGB_B 0TCPServer server =TCPServer(SERVER_PORT); TCPClientclient;LSM9DS1 imu; void setup() { Serial.begin(9600); // Start listening for clients server.begin(); // InitializeSparkFun Photon IMU Shield imu.settings.device.commInterface =IMU_MODE_I2C; imu.settings.device.mAddress = LSM9DS1_M; imu.settings.device.agAddress =LSM9DS1_AG; imu.begin(); } 在代码中我们包含了 SparkFunLSM9DS1 库,它允许我们与SparkFun IMU Shield进行通信,以及一些可用于调整应用程序以满足特定需求的#defines 。在这种情况下,我们假设它保持不变。下一步是定义 server 和 client 我们使用与在无线网络连接客户端通信。最后我们定义了 imu 哪个是我们与IMU屏蔽的接口。 0 I* D6 c$ m( H' v/ D在内部,setup() 我们启用串行通信,我们将使用它来打印接收的网络设置。然后我们通过执行该方法开始侦听TCP连接server.begin()。一些设置更新后启动IMU屏蔽。现在我们已经配置并启动了串行连接,TCP服务器和IMU屏蔽。 0 M$ U( a; }0 v4 W, D, ]+ O以下部分介绍了在开发板上连续执行的loop()功能。 7 Z9 y9 p1 y1 q7 d" p0 @2 r/ Vvoid loop() { if (client.connected()) { // Discard datanot read by client client.flush(); // Take control of the LED RGB.control(true); RGB.color(RGB_R, RGB_G, RGB_B); // Read IMUdata imu.readAccel(); // Create JSON-object char buffer [40]; size_t length = sprintf(buffer, "{\"ax\":%.3f, \"ay\": %.3f, \"az\": %.3f}\n", imu.calcAccel(imu.ax), imu.calcAccel(imu.ay), imu.calcAccel(imu.az)); // Flash LED RGB.brightness(RGB.brightness() ==RGB_BRIGHTNESS ? 0 : RGB_BRIGHTNESS); // TransferJSON-object server.write((uint8_t *)buffer, length); } { // Turn on LEDand release control of LED RGB.brightness(RGB_BRIGHTNESS); RGB.control(false); // Check ifclient connected client = server.available(); } // Send networkinformation if serial data // is received if(Serial.available()) { Serial.println(WiFi.localIP()); Serial.println(WiFi.subnetMask()); Serial.println(WiFi.SSID()); while(Serial.available()) { Serial.read(); } } delay(DELAY_BETWEEN_TRANSFERS); } e+ ~0 N8 v9 ]: J应用程序主if-else语句检查是否有连接到开发板的客户端。如果存在客户端,则应用程序开始通过执行该client.flush() 方法丢弃客户端尚未读取的数据 。然后,软件控制RGB LED,并定义一种颜色,用于在客户端连接到开发板时发出信号。该 imu.readAccel() 方法更新包含从屏蔽获取的最新加速度数据的内部数据结构。在调用方法之前调用此 imu.calcAccel()方法以获取最新的采样加速度。 0 w2 p9 P, V- u, f2 K& k下一步是定义一个缓冲区,我们使用包含最新加速数据的JSON对象填充该缓冲区。每次通过调用缓冲区传输到客户端之前 server.write() 方法是开发板上的RGB LED闪烁。 如果没有客户端连接到Photon,则应用程序确保LED已打开并且控件已释放。然后应用程序检查是否连接了客户端。 ( J" c, _! z( i8 z4 ^( Q) U如果应用程序从串行连接接收数据,它将从当前网络连接传输网络信息。这包括本地IP地址,子网,网关和网络的名称(SSID)。作为最后一个操作,实现将读取并丢弃从串行连接接收的所有数据。 ( u! q0 ~4 A' y9 n' [在我们完成第2步之前,我需要将软件编译并刷新到开发板上,并打开与电路板的串行连接,将任何数据发送到电路板并记下网络信息。注意板的IP,稍后我们将在移动应用程序中使用它。 第3步 - 移动应用程序 可以在Github存储库中找到下面描述的完整源代码。 L j# n9 C- U! p从GitHub 获取pacman-canvas 提交3c24c7a995b1e329c5849ac24421eedfc1d70474 。解压缩应用程序并打开文件index.htm ,并pacman-canvas.js在您选择的编辑器。这些是我们为了实现目标而必须编辑的唯一两个文件。让我们开始吧index.htm。 4 J! Y7 M1 s# M5 m7 Z- ?" x, m我们要做的第一件事是删除一些我们不需要的代码片段。从以下部分中删除代码: 谷歌分析 谷歌的AdSense 高分 我们删除该Highscore 部分的原因是它是使用PHP脚本语言实现的,这是一种不支持在移动客户端上下文中执行应用程序的技术。找到<div> 带有id的内容menu-button 并删除以下代码: <li class="button" id="highscore">Highscore</li> 下一步是在标记之前添加下面的代码片段</head>。 <script> // Redirectconsole.log to Evothings Workbench. if (window.hyper && window.hyper.log) { console.log = hyper.log } </script> <script src="cordova.js"></script> 此代码将每次console.log() 调用,定向到Evothings Workbench特殊函数hyper.log(),以便将应用程序调试回Workbench 的Tools 部分。 列表中的最后一项是在主菜单中添加两个按钮。我们将使用一个连接Photon,一个将我们带回到开始屏幕。找到<div>带有id的内容menu-control 并添加以下代码: <li class="button" id="photon-control">Connect Photon</li> <li class="button" id="evothings-back">Back</li> 此时没有什么可以编辑的index.htm 。按“保存”,然后继续编辑pacman-canvas.js文件。作为第一步,我们将创建一个代表Photon的对象。在文件的顶部,在声明全局变量之后添加以下代码片段,不要忘记添加Photon的IP: , G' O" l: D/ B0 d" d// Photonhandlerfunction Photon() { // IPAddressand port of the Photon var IPAddress = 'YOUR IPADDRESS HERE' var port = 23 var socketId var previousDirection = {} this.connect = function() { // Returnimmediately if there is // a connectionpresent if(socketId) { return } chrome.sockets.tcp.create(function(createInfo) { socketId = createInfo.socketId; chrome.sockets.tcp.connect(socketId, IPAddress,port,connectedCallback) }) } this.disconnect = function () { chrome.sockets.tcp.close(socketId, function() { socketId = 0; // Resetgraphics and callbacks associated // with thebutton in the main menu $('#' + previousDirection.name).css('background-color', '') $('#photon-control').text('Connect Photon') $(document).off('click','.button#photon-control').on('click','.button#photon-control', function(event) { photon.connect() }) }) } 该方法 connect() 尝试使用定义的IPAddress 和 连接到开发板 port 。此方法 chrome.sockets.tcp.create() ,可确保应用程序仅连接到一个开发板。 function connectedCallback(result) { if (result === 0) { // Updategraphics and callbacks associated // with thebutton in the main menu $('#photon-control').text('Disconnect'); $(document).off('click','.button#photon-control') .on('click','.button#photon-control', function(event) { photon.disconnect(); }); // Set callbackto handle received data chrome.sockets.tcp.onReceive.addListener(receiveData); } else { alert('Failed to connect to Photon!' + ' Try again!', function() {}) } } connectedCallback() 当存在连接尝试的结果时,回调是异步执行的。回调评估连接是否成功。如果存在已建立的连接(结果=== 0),则更新主菜单以处理断开连接并receiveData()配置对handle()的回调。如果由于某种原因连接失败,屏幕上会显示一个警告对话框并 socketId 重置为零,以启用新的连接尝试。 // Function tohandle received data. function receiveData(info) { // Convertbuffer to string containing // the sentJSON-object var jsonString = String.fromCharCode.apply(null, new Uint8Array(info.data)) // Try toconvert the string to an actual // JavaScriptobject try { var jsonObject = JSON.parse(jsonString) } catch(e) { return } var ax = jsonObject['ax'] var ay = jsonObject['ay'] var az = jsonObject['az'] // Adjustpacman direction depending on // receivedacceleration if(Math.abs(ax) > Math.abs(ay)) { if(ax < 0) { adjustPacmanDirection(down) } else { adjustPacmanDirection(up) } } else if (Math.abs(ay) > Math.abs(ax)) { if(ay < 0) { adjustPacmanDirection(left) } else { adjustPacmanDirection(right) } } } 每次收到新数据时都会执行该 receiveData()功能。第一步是将接收的数据转换为可从中提取数据的JavaScript对象。第二步是根据加速度的值调整pacman的方向。 // Move Pac-Manaround functionadjustPacmanDirection(direction) { pacman.directionWatcher.set(direction) $('#' + direction.name).css('background-color', '#008000') if(!direction.equals(previousDirection)) { $('#' + previousDirection.name).css('background-color', '') previousDirection = direction } } 该功能adjustPacmanDirection() 改变了游戏中pacman图形的方向,并更新了箭头以显示此刻图形朝向的方向。 2 L5 b# Z/ P) [photon 通过在变量声明下面的行上添加以下代码来声明在全局变量中命名的变量mapConfig 。 var photon 下一步是定义可变光子。这是通过在game 变量( )的定义下添加以下代码来完成的game = new Game()。 photon = new Photon() 下一步也是最后一步是将初始回调添加到我们index.html 在本教程前面添加的按钮中。声明这个的最佳位置是在$(document).ready() 方法中,因为在我们可以添加回调之前必须完全加载DOM。找到此方法并在定义其他按钮回调的位置添加以下代码。 $(document).on('click','.button#photon-control', function(event) { photon.connect()}); $(document).on('click', { history.back() }) }) 就是这样,您现在应该能够在Evothings Workbench中按Run并将Pac-Man设置为在您的Android或iPhone上运行。 结论 使用粒子光子很有趣。我肯定会将开发板作为未来项目的基础。$ T; V9 y) o9 b$ N% h: t |
强大 |