Sie sind auf Seite 1von 10

Smarter Version of Classic Snake Game on Android

Final Project Report

Abstract-- This project is an implementation 2. Android Studio (on host computer)


of a classic ‘snake game’ on android platform.
This is solely a sensor based game where C. User Interface and app layout
different smartphone sensors have been Interactive Layout design for an app is one of
incorporated to make it smarter. the most important parts of any app
development. The challenge is more when the
INTRODUCTION app is a game. A Layout defines the visual
structure for a user interface, such as UI for an
A. Aim activity or app widget. There are two ways to
Initial goals: declare a layout for an application. Android
provides a convenient way to declare the layout
1. Use of two different sensors: accelerometer components in a separate XML file.
and proximity sensor to control the game. Programmer can easily use them in their java
source code by referring to that file. Another
2. Use of basic touch gestures. way is to instantiate a layout at runtime by
programmatically declaring its components.
Additional goal: Play the game on one device We developed our app following the first
and control from another via Bluetooth approach as we found it convenient to keep the
connection. interface presentation of our app from the
source code. We could easily change different
B. Motivation parameters in the layout components without
In the era of smartphones, we are trying to make modifying the source code at all.
the classic snake smarter to make it comparable User interface layout is a hierarchical
with the other games of smartphones. Instead of representation of the view groups it consist of.
using the buttons to control the snake, we’ll be Depending on the organization of the view
using the sensors embedded in a device. groups inside the layout, there are few
Anyone can play the game by just waving or
categories such as linear layout, Relative
moving the device without any touch or by layout, Grid layout etc. For our app, we
swiping along the screen.
organized the view groups according to a
relative layout. Relative layout displays its
BACKGROUND child views relative to its sibling elements
rather than defining any absolute positions. It
In a classic snake game, there is a snake which eliminates any nested view groups and
can go in the four directions in a two- maintains a flat layout hierarchy.
dimensional screen. The goal is to reach its food D. Sensors
randomly generated on the screen. Its length 1. Accelerometer
increases each time it reaches or eats its food. Accelerometer sensor can give us the real-time
There are four buttons to control its up, down, acceleration along X, Y and Z-axis of the smart-
left or right movement. phone. So inside the android game application,
we take the readings from the sensor and
A. Hardware Requirement convert them to basic four directions: UP,
1. A Smartphone with android OS to test the DOWN, LEFT and RIGHT. So whenever the
application phone moves UP, the application detects the
2. Host Computer to create, debug and test the movement as UP command to move the snake
application and so on. However, in a snake game, 1800
movement is not allowed. So we’ve to ignore a
UP/DOWN command when the snake is
B. Software Requirement moving in DOWN/UP direction and
1. Android OS (on smartphone)

1
LEFT/RIGHT command when moving in gone. The same button is named as Restart
RIGHT/LEFT directions. when a game is over and is used to restart the
game. Another button placed at the top right
2. Proximity sensor corner of the screen is used to pause or resume
Proximity sensor can detect the presence of an the game. It is visible only when the game is
object near it. A simple proximity sensor gives started or restarted. Whenever the game is
the reading “NEAR” of “FAR”. We implement paused, the button’s text field is changed to
this functionality to alternatively resume and vice versa.
PAUSE/RESUME the game. So just a hand
wave over the phone would pause the game and
another wave would resume the game.

3. Touch gesture control


We also have implemented the basic four
gestures controls. Sliding a finger along UP,
DOWN, LEFT or RIGHT would steer the snake
in the corresponding directions. This reading or
the reading from the accelerometer guide the
snake on the screen.

SYSTEM SETUP AND DESIGN

A. Basic Design Overview


