Join Now
Quality Rating:
  • Currently 0.0 / 5
(0.0 / 5 - 0 votes cast)
Expertise Level:
  • Currently 0.0 / 5
(0.0 / 5 - 0 votes cast)

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
 
Powered by MediaWiki