Augmented Reality and Virtual Gaming are a recent trend in the gaming industry. The times of using a keyboard/Joystick, and a mouse to play a computer game has gone behind. Now every gaming console comes with a Virtual Controller that helps us to play the game using our body movements and gestures, this way the gaming experience has increased a lot and user feels more involved into the game.
In this first version project let's try to have fun for people with disabilities. Let us create a game for PC or laptop, and play it using your hand’s movement with a portable and light device. We are creating the classic Space Invaders Game using Blues Swan board, and an Accelerometer.
How does it works?
- The accelerometer captures the acceleration variables "X" and "Y".
- The acceleration and firing values are processed by the Blues Swan board and sent to the serial port of the PC.
- This data is used by the Processing program (Java code) once it is running.
- The acceleration values on the X axis will be used to move the spacecraft on the horizontal axis. Rotating the user's hand to the left moves the spaceship to the left of the screen, and rotating the hand to the right moves the spaceship to the right.
- The acceleration values on the Y axis will be used to move the spacecraft on the vertical axis. Rotating the user's hand forward moves the spaceship up the screen, and rotating the user's hand backward moves the spaceship down.
- I have added a variable for the spaceship shots, which will be carried out automatically once the game has started.
- If the user's spaceship hits an enemy spaceship it is automatically destroyed.
- If the user's spaceship crashes, then a "game over" message appears in red letters on the screen.
Below I show you the electrical diagram of the project.
Blues Swan
- Feather-compatible dev board, powered by an STM32L4+ @ 120 MHz with 2MB of Flash and 640KB of RAM
- Expandable to 55 pins for access to additional I/O and buses
- Plenty of Flash and RAM for edge ML workloads or complex applications
- Support for C/C++, Arduino, and CircuitPython
- CORTEX Debug connector, enabling the use of Visual Studio Code, IAR, and STM32CubeIDE with optional SWD programmer
Grove - MMA7660 - axisdigital accelerometer I2C
- Grove interface
- 3-axis motion detection / position detection
- Digital I2C output
- Input voltage from 3 V to 5 V
- Current consumption in OFF mode: 0.4 μA
- Current consumption at standstill: 2 μA
- Current consumption during operation: 47 μA
- Acceleration range: ± 1.5 g
- Sensitivity: 21 count/g
An Accelerometer is a device which can convert acceleration in any direction to its respective variable voltage. This is accomplished by using capacitors, as the accelerometere moves, the capacitor present inside it, will also undergo changes based on the movement, since the capacitance is varied, a variable voltage can also be obtained. Por tanto, todo acelerómetro sufre el problema del efecto de la gravedad. No importa qué tan preciso esté calibrado su sensor, se verá afectado por la gravedad.
I have printed three 3D pieces with the next dimensions (from left to right): first piece with 95x35x10mm, second piece with 36x32x10 mm, and third piece with 45x20x10 mm. All of them are 1 mm thick.
The second piece is inserted inside the first piece as shown in the image below. The pieces can be joined with screws or silicone.
The third piece is inserted inside the second piece as shown in the image below. This third piece will be used to assemble the Blues Swan board.
In the image below I show you how the device will hypothetically be used when manipulated by hand. The middle finger is inserted into the lower space.
Finally, in the image below I show you the Blues board mounted in the middle space, and the accelerometer on the top of the device. I have fixed the wiring using silicone.
Blues has enough documentation to start programming the Blues Swan board. Here is a link for beginners: https://dev.blues.io/quickstart/notecard-quickstart/notecard-and-notecarrier-f/
After I installed PlatformIO in Visual Studio, I created the Accelerometer_imu project.
I have installed the library for the Grove - MMA7660 3-axis digital accelerometer I2C. Next, the configuration of the platformio.ini file is as shown below:
[env:bw_swan_r5]
platform = ststm32
board = bw_swan_r5
upload_protocol = dfu
framework = arduino
build_flags = -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
monitor_speed = 115200
lib_deps =
Wire
blues/Blues Wireless Notecard@^1.4.5
blues/Blues Wireless Notecard Pseudo Sensor@^1.1.0
seeed-studio/Accelerometer_MMA7660@^1.0.0
Now, below I show you the code from the main.cpp
file.
// AUTHOR: GUILLERMO PEREZ GUILLEN
#include <Arduino.h>
#include <Notecard.h>
#include <NotecardPseudoSensor.h>
#include <Wire.h>
#include "MMA7660.h"
MMA7660 accelemeter;
void setup()
{
accelemeter.init();
Serial.begin(9600);
}
void loop()
{
int8_t x;
int8_t y;
int8_t z;
float ax,ay,az;
accelemeter.getXYZ(&x,&y,&z);
accelemeter.getAcceleration(&ax,&ay,&az);
int btnval = 0;
int valX = (ax * 100) + 200;
int toSendX = map (valX, 100, 300, 50, 950);
int valY = (ay * 100) + 200;
int toSendY = map (valY, 100, 300, 950, 50);
Serial.print(toSendX);//Send xval value
Serial.print(',');
Serial.print(toSendY);//Send yval value
Serial.print(',');
Serial.print(btnval);//Send btnval value
Serial.println(',');
delay(200);
delay(100);
}
Programming Processing:Processing is open source software which is used by artists for Graphics designing. This software is used to develop software and Android applications. It is quite easy to develop and very much similar to the Android Development IDE. Hence I have shortened the explanation. Here you can get the Processing IDE: https://processing.org/download
The Processing Code for the Space Invaders Game is given below:
// SPACE INVADERS
// AUTHOR: GUILLERMO PEREZ GUILLEN
import processing.serial.*; //Transferred to the serial library
import processing.sound.*;
SoundFile file;//Create SoundFile objects file
FFT fft; //Create FFT objects fft
Serial myPort; //Create Serial objects myPort
PImage img;
int Rw[] = new int[3];
byte inBuffer[] = new byte[100];
int fire[]=new int[1];
Sky stars = new Sky();
Rect rect1;
Box[] boxes;
Time timer;
Drop[] drop;
PImage head;
int totaldrop=0;
int totalboxes=0;
void setup(){
file = new SoundFile(this,"Linked Horizon.mp3");
file.play();
size(560,600);
// Open the serial port and set the baud rate to 9600
// This experiment blues board is connected to COM23, here please
myPort = new Serial(this,"COM23",9600);
img = loadImage("LOGO.png");
fire[0] = 0;
smooth();
rect1=new Rect();
stars.setup();
head = loadImage("spaceship.png");
timer=new Time(300);
drop=new Drop[1000];
boxes=new Box[100];
timer.start();
}
void draw(){
background(0);
readSensors();
rect1.setlocation(-Rw[1]/2+275,-Rw[0]/2+550);
rect1.display();
stars.move();
stars.display();
imageMode(CENTER);
image(head,-Rw[1]/2+275,-Rw[0]/2+550);
if(timer.isFinished()){
drop[totaldrop]=new Drop();
boxes[totalboxes]=new Box();
totaldrop++;
totalboxes++;
if(totaldrop>=drop.length){
totaldrop=0;
}
if(totalboxes>=boxes.length){
totalboxes=0;
}
timer.start();
}
if(fire[0]==1){
for(int i=0;i<totaldrop;i++){
drop[i].move();
drop[i].display();
}
}
for(int j=0;j<totalboxes;j++){
boxes[j].move();
boxes[j].display();
for(int i=0;i<totaldrop;i++){
if(drop[i].intersect(boxes[j])){
boxes[j].caught();
drop[i].caught1();
}
if(rect1.inter(boxes[j])){
gameover();
}
}
}
image(img,520,550);
}
void gameover() {
fill (240, 40, 40);
textSize (60); //
textAlign(CENTER);
text ("GAME OVER", width/2, height/2);
}
class Time{
int savedtime;
int totaltime;
Time(int temptotaltime){
totaltime=temptotaltime;
}
void start(){
savedtime=millis();
}
boolean isFinished(){
int passedtime=millis()-savedtime;
if(passedtime>totaltime){
return true;
}else{
return false;
}
}
}
class Drop{
float x,y;
float r;
float speed;
color c;
Drop(){
if(Rw[2]==0){
r=3;
y=-Rw[0]/2+550;
x=-Rw[1]/2+275;
speed=25;// 30
c=color(255,0,0);
fire[0]=1;
}
}
void move(){
y=y-speed;
}
void display(){
noStroke();
fill(c);
for(int i=9;i>r;i--){
ellipse(x,y-i*6,i*2,i*2);
}
}
boolean intersect(Box b){
float distance=dist(x,y,b.x,b.y);
if(distance<r+55){
return true;
}else{
return false;
}
}
void caught1(){
speed=0;
y=-1000;
}
void stop2(){
speed=0;
}
}
class Box{
float x = random(width);
float y = random(1);
int life;
int speed;
Box(){
life = 3;
speed =1;
}
void display(){
ellipseMode (CENTER);
rectMode (CENTER);
stroke (255);
strokeWeight (1);
fill (37, 198, 37); // green
rect (x, y-15, 65, 6);
rect (x, y-15, 85, 5);
arc (x, y-8, 16, 35, PI, PI*2);
ellipse (x, y-10, 35, 16);
fill (0, 80, 192); // blue
ellipse (x-26, y-15, 13, 13);
ellipse (x+26, y-15, 13, 13);
fill (249, 231, 69); // yellow
ellipse (x+26, y-15, 5, 5);
ellipse (x-26, y-15, 5, 5);
}
void move(){
y=y+speed;
}
void caught(){
speed=0;
y=-1000;
}
void stop1(){
speed=0;
}
}
class Sky {
int n = 60;
float speed = 1;
float[] x = new float [n];
float[] y = new float [n];
float[] d = new float [n];
Sky () {
}
void setup() {
for (int i=0; i<n; i++) {
if (i%5 == 0)
d[i] = random (0, 2);
else
d[i] = 3;
x[i] = random (0, width);
y[i] = random (-height, height*2);
}
}
void move() {
for (int i=0; i<n; i++) {
y[i] += d[i]*speed;
if (y[i]>height*2)
y[i] = random (-height-100, -height+100);
}
}
void display() {
fill (255);
noStroke();
for (int i=0; i<n; i++) {
ellipse (x[i], y[i], d[i], d[i]);
}
}
}
class Rect{
float x;
float y;
float w;
float h;
Rect(){
x=0;
y=0;
w=85;
h=60;
}
void setlocation(float tempx,float tempy){
x=tempx;
y=tempy;
}
void display(){
noStroke();
fill(0);
rectMode(CENTER);
rect(x,y,w,h);
}
boolean inter(Box b1){
float distance1=dist(x+40,y+30,b1.x+40,b1.y+6);
if(distance1<70){
return true;
}else{
return false;
}
}
}
void readSensors(){
if(myPort.available()>0){
if(myPort.readBytesUntil(10,inBuffer)>0){//Read to determine whether the wrap 10BYTE
String inputString = new String(inBuffer);
String inputStringArr[] = split(inputString,',');
Rw[0] = int(inputStringArr[0]);//Read the X value
Rw[1] = int(inputStringArr[1]);//Read the y value
Rw[2] = int(inputStringArr[2]);
Rw[0] = 515 - Rw[0];//Rocker midpoint value 515 into 0
if(Rw[0]<0){
Rw[0]=0;
}
Rw[1] = Rw[1] - 515;//Converted to negative (rocker line out)
}
}
}
My Blues board uses the COM23 serial port. You must verify which port your programming board uses.
myPort = new Serial(this,"COM23",9600);
Please, before running this code you must install the audio library as shown in the image below:
Now since our Processing and Arduino sketch is ready, just upload the below given program to PlatformIO and connect your Blues Swan to user PC thorough programming cable and launch the game by Run the Processing code file (Space_Invaders.pde). That's it! Move your Accelerometer and play your Space Invaders Game. The Video will guide you through the complete project.
Conclusion- In this first version I have fulfilled the main goal of designing a portable device for a disabled person while playing their favorite game on the PC or laptop or other compatible device.
- This joystic weighs little and you only have to insert one finger to hold it comfortably.
- I have had other ideas about adapting it to a hat or cap. It could even fit one leg. The options are incredible! Maybe version 2 will be a wireless device.
- As for the game with processing, the next challenge is to add several levels and scores, as well as various enemy spaceships.
Comments