Categories: Java | Java ME | Games | How To | Code Examples
This page was last modified 13:20, 12 February 2008.
How to develop a game - Part 7
From Forum Nokia Wiki
Now that we have our Arkanoid single player experience complete is time to connect to rest of the world. After all better than show off our high-scores to our friends is to show them to everybody in the Internet!
One of the main features of mobile devices is the ability to be connected almost everywhere anytime. Java ME allows easy access to these communications features of your device:
- HTTP
- Socket
- SMS
- Bluetooth
During this lesson we are going to learn to use a HTTP connection to send our highscores data to a central server and to use the SMS functionality to invite other friends to play our Arkanoid game.
Connector and Connections
The main entry point for network functionality is the factory class Connector. This class allows the creation of Connection objects trough the following static methods:
- open(String name)
- open(String name, int mode)
The name parameter is a URL string that identifies the connection you want to make. Depending of the protocol in the URL, a different kind of Connection object is returned. Here is a list of URL and the correspondent Connection objects:
- "http://www.server.com", returns a http connection, using the class HttpConnection
- "socket://server.com:8080", returns a TCP/IP connection
- "btsp://2343434d3434", returns a bluetooth connection
- "sms://+351910000000", returns a SMS connection to the phone +351910000000
Of those protocols only HTTP is mandatory on all Java ME phones, all the others are device dependent, however the majority of new phones support all these protocols.
One thing you must be aware is that when you try to open any kind of connection, the user of your application is notified by the Application Management System. He then has the option to accept or deny your connection, if he denies your application will receive a SecurityException and no communication will happen.
HTTP
Let's start with HTTP connections, one of the most common type of connections used. To create an HTTP connection you just need to do the following:
import javax.microedition.io.Connector; import javax.microedition.io.HttpConnection; public class Network { public byte[] httpConnection(String url, byte[] dataToSend) throws IOException { HttpConnection hc = null; // Prepare Connection hc = (HttpConnection) Connector.open(url, Connector.READ_WRITE); [...] } }
The HTTP connections are represented by the HttpConnection class, this class has three states:
* Setup, in which you can setup the request parameters * Connected, where you can send and receive data. You can only send data first and then receive the answer. * Closed, after you read the data and the connection is ended.
When you receive the HttpConnection object from the Connector it's in the Setup state. You can then configure the request parameters. One of the main options is the HTTP request method (POST, GET or HEAD).
public byte[] httpConnection(String url, byte[] dataToSend) throws IOException { [..] if (dataToSend == null){ hc.setRequestMethod( HttpConnection.GET ); } else { hc.setRequestMethod( HttpConnection.POST ); } [...] }
You can also configure the request properties like the content type of what you are sending in case of a POST.
hc.setRequestProperty("Content-type", "application/octet-stream" );
After you have configured the connection you can start send data, when you start this process you cannot change the request parameters. If the communication goes trough you start receiving data.
public byte[] httpConnection(String url, byte[] dataToSend) throws IOException { [...] if (dataToSend != null){ // Write Data OutputStream os = hc.openOutputStream(); os.write( dataToSend ); os.close(); } // gets answer from server int rc = hc.getResponseCode(); // check http response if (rc == HttpConnection.HTTP_OK){ // Read Data InputStream in = hc.openInputStream(); ByteArrayOutputStream tmp = new ByteArrayOutputStream(); int ch; while ((ch = in.read()) != -1) { tmp.write(ch); } data = tmp.toByteArray(); in.close(); hc.close(); } return data; }
We now have our httpConnection() method complete let's use it in our game to send the high scores to a server. Start by adding a new option to our highscores screen:
public Displayable initScoreForm() { [...] cmdSendHighScore = new Command("Send to Server", Command.ITEM, 1); highScoreForm.addCommand(cmdSendHighScore); [...] }
And then create a method to use it when this Command is selected:
public String sendScore(String user, int score) { String result = "No Answer"; // server to send data String url = "http://www.sergioestevao.com/midpAdventures/post.php"; // prepare http request String urlTotal = url + "?user=" + user + "&score=" + score; byte[] data = null; try { data = network.httpConnection(urlTotal, null); } catch (IOException e) { result = "Communication Problems"; e.printStackTrace(); } catch (SecurityException s) { // user denied access to communication result = "You need to allow communications in order to send the highscore to server."; s.printStackTrace(); } // chek data return. if (data != null) { result = new String(data); } return result; }
And call it when the Command is used
if (cmd == comInviteSend) { result = sendScore(scores[0].name, scores[0].value); display(new Alert("Result", result, null, AlertType.INFO)); }
If you try this code has it is you will receive the following warning:
Warning: To avoid potential deadlock, operations that may block, such as networking, should be performed in a different thread than the commandAction() handler.
Remember, you are executing this network code as an answer to an user event, that is being executed on the UI thread. If this code blocks or takes a long time to execute all the application will be stuck.
To avoid this issue you must use a thread to do you network related tasks. We start by declaring a thread and some state variables to control the actions of the thread.
private static final int ACTION_SEND_HIGHSCORE = 0; public Thread workThread; public boolean active = false;
Then every time we need to do a time consuming event, we call a method that prepares the thread and starts the action.
public void doAction(int action) { // stores action to do this.action = action; // check if thread is already created if (workThread == null) { workThread = new Thread(this); workThread.start(); active = true; } // wakes up thread to work synchronized (this) { notify(); } }
The new thread will execute our run method and do the actions we need
public void run() { while (active) { // check what action to do switch (action) { case (ACTION_SEND_HIGHSCORE): // send the first score to the server result = sendScore(scores[0].name, scores[0].value); commandAction(cmdReceiveHighScore, highScoreForm); break; } // waits for action to do. synchronized (this) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Don't forget to declare the Runnable interface in your midlet
public class MyMidlet extends MIDlet implements CommandListener, Runnable {
Now we just need to call our doAction() method when the user chooses the send high score option. You may have noticed that our run() method invokes a command called cmdReceiveHighScore. This is used to show results of the communication to the user.
if (cmd == cmdSendHighScore) { doAction(ACTION_SEND_HIGHSCORE); } if (cmd == cmdReceiveHighScore) { display(new Alert("Result", result, null, AlertType.INFO)); }
SMS
Our second use to communications in JavaME is to send invitations to play the game to our friends. And you can have some competition in the high-scores tables.
First we are going to implement the method that sends the sms on our network class.
public boolean sendSms(String number, String message){ boolean result = true; try { //sets address to send message String addr = "sms://"+number; // opens connection MessageConnection conn = (MessageConnection) Connector.open(addr); // prepares text message TextMessage msg = (TextMessage)conn.newMessage(MessageConnection.TEXT_MESSAGE); //set text msg.setPayloadText(message); // send message conn.send(msg); } catch (Exception e) { result = false; } return result; }
As you can see we just need to use the open() method of the Connector class with an url of the format "sms://number". Then you create a TextMessage and send it trough the Connection. The size of the message is limited to around 160 characters.
Now we need to create a form to receive the name and phone information from the user.
public Displayable initInviteForm() { if (inviteForm == null) { inviteForm = new Form("Invite"); inviteForm.setCommandListener(this); inviteForm.addCommand(initBackCommand()); inviteName = new TextField("Name:", "", 20, TextField.ANY); inviteNumber = new TextField("Number:", "", 20, TextField.PHONENUMBER); inviteForm.append(inviteName); inviteForm.append(inviteNumber); comInviteSend = new Command("Invite", Command.ITEM, 1); inviteForm.addCommand(comInviteSend); } return inviteForm; }
And implement the commands action to show our form and send the message using our worker thread.
public void commandAction(Command cmd, Displayable display) { [...] else if (display == inviteForm) { if (cmd == comBack) { display(initMainForm()); } if (cmd == comInviteSend) { doAction(ACTION_SEND_INVITE); } } [...] }
Finally we implement the new action in our run method
public void run() { [...] case (ACTION_SEND_INVITE): // invite another player to play String inviteMessage = " invites you to play Transnoid!"; network.sendSms(inviteNumber.getString(), inviteName.getString() + inviteMessage); break; } [..] }
Now run your game and start sending invitations to your friends :). See you soon.
Downloads:
| Related Discussions | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| making your game available. | smb101 | Mobile Java General | 0 | 2003-12-24 10:32 |
| downloading game | er_rajiv | Mobile Java General | 0 | 2004-01-29 16:19 |
| Making my game available for download | smb101 | Mobile Java General | 3 | 2004-06-24 14:00 |
| 3D game | drrpbs | Mobile Java General | 5 | 2006-02-06 12:34 |
| 3650 and SIS download - cant uninstall | rixis | General Symbian C++ | 4 | 2004-02-03 09:34 |