There are two basic functional blocks in our
design. One is to sensor data acquisition and
interpretation. Other part is the gameplay
controlling and UI updating according to sensor Figure1: System block diagram.
data. There is another additional part in our
design that enables the user to control the game 2. Score and level text field
based on the sensor data of another android
phone. For that part another phone will receive There are two text views we used in our layout.
the sensor data and send it to the phone where One is shown in the top left corner and the other
the game is played. A Bluetooth is at the top middle of the screen. The first one
communication is needed to implement this is used to show the score and level of the game
part though we could not make it working continuously. This is visible only when the
finally. game is on running. The other text view is used
to show the final score of the game. This is
B. App Layout visible only when the game is over and not
restarted.
There are a large number of built in android
widgets such as button, text view, image view 3. Additional Menu Items
etc. But some app has unique requirements that
We have declared some menu options in the
can’t be met with these built in views. In that
xml menu file. The important one is the exit
case android facilitates the programmer to
option. User can safely exit from the game at
create his own customized view meeting the
any time simply by selecting exit options from
specific need for the app.
pop up menu items. There is a help menu that
1. Start and Pause Button helps user to know about the game play
instructions. The other option in the menu item
Used android widgets in out app layout are two is credit that shows the name of the developers.
buttons, two text views and one custom view.
One of the button named Start is used to start 4. Customized view for drawing
the game and placed at the center of the layout.
We defined our custom view in a public class
It is visible when the app is launched first.
having the same name as the view has. This
When the game starts its visibility is made

2
class extends a public android class, Surface interface to the actual surface upon which our
view and implements two android public graphics will be drawn. It holds all of the draw
interface SurfaceHolder.Callback and calls. Canvas defines what to draw on the
SensorEventListener. Surface View provides a surface. On the other hand, Paint defines the
dedicated drawing surface embedded inside a features that the drawing will have. Features
view hierarchy. The purpose of this class is to may include shape, color etc. Using Canvas,
provide a surface in which a secondary thread actually all of the drawings are performed upon
can render into the screen. an underlying Bitmap, which is placed into the
particular positions within the window. In this
5. Drawing mechanism app we have three drawable objects- snake
For the graphical design of our game we used body, game boundary and food that the snake
some android class such as Canvas and Paint tries to catch in order to increase. We used a
which made it easy for us. Canvas works as an tile block image as the bitmap for our game
interface to the actual surface upon which our drawings. The same tile image is used to draw
graphics will be drawn. It holds all of the draw all of the three drawable objects of the game.
calls. Canvas defines what to draw on the Canvas provides a method named drawBitmap
surface. On the other hand, Paint defines the that facilitates the drawing of the tiles into
features that the drawing will have. Features specified position on the screen. Android
may include shape, color etc. Using Canvas, defines this method as public void drawBitmap
actually all of the drawings are performed upon (Bitmap bitmap, float left, float top, Paint
an underlying Bitmap, which is placed into the paint).
particular positions within the window. In this
app we have three drawable objects- snake
body, game boundary and food that the snake
tries to catch in order to increase. We used a
tile block image as the bitmap for our game
drawings. The same tile image is used to draw
all of the three drawable objects of the game.
Canvas provides a method named draw Bitmap
that facilitates the drawing of the tiles into
specified position on the screen. Android
defines this method as public void drawBitmap
(Bitmap bitmap, float left, float top, Paint
paint). Parameters bitmap takes the bitmap to
be drawn which is the tiles image in our app.
Parameters left and top specifies the origin of
the drawable tiles as its top left corner. Three
individual paint objects were declared for the
three drawable elements. These objects are
painted with different colors to distinguish from
each other. Among the three drawable
elements, only the game boundary is static and
the other two- snake body and foods are
changed dynamically with the game flow. To
draw these elements, we stored all the
coordinates of the individual drawables into
separate arrays. These arrays serially keep the x
coordinates and y coordinates of the top left
corner of all of the tiles used for drawing.
5. Drawing mechanism:
For the graphical design of our game we used Figure 2: App layout at different phase of the
some android class such as Canvas and Paint game. (a) App launched (b) game paused (c)
which made it easy for us. Canvas works as an game resumed (d) game over

3
Parameters bitmap takes the bitmap to be drawn changes in accelerometer readings are filtered
which is the tiles image in our app. Parameters out. To be compatible with a natural snake
left and top specifies the origin of the drawable movement in the game, a 1800 movement is not
tiles as its top left corner. Three individual paint allowed. So we ignore a UP or DOWN
objects were declared for the three drawable command when the snake is moving in either
elements. These objects are painted with DOWN or UP direction and LEFT or RIGHT
different colors to distinguish from each other. command when moving in RIGHT or LEFT
Among the three drawable elements, only the directions correspondingly.
game boundary is static and the other two-
snake body and foods are changed dynamically
with the game flow. To draw these elements,
we stored all the coordinates of the individual
drawables into separate arrays. These arrays
serially keep the x coordinates and y
coordinates of the top left corner of all of the
tiles used for drawing.
B. Reading and converting accelerometer data

Most of the smartphones and tablets have built-


in accelerometer sensors in them. Android
provides a SensorManager class to access and
read all the sensors of an android device. To
have access to the accelerometer data, it has to
be registered within this class.
Accelerometer measures and provides the raw Figure 3: Axis on a smartphone
acceleration along the x, y and z axis of a
smartphone. A simple form of this algorithm can be like this:
In the event of any of the change in
measurements along these three axes,the event /* in declaration or in the constructor, create an
onSensorChanged() method is called. If the instance of the sensorManager class*/
phone is laid flat on a table, then these would be SensorManager sm = (SensorManager)
the readings provided by the SensorEvent class. context.getSystemService(Context.SENSOR_
event.values[0]: Acceleration along x- SERVICE);
axis. If the phone is not moving, this value is
0.0. /*now register accelerometer to this class */
event.values[1]: Acceleration along x- Sensor accelerometer =
axis. If the phone is not moving, this value is sm.getDefaultSensor(Sensor.TYPE_ACCELE
9.81 (due to the force of gravity). ROMETER);
event.values[2]:.Acceleration along x-
axis. If the phone is not moving, this value is float THRES_ACCL = 2;
0.0. /* inside onSensorChanged method*/
if (event.sensor.getType() ==
To achieve this, the accelerometer sensor is Sensor.TYPE_ACCELEROMETER) {
sampled at a sufficiently quick intervals and /*0=right, 1=top, 2=left, 3=bottom*/
then we compare the two readings. We catch long actualTime = event.timestamp;
those changes and convert them into basic four if (actualTime - lastUpdate <
left, right, top and bottom directions. After samplingPeriod) {
testing on our smartphones, we learned that a return;
decrease in x-axis reading means a movement }
in right and vise-versa for left a decrease in y- lastUpdate = actualTime;
axis reading means a movement in top direction if(XX-event.values[0]>THRES_ACCL){
and vise-versa for bottom. We also choose //acceleration.setText(XX+" Right
minimum thresholds for these changes to "+event.values[0]);
ensure smooth gameplay. Therefore, negligible if(dir!=2) {

4
dir = 0; //right
}
}
else if(event.values[0]-XX>THRES_ACCL){
if(dir!=0) {
dir = 2; //left
}
}
else if(YY-event.values[1]>THRES_ACCL){
if(dir!=3){
dir = 1; //top
}
}
else if(event.values[1]-YY>THRES_ACCL){
if(dir!=1){
dir = 3; //bottom
}
}
XX = event.values[0];
YY = event.values[1];
ZZ = event.values[2]; Figure 4: Location of proximity sensor on a
} smartphone

C. Reading and converting proximity sensor data /* in declaration */


/*register proximity sensor to the
Most of the smartphones also come with a sensorManager class*/
proximity sensor. It can be be accessed from the Sensor mProximity =
SensorManager class too. If an object like a sm.getDefaultSensor(Sensor.TYPE_PROXI
hand is placed above this sensor, then it reads MITY);
0.0 or NEAR. If the hand is moved away, it boolean pauseResume =
reads 1.0 or FAR. Proximity sensors with true; //true=running, 0 = paused
higher resolution than just the binary values are
also used, but this is the most common among if (event.sensor.getType() ==
smartphones. The readings provided by the Sensor.TYPE_PROXIMITY) {
SensorEvent class are: /* inside onSensorChanged class*/
event.values[0]: Hand is above the if(event.values[0]==0.0){
phone. Reads 0.0. if(pauseResume){
event.values[0]: Hand is moved pauseResume = false;
away.Reads 1.0. }
else{
Now since the event of change of proximity pauseResume = true;
sensor is not continuous, we don’t need }
sampling of time for the proximity sensor. }
Our design was to pause or resume the game on else if(event.values[0]==1.0){
a hand wave over the phone. If the game is acceleration.setText("FAR &
running, then a hand wave would cause it to "+pauseResumeText);
pause and while it is in pause, hand wave would }
resume the game. So two hand-waves or two }
NEAR (1.0) readings mean the same game state
is restored. The code segment for this part looks D. Reading and converting touch gesture action
like this:
Touching the phone with a finger and sliding
along a direction is a touch gesture. Android
provides a variety of classes for this. We used

5
the MotionEvent class to detect sliding which detects different condition of the game
movements on the left, right, top or bottom and take necessary decisions accordingly.
directions. When a user touches the screen,
onTouchEvent() method is called and the 1. Check Collision
corresponding touch action can be read from At every instant of timing schedule game
the MotionEvent class. For our application, we engine checks if there is any collision happened
ignored all other types of touch events. between snake body and any other drawable
So we collect the directional readings and as components including snake body. If collision
usual ignore the 1800 movement. The code with game boundary is detected, snake body
segment for the this part is something like this: comes out of the other end of the boundary. If
snake collides with itself i.e any part of its body
/* inside onTouchEvent method*/ then game with will be over and final score will
if (event.getAction() == be shown. If snake collides with the food its
MotionEvent.ACTION_DOWN) { length increases and scores increase.
initX = event.getX();
initY = event.getY(); 2. Timer scheduling
The game speed is defined by a timer that may
}
be updated on certain occasions. If snake passes
double totY = Math.abs(Math.abs(finalY) -
a level its timer is scheduled with a new value
Math.abs(initY));
which is proportional to that level. If game is
double totX = Math.abs(Math.abs(finalX) -
paused the timer is cancelled and it is
Math.abs(initX));
rescheduled when the game is resumed.
if (event.getAction() ==
MotionEvent.ACTION_MOVE) { 3. Snake Move
finalX = event.getX();
finalY = event.getY(); When there is no collision, pause or user input
totY = Math.abs(Math.abs(finalY) - found, the snake should moves ahead in its
Math.abs(initY)); previous direction. If snake is moving
totX = Math.abs(Math.abs(finalX) - horizontally and user selects up or down
Math.abs(initX)); direction snake will sanitized to the new
direction. In the same way when snake moves
float threshold = 20; //chosen based on vertically and user selects left or right direction
testing snake will head to the new direction. But user
if (totY > threshold || totX > threshold) { cannot redirect the snake just to the opposite
if (totX > totY) { direction such as left to right or vice versa and
if (finalX > initX) { up to down or vice versa.
engine.setDirection(1); 4. Random Food generation
} else if (finalX < initX) {
engine.setDirection(3); Every time snake eats a food, a new food is
} generated at a random location within snake
} else if (totY > totX) { boundary. Few bugs are possible if we do not
if (finalY > initY) { set some bound to this randomness. For proper
engine.setDirection(0); operation we have to make sure certain things.
} else if (finalY < initY) { Firstly, food should be within the game
engine.setDirection(2); boundary. Then, food should not be at the same
} place with the game boundary or snake body.
} We used some bounded random number
} generation technique to ensure these criteria for
} food generation.

E. Game Engine Development


Game engine is the core component of this
game that decides the overall gaming
mechanism. It has several functional block

6
F. Additional Improvement be different to generate different tones. Last
argument (500) is the duration of the tone
1. Adaptable Screen Size playback.*/
toneG.startTone(ToneGenerator.TONE_CDM
If we had developed our application on iOS, A_EMERGENCY_RINGBACK, 500);
we’d not need to worry about the screen size
much because there is only a limited number of
variations. But since there is a huge amount of The duration of the sound is very short for
variations among devices that run on android, snake movement and somewhat long when the
we needed to think of adaptable game boundary game is over.
that is configured programmatically based on
the screen size and resolution of the android G. Remote control using bluetooth
device. DisplayMetrics class provides the
screen-size of an android device. Our final and somewhat ambitious target was to
control and play the snake game from another
DisplayMetrics displayMetrics = new android device. For that purpose, we used
DisplayMetrics(); bluetooth communication. The interface or
activity for Bluetooth connection in our
displayMetrics = application looks like this:
context.getResources().getDisplayMetrics();

We divide the height and width of the screen


with the height and width of the tile
correspondingly that is used to draw the game
boundary. Therefore, inside the game
boundary, the minimum resolution is dependent
on the dimension of the tile we used to draw it.
We also left some space of the screen for
displaying menu like pause, restart, show score
and level etc.

2. Sound generation

The snake makes a beep sound each time it


moves in any direction. There are also also two
different tones to indicate the event of the snake
eating its food and when it destroys itself by
colliding its head with other parts of the body.
ToneGenerator class of android library
provides this functionality. We just call the Figure 5: Interface for communicating via
startTone() method of this class on these cases bluetooth
with different constants defined in android
library for different tones. Step 1: Checking and setup of the bluetooth
connection and make the device visible
The BluetoothAdapter class provides the
interface for setup, enabling of a bluetooth
/*in declaration*/ device and making it visible for a certain period
ToneGenerator toneG = new of time. In simplest form of the code would be
ToneGenerator(AudioManager.STREAM_AL like this:
ARM, 50); //50 is the sound level
BluetoothAdapter mBluetoothAdapter =
/*inside the snakeMove(), eatFood() or BluetoothAdapter.getDefaultAdapter();
collide() functions, the constant names would if (!mBluetoothAdapter.isEnabled() ) {

7
Intent enableBtIntent = new alist.add(tooth.getName()+"\n"+tooth.get
Intent(BluetoothAdapter.ACTION_REQUES Address());
T_ENABLE); }
startActivityForResult(enableBtIntent, }
1); //any integer greater than 0
} Step 3: Setup communication channel between
Intent getVisible = new the paired devices:
Intent(BluetoothAdapter.ACTION_REQUES The device with the controller app acts as a
T_DISCOVERABLE); server and the the device with the game acts as
getVisible.putExtra(BluetoothAdapter.EXTRA a client. A socket connection is established
_DISCOVERABLE_DURATION, 300); //for between these two devices using
300 seconds BluetoothSocket class library. BluetoothDevice
startActivityForResult(getVisible, 0); class represents the device connected.

Step 2: Searching for device /*/////////for client///////*/


Searching for bluetooth device is very simple. private final BluetoothSocket mmSocket;
Just calling the startDiscovery() method private final BluetoothDevice mmDevice;
performs this action. Then the devices found on
search and already paired are kept in an /*constructor method*/
arrayAdapter using BroadcastReceiver class. public ConnectThread(BluetoothDevice
The user can click and select a particular device Device) {
to be paired. BluetoothSocket tmp = null;
mmDevice = Device;
try {
// MY_UUID is the app's UUID string, also
used by the server code
tmp =
Device.createRfcommSocketToServiceRecord
(MY_UUID);
} catch (IOException e) {}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down
the connection
mBluetoothAdapter.cancelDiscovery();
try {
mmSocket.connect();
} catch (IOException connectException) {
try {
mmSocket.close();
} catch (IOException closeException) { }
return;
}
Figure 6: Snapshot from app which shows the }
list of searched bluetooth devices /*/////////// for server//////////*/

public AcceptThread() {
BluetoothServerSocket tmp = null;
if(mBluetoothAdapter.startDiscovery()){ try {
pairedDeviceList = // MY_UUID is the app's UUID string, also
mBluetoothAdapter.getBondedDevices(); used by the client code
alist = new ArrayList(); tmp =
for(BluetoothDevice mBluetoothAdapter.listenUsingRfcommWith
tooth:pairedDeviceList){ ServiceRecord(NAME, MY_UUID);

8
} catch (IOException e) { } The value received on the main game
mmServerSocket = tmp; application is used for controlling the game.
} Since bluetooth is a very buggy and unstable
public void socketConnect() throws connection, we faced a lot of trouble in this part.
IOException { Therefore, we couldn’t exactly finish this part.
BluetoothSocket socket = null; Hopefully, using wifi or NFC connection would
// Keep listening until exception occurs or a solve this problem.
socket is returned
while (true) {
try {
socket = mmServerSocket.accept(); GAMEPLAY AND CONTROL
} catch (IOException e) { To play the game, a user has to move his
break; smartphone in any of the four directions or he
} or she can touch the screen and slide fingers
// If a connection was accepted along any direction. The snake will follow that
if (socket != null) { path. To pause or resume the game, he can just
break; wave his hand over the proximity sensor
} generally located at the top of an android phone
try { and the game will pause/resume. If the snake
mmServerSocket.close(); stumbles upon itself, the game is over. So the
} catch (IOException e) {} goal to keep the snake as long as possible and
} eat as much food as possible. The snake’s
length increases as it eats the food. The score is
Step 4: Sending data over bluetooth: updated and displayed live on the top of the
Whenever a valid control like a valid snake screen. Touching a boundary doesn’t kill it,
movement or pause or resume command is rather it pops out from the opposite direction of
obtained, the sendData() function is called from the screen. After some time, snake’s speed is
inside the onSensorChanged() method. also increased to make it more challenging,
Receiving data is an event triggered by the although there is an upper limit to keep it.
availability of some data over the socket.
ByteArrayOutputStream class is used for To play the game remotely from another
sending and receiving data using a buffer. android device, the player first need to setup the
bluetooth connection with the gaming device.
public void sendData(BluetoothSocket socket, We provide interface for this part too.
int data) throws IOException{
ByteArrayOutputStream output = new
ByteArrayOutputStream(4); CHALLENGES AND DISCUSSIONS
output.write(data); The main obstacle for our project was that we
OutputStream outputStream = didn’t have any previous experience on android
socket.getOutputStream(); or any type of app development. Limited
outputStream.write(output.toByteArray()); experience of object-oriented programming and
} XML also made us slow. So we had to start
from the very basic of android coding and had
public int receiveData(BluetoothSocket to work our way through our project. Because
socket) throws IOException{ the android IDE takes a lot of space and
byte[] buffer = new byte[4]; processor power, we couldn’t run it on our
ByteArrayInputStream input = new laptops (two of us even don’t have a laptop) and
ByteArrayInputStream(buffer); had to work on the school’s computer. This and
InputStream inputStream = being a group of all graduate students with
socket.getInputStream(); limited time made our progress slower than
inputStream.read(buffer); expected. However, still we managed to
return input.read(); complete our goals and now have a good
} platform for further improvement. We learned
a lot from this project and are very confident in

9
app and game development on android
platform.

FUTURE WORK
Since our project was to develop a game, there
may be a tons of different improvements
possible. We tried to incorporate many
additional features in our game like game
sound, variable screen size, buttons, multiple
color of snake’s body, multiple levels and
displaying live scores etc. Even though we can
add many things. One very important work is to
make the touch and orientation very smooth for
user’s ease. Much more testing and user
reviews are needed for this. We can also work
on the graphics and make it more like modern
games and more user-friendly. We can analyze
our coding more carefully for possible power
optimization, processing speedup and lower
memory footprint.

10

Das könnte Ihnen auch gefallen