查看: 4661|回复: 1

【CurieNano项目2】重力感应平衡球游戏

[复制链接]
  • TA的每日心情
    开心
    2017-5-15 14:59
  • 签到天数: 8 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    发表于 2017-5-15 16:02: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版本的平衡球



    回复

    使用道具 举报

  • TA的每日心情
    难过
    2021-2-27 22:16
  • 签到天数: 1568 天

    连续签到: 1 天

    [LV.Master]伴坛终老

    发表于 2017-12-22 10:07:24 | 显示全部楼层
    我也喜欢设计游戏
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

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



    手机版|小黑屋|与非网

    GMT+8, 2024-4-16 18:51 , Processed in 0.137123 second(s), 19 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.