1回答

1收藏

[原创] 【CurieNano项目2】重力感应平衡球游戏

DFROBOT DFROBOT 5901 人阅读 | 1 人回复 | 2017-05-15

概述:
        平衡球游戏在手机平台上很常见,玩家操控手机的平衡来控制平衡球运动,到达指定地点。为了实现平衡球游戏,我使用Arduino 101作为游戏手柄,将101的加速度计数据通过串口或BLE发给PC机,在PC机上实现一个平衡球游戏的界面。(因为没学过美工,也没有时间去认真做这个游戏,现在界面很简陋,仅仅作为一个抛砖引玉).



目的:
        使用Arduino 101作为手柄,用PC机作为界面,通过串口和BLE两种方式完成101与PC机的交互,实现平衡球游戏。



硬件/软件需求:
       硬件需求:CurieNano/Arduino 101、电脑
       软件需求(对于串口版本):Arduino 101 1.x+库、 Python、pygame
       软件需求(对于蓝牙版本):Arduino 101 1.x+库、Visual Studio2015+



使用串口传输的版本:
        这个版本没有使用BLE,需要把101和电脑通过USB连接。我写了一个Python2.7的脚本,调用串口库获取101发来的串口数据,调用pygame显示界面。
        需要:Python2.7 、pygame 、Arduino 101 、Arduino 101 1.0.x+库

Arduino 101代码:
  1. #include "CurieIMU.h"
  2. int ax, ay, az;         // accelerometer values
  3. int gx, gy, gz;         // gyrometer values

  4. const int ledPin = 13;      // activity LED pin
  5. boolean blinkState = false; // state of the LED

  6. int calibrateOffsets = 1; // int to determine whether calibration takes place or not

  7. void setup() {
  8.   Serial.begin(9600);
  9.   while (!Serial);
  10.   CurieIMU.begin();

  11.   if (calibrateOffsets == 1) {
  12.     delay(1000);
  13.     CurieIMU.autoCalibrateGyroOffset();
  14.     CurieIMU.autoCalibrateAccelerometerOffset(X_AXIS, 0);
  15.     CurieIMU.autoCalibrateAccelerometerOffset(Y_AXIS, 0);
  16.     CurieIMU.autoCalibrateAccelerometerOffset(Z_AXIS, 1);
  17.   }
  18.   pinMode(ledPin, OUTPUT);
  19. }

  20. int8_t buf[4];

  21. void loop() {
  22.   while(Serial.read()!='g');
  23.   CurieIMU.readMotionSensor(ax, ay, az, gx, gy, gz);
  24.   *((int16_t*)buf) = ax;
  25.   *((int16_t*)(buf+2)) = ay;
  26.   Serial.write(buf[0]);
  27.   Serial.write(buf[1]);
  28.   Serial.write(buf[2]);
  29.   Serial.write(buf[3]);

  30.   blinkState = !blinkState;
  31.   digitalWrite(ledPin, blinkState);
  32. }
复制代码
Python2.7代码:
  1. #coding: utf-8
  2. #Version:   Python2.7

  3. from time import sleep
  4. from serial.tools import list_ports
  5. from serial import Serial
  6. from struct import unpack
  7. import pygame,sys

  8. class MySerial():
  9.     def __init__(self):
  10.         port_list = list(list_ports.comports())
  11.         if len(port_list) <= 0:
  12.             self._ser = None
  13.             return
  14.         self._ser = Serial(list(port_list[0])[0],9600)
  15.         sleep(1)
  16.     def opened(self):
  17.         return self._ser!=None
  18.     def GetAngle(self):
  19.         self._ser.write('g')
  20.         s = self._ser.read(size=4)
  21.         return unpack('hh',s)
  22.          
  23.          
  24. class Ball():
  25.     def __init__(self):
  26.         self.reset()
  27.         self.radius = 20.0
  28.     def reset(self):
  29.         self.x = 100.0
  30.         self.y = 100.0
  31.         self.vx = 0.0
  32.         self.vy = 0.0
  33.     def move(self,a):
  34.         self.vx += a[0]/131072.0
  35.         self.vy += a[1]/131072.0
  36.         self.x -= self.vx
  37.         self.y += self.vy
  38.          
  39.         if self.x<self.radius:
  40.             self.vx = 0.0
  41.             self.x = self.radius
  42.          
  43.         if self.x>600.0-self.radius:
  44.             self.vx = 0.0
  45.             self.x = 600.0-self.radius
  46.          
  47.         if self.y<self.radius:
  48.             self.vy = 0.0
  49.             self.y = self.radius
  50.             
  51.         if self.y>600.0-self.radius:
  52.             self.vy = 0.0
  53.             self.y = 600.0-self.radius
  54.          
  55.         if self.y>200.0-2*self.radius and self.y<200.0 and self.x<400.0:
  56.             self.vy = 0.0
  57.             self.y = 200.0-2*self.radius
  58.          
  59.         if self.y<200.0+2*self.radius and self.y>200.0 and self.x<400.0:
  60.             self.vy = 0.0
  61.             self.y = 200.0+2*self.radius
  62.             
  63.         if self.y>400.0-2*self.radius and self.y<400.0 and self.x>200.0:
  64.             self.vy = 0.0
  65.             self.y = 400.0-2*self.radius
  66.          
  67.         if self.y<400.0+2*self.radius and self.y>400.0 and self.x>200.0:
  68.             self.vy = 0.0
  69.             self.y = 400.0+2*self.radius
  70.          
  71.         if (465-self.x)**2+(465-self.y)**2 < (1.4*self.radius)**2:
  72.                     return 1
  73.          
  74.         for i in xrange(0,4):
  75.             for j in xrange(0,4):
  76.                 hole_x = 150*i + 15
  77.                 hole_y = 150*j + 15
  78.                 if (hole_x-self.x)**2+(hole_y-self.y)**2 < (1.4*self.radius)**2:
  79.                     return -1
  80.         return 0
  81.      
  82. def main():
  83.     ser = MySerial()
  84.     if not ser.opened():
  85.         print "No Serial"
  86.         return
  87.     else:
  88.         print "Serial OK"
  89.     ball = Ball()
  90.     pygame.init()
  91.     screencaption = pygame.display.set_caption('Balance Ball')
  92.     screen = pygame.display.set_mode([600,600])
  93.     screen.fill([255,255,255])
  94.     pygame.display.update()

  95.     while True:
  96.         for event in pygame.event.get():
  97.             if event.type==pygame.QUIT:
  98.                 return
  99.         screen.fill([255,255,192])
  100.         pygame.draw.rect(screen,[0,0,0],[0,200-int(ball.radius),400,int(ball.radius)*2],3)
  101.         pygame.draw.rect(screen,[0,0,0],[200,400-int(ball.radius),600,int(ball.radius)*2],3)
  102.         for i in xrange(0,4):
  103.             for j in xrange(0,4):
  104.                 hole_x = 150*i + 15
  105.                 hole_y = 150*j + 15
  106.                 pygame.draw.circle(screen,[0,0,0],[hole_x,hole_y],int(ball.radius),int(ball.radius))
  107.                  
  108.         pygame.draw.circle(screen,[0,0,255],[465,465],int(ball.radius),int(ball.radius))
  109.         pygame.draw.circle(screen,[255,30,60],[int(ball.x),int(ball.y)],int(ball.radius),int(ball.radius))
  110.         pygame.display.update()
  111.          
  112.         result = ball.move(ser.GetAngle())
  113.          
  114.         if result == -1 :
  115.             print "You Lose!"
  116.             ball.reset()
  117.         elif result == 1:
  118.             print "You Win!"
  119.             ball.reset()

  120. if __name__ == '__main__':
  121.     main()
复制代码
运行方式:
上传程序后,确保Arduino 101已连接电脑,且不要使用其它COM口。再运行Python脚本,这个脚本是自动寻找Arduino101的串口的,若找到串口,会在屏幕上显示"Serial Ready",然后弹出游戏界面,就可以玩了:

图:有线连接的平衡球游戏









使用BLE传输的版本:

        这个版本使用了BLE,不需要把101和电脑通过USB连接,只需要给101供电就行(比如充电宝)。在PC端我是修改的一个UWP应用,还没有编写墙壁、洞口等场景,仅有空的地图。
需要:Windows10 、Visual Studio 2015+ 、Arduino 101 、Arduino 101 1.0.x+库

代码:
        算上UWP工程后,文件极大,因此可前往git库下载:

https://git.ustclug.org/WangXuan.c/101-UWP-balanceball
并按照ReadMe.txt操作。

运行方法:
       上传Arduino101代码后,给101上电(不必用电脑供电),在Win10的蓝牙设置里配对Arduino 101。编译运行UWP程序,可以看到以下界面。依次点击“101 Detected! Press to Start”和“{00002A37-0000-1000-8000-00805F9B34FB}” 。晃动101,就能看到黄色的圆球随之运动了。

图:BLE版本的平衡球



关注下面的标签,发现更多相似文章
分享到:
回复

使用道具 举报

回答|共 1 个

倒序浏览

沙发

feixiang20

发表于 2017-12-22 10:07:24 | 只看该作者

我也喜欢设计游戏
您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条