Java
  Home arrow Java arrow Page 5 - Storing and Retrieving Data
Dev Articles Forums 
ADO.NET  
Apache  
ASP  
ASP.NET  
C#  
C++  
ColdFusion  
COM/COM+  
Delphi-Kylix  
Design Usability  
Development Cycles  
DHTML  
Embedded Tools  
Flash  
Graphic Design  
HTML  
IIS  
Interviews  
Java  
JavaScript  
MySQL  
Oracle  
Photoshop  
PHP  
Reviews  
Ruby-on-Rails  
SQL  
SQL Server  
Style Sheets  
VB.Net  
Visual Basic  
Web Authoring  
Web Services  
Web Standards  
XML  
Mobile Linux 
App Generation ROI 
IBM® developerWorks 
Sun Developer Network 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid 
Request Media Kit
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
JAVA

Storing and Retrieving Data
By: Apress Publishing
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 4 stars4 stars4 stars4 stars4 stars / 14
    2005-05-12

    Table of Contents:
  • Storing and Retrieving Data
  • Serializing More Complex Data Using Streams
  • Using Data Types and Byte Arithmetic
  • Applying Data Storage to a Game
  • Converting an array of bytes into a dungeon
  • Creating the Complete Example Game
  • DungeonManager.java
  • Doors and keys

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article
     
     
    ADVERTISEMENT


    Storing and Retrieving Data - Converting an array of bytes into a dungeon


    (Page 5 of 8 )

    Listing 5-5. BoardDecoder.java

      package net.frog_parrot.dungeon;
     
    import javax.microedition.lcdui.*;
      import javax.microedition.lcdui.game.*;
     
    import net.frog_parrot.util.DataConverter;
      /**
        * This class contains the data for the map of the dungeon.
        *
       
    * @author Carol Hamer
       
    */
      public class BoardDecoder {
        //-----------------------------------------------------    // fields
      /**
       
    * The coordinates of where the player starts on the map
        * in terms of the array indices.
       
    */
      private int[] myPlayerSquare;
       
    /**
       
    * The coordinates of the goal (crown).
        
    */
      private int[] myGoalSquare;
     
    /**
        * The coordinates of the doors.
       
    the there should be two in arow of each color,
       
    * following the same sequence as the keys.
       
    */
      private int[][] myDoors;
     
    /**
       
    * The coordinates of the Keys.
       
    they should be of each color,
       
    * following the same sequence as the doors.
          */
      private int[][] myKeys;
      /**
       
    * The coordinates of the stone walls of the maze,
       
    * encoded bit by bit.
       
    */
      private TiledLayer myLayer;
     
    /**
        * The data in bytes that gives the various boards.
       
    * This was created using EncodingUtils...
       
    * This is a two-dimensional array: Each of the four
       
    * main sections corresponds to one of the four
       
    * possible boards.
        */
      private static byte[][] myData = {
          { 0, 0, -108, -100, -24, 65, 21, 58, 53, -54, -116, -58, -56,
          -84, 115, -118,
          -1, -1, -128, 1, -103, -15, -128, 25, -97, -127, -128, 79, -14,
          1, -126, 121, -122, 1, -113, -49, -116, 1, -100, -3, -124, 5,
          -25, -27, -128, 1, -1, -1 },
          { 0, 1, 122, 90, -62, 34, -43, 72, -59, -29, 56, -55, 98, 126,
          -79, 61,
          -1, -1, -125, 1, -128, 17, -26, 29, -31, 57, -72, 1, -128, -51,
          -100, 65, -124, 57, -2, 1, -126, 13, -113, 1, -97, 25, -127,
          -99, -8, 1, -1, -1 },
          { 0, 2, 108, -24, 18, -26, 102, 30, -58, 46, -28, -88, 34,
          -98, 97, -41,
          -1, -1, -96, 1, -126, 57, -9, 97, -127, 69, -119, 73, -127,
          1, -109, 59, -126, 1, -26, 103, -127, 65, -103, 115, -127,
          65, -25, 73, -128, 1, -1, -1 },
         
    { 0, 3, -114, 18, -34, 27, -39, -60, -76, -50, 118, 90, 82,
          -88, 34, -74,
          -1, -1, -66, 1, -128, 121, -26, 125, -128, -123, -103, 29,
          -112, 1, -109, 49, -112, 1, -116, -31, -128, 5, -122, 5,
          -32, 13, -127, -51, -125, 1, -1, -1 },
     
    };

      //-------------------------------------------------------  // initialization

      /**
        * Constructor fills data fields by interpreting
       
    * the data bytes.
        */
      public BoardDecoder(int boardNum) throws Exception {
        // you start by selecting the two dimensional
        // array corresponding to the desired board:
        byte[] data = myData[boardNum];
        // The first two bytes give the version number and
        // the board number, but you ignore them because
        // they are assumed to be correct.
        // The third byte of the first array is the first one
        // you read: it gives the player's starting coordinates:
        myPlayerSquare = DataConverter.decodeCoords(data[2]);
        // the next byte gives the coordinates of the crown:  
        myGoalSquare = DataConverter.decodeCoords(data[3]);
        // the next 4 bytes give the coordinates of the keys: 
        myKeys = new int[4][];
        for(int i = 0; i < myKeys.length; i++) {
          myKeys[i] = DataConverter.decodeCoords(data[i + 4]);
        }
        // the next 8 bytes give the coordinates of the doors:     myDoors = new int[8][];
        for(int i = 0; i < myDoors.length; i++) {
          
    myDoors[i] = DataConverter.decodeCoords(data[i + 8]);
        }
        // now you create the TiledLayer object that is the
        // background dungeon map:
       
    myLayer = new TiledLayer(16, 16,
              Image.createImage("/images/stone.png"), 
              DungeonManager.SQUARE_WIDTH, DungeonManager.SQUARE_WIDTH);
       
    // now you call an internal utility that reads the array
        // of data that gives the positions of the blocks in the
        // walls of this dungeon:
        decodeDungeon(data, myLayer, 16);
      }
      //-------------------------------------------------------  // get/set data
      /**
        * @return the number of boards currently stored in 
          * this class.
        */
      public static int getNumBoards() {
       
    return(myData.length);
      }
     
    /**
        * get the coordinates of where the player starts on the map
       
    * in terms of the array indices.
        */
        public int[] getPlayerSquare() {
          
    return(myPlayerSquare);
        }
      /**
        * get the coordinates of the goal crown
       
    * in terms of the array indices.
        */
      public int[] getGoalSquare() {
       
    return(myGoalSquare);
      }
     
    /**
       
    * get the tiled layer that gives the map of the dungeon.
        */
      public TiledLayer getLayer() {
       
    return(myLayer);
      }
      /**
        * Creates the array of door sprites. (call this only once to avoid
       
    * creating redundant sprites).
        */
     
    DoorKey[] createDoors() {
        DoorKey[] retArray = new DoorKey[8];
        for(int i = 0; i < 4; i++) {
         
    retArray[2*i] = new DoorKey(i, false, myDoors[2*i]);
         
    retArray[2*i + 1] = new DoorKey(i, false, myDoors[2*i + 1]);
        }
        return(retArray);
     
    }
     
    /**
        * Creates the array of key sprites. (call this only once to avoid
          * creating redundant sprites.)
        */
     
    DoorKey[] createKeys() {
        DoorKey[] retArray = new DoorKey[4];
        for(int i = 0; i < 4; i++) {
         
    retArray[i] = new DoorKey(i, true, myKeys[i]);
        }
        return(retArray);
     
    }
      //-------------------------------------------------------  // decoding utilities
      /**
       
    * Takes adungeon given as a byte array and uses it
       
    * to set the tiles of atiled layer.
        *
       
    * The TiledLayer in this case is a16x16 grid
          * in which each square can be either blank
       
    * (value of 0) or can be filled with a stone block
       
    * (value of 1). Therefore each square requires only 
        * one bit of information. Each byte of data in
       
    * the array called "data" records the frame indices
        * of eight squares in the grid.
        */
     
    private static void decodeDungeon(byte[] data, TiledLayer dungeon,
            int offset) throws Exception {
        if(data.length + offset < 32) {
          throw(new Exception(
                    "BoardDecoder.decodeDungeon-->not enough data!!!"));
          }
          // a frame index of zero indicates a blank square
          // (this is always true in a TiledLayer).
          // This TiledLayer has only one possible (nonblank)
          // frame, so a frame index of 1 indicates a stone block
          int frame = 0;
          // Each of the 32 bytes in the data array records
          // the frame indices of eight block in the 16x16
          // grid. Two bytes give one row of the dungeon,
          // so you have the array index go from zero to 16
          // to set the frame indices for each of the 16       
    rows.
          for(int i = 0; i < 16; i++) {
         
    // The flag allows you to look at each bit individually
          // to determine if it is one or zero. The number 128
          // corresponds to the highest bit of a byte, so you
          // start with that one.
          int flag = 128;
          // Here you check two bytes at the same time
          // (the two bytes together correspond to one row
          // of the dungeon). You use a loop that checks
          // the bytes bit by bit by performing a bitwise
          // and (&) between the data byte and a flag:
          for(int j = 0; j < 8; j++) {
           
    if((data[offset + 2*i] & flag) != 0) {
              frame = 1;
            } else {
             
    frame = 0;
            } dungeon.setCell(j, i, frame);
            if((data[offset + 2*i + 1] & flag) != 0) {
             
    frame = 1;
            } else {
             
    frame = 0;
            }
            dungeon.setCell(j + 8, i, frame);
            // move the flag down one bit so you can
            // check the next bit of data on the next pass
            // through the loop:
            flag = flag >> 1;
         
    }
        }
      }

    }

    In case you’re wondering where the byte arrays in the previous class came from, Listing 5-6 shows the utility class I used to encode them. Keep in mind that this class is merely a tool I used to create the data for the game. Once the data has been created, this class is no longer used. It would certainly not be distributed to users with the game. Listing 5-6 shows EncodingUtils.java.

    Listing 5-6. EncodingUtils.java

      package net.frog_parrot.dungeon;
     
    import net.frog_parrot.util.DataConverter;
      /**
        * This class contains the data for the map of the dungeon.
       
    * This is autility class that allows a developer to write
       
    * the data for aboard in a simple format, then this class
       
    * encodes the data in aformat that the game can use.
        * 
       
    * note that the data that this class encodes is hard-coded.
       
    * that is because this class is intended to be used only a
       
    * few times to encode the data. Once the board data has been
       
    * encoded, it never needs to be encoded again. The encoding
       
    * methods used in this class could be generalized to be used
       
    * to create aboard editor that would allow a user to easily
       
    * create new boards, but that is an exercise for another day...
        *
       
    * @author Carol Hamer
       
    *
       public class EncodingUtils {
       
    //-----------------------------------------------------    // fields
      /**
       
    * data for which squares are filled and which are blank.
        * 0 = empty
        * 1 = filled
        */ 
      private int[][] mySquares = {
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 },
        { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1 },
        { 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1 },
        { 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1 },
        { 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
       
    { 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1 },
       
    { 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 },
       
    { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1 },
       
    { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
       
    { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1 },
       
    { 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 },
       
    { 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1 },
       
    { 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1 },
       
    { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
       
    { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
      };
      /**
       
    * The coordinates of where the player starts on the map
        * in terms of the array indices.
       
    */
      private int[] myPlayerSquare = { 7, 10 };
     
    /**
       
    * The coordinates of the goal (crown).
       
    */
      private int[] myGoalSquare = { 5, 10 };
      //-------------------------------------------------------
      // get/set data
     
    /**
        * Creates the array of door sprites. (call this only once to avoid
       
    * creating redundant sprites).
        */
      int[][] getDoorCoords() {
        int[][] retArray = new int[8][];
       
    for(int i = 0; i < retArray.length; i++) {
          
    retArray[i] = new int[2];
        }
        // red
        retArray[0][0] = 12;
        retArray[0][1] = 5;
        retArray[1][0] = 14;
        retArray[1][1] = 3;
        // green
        retArray[2][0] = 3;
        retArray[2][1] = 8;
       
    retArray[3][0] = 12;
       
    retArray[3][1] = 9;
       
    // blue
       
    retArray[4][0] = 6;
       
    retArray[4][1] = 2;
       
    retArray[5][0] = 7;
       
    retArray[5][1] = 14;
       
    // yellow
       
    retArray[6][0] = 11;
       
    retArray[6][1] = 1;
       
    retArray[7][0] = 3;
       
    retArray[7][1] = 13;
       
    return(retArray);
     
    }
     
    /** 
        * Creates the array of key sprites. (call this only once to avoid
       
    * creating redundant sprites.)
        */
     
    int[][] getKeyCoords() {
        
    int[][] retArray = new int[4][];
       
    for(int i = 0; i < retArray.length; i++) {
         
    retArray[i] = new int[2];
        }
        // red
        retArray[0][0] = 12;
        retArray[0][1] = 2;
        // green
        retArray[1][0] = 2;
        retArray[1][1] = 2;
        // blue
        retArray[2][0] = 13;
        retArray[2][1] = 5;
        // yellow
        retArray[3][0] = 4;
        retArray[3][1] = 8;
        return(retArray);
     
    }
     
    //-------------------------------------------------------  // encoding / decoding utilities
      /**
       
    * Encodes the entire dungeon.
        */
     
    byte[][] encodeDungeon() {
        byte[][] retArray = new byte[2][];
        retArray[0] = new byte[16];
        // the first byte is the version number:
        retArray[0][0] = 0;
        // the second byte is the board number:
        retArray[0][1] = 0;
        // the player's start square:
        retArray[0][2] = DataConverter.encodeCoords(myPlayerSquare);
        // the goal (crown) square:
        retArray[0][3] = DataConverter.encodeCoords(myGoalSquare);
        //encode the keys:
        int[][] keyCoords = getKeyCoords();
        for(int i = 0; i < keyCoords.length; i++) {
         
    retArray[0][i + 4] = DataConverter.encodeCoords(keyCoords[i]);
        }
        //encode the doors:
        int[][] doorCoords = getDoorCoords();
        for(int i = 0; i < doorCoords.length; i++) {
         
    retArray[0][i + 8] = DataConverter.encodeCoords(doorCoords[i]);
        }
        //encode the maze:
        try {
         
    retArray[1] = encodeDungeon(mySquares);
        } catch(Exception e) {
         
    e.printStackTrace();
        } return(retArray);
     
    }
      /**
        * Takes adungeon given in terms of an array of ones and zeros
       
    * and turns it into an array of bytes.
          * WARNING: the array MUST BE 16x16.
        */
      static byte[] encodeDungeon(int[][] dungeonMap) throws Exception {
        if((dungeonMap.length != 16) || (dungeonMap[0].length != 16)) { 
          throw(new Exception("EncodingUtils.encodeDungeon-->must be 16x16!!!"));
        }
        byte[] retArray = new byte[32];
        for(int i = 0; i < 16; i++) {
          retArray[2*i] = DataConverter.encode8(dungeonMap[i], 0);
          
    retArray[2*i + 1] = DataConverter.encode8(dungeonMap[i], 8);
        }
        return(retArray);
      }
      //-------------------------------------------------------  // main prints the bytes to standard out.
      // (note that this class is not intended to be run as a MIDlet)
     
    /**
       
    * Prints the byte version of the board to standard out.     */
      public static void main(String[] args) {
       
    try {
          EncodingUtils map = new EncodingUtils();
          byte[][] data = map.encodeDungeon();  
          System.out.println("EncodingUtils.main-->dungeon encoded");
          System.out.print("{\n  " + data[0][0]);
          for(int i = 1; i < data[0].length; i++) {
           
    System.out.print(", " + data[0][i]);
          }
          for(int i = 1; i < data[1].length; i++) {
           
    System.out.print(", " + data[1][i]);
          }
          System.out.println("\n};");
       
    } catch(Exception e) {
          e.printStackTrace();
        }
      }

    }

    More Java Articles
    More By Apress Publishing


     

    Buy this book now. This article is taken from chapter five of the book J2ME Games with MIDP2, written by Carol Hamer (Apress, 2004; ISBN: 1590593820). Check it out at your favorite bookstore. Buy this book now.

    JAVA ARTICLES

    - Deploying Multiple Java Applets as One
    - Deploying Java Applets
    - Understanding Deployment Frameworks
    - Database Programming in Java Using JDBC
    - Extension Interfaces and SAX
    - Entities, Handlers and SAX
    - Advanced SAX
    - Conversions and Java Print Streams
    - Formatters and Java Print Streams
    - Java Print Streams
    - Wildcards, Arrays, and Generics in Java
    - Wildcards and Generic Methods in Java
    - Finishing the Project: Java Web Development ...
    - Generics and Limitations in Java
    - Getting Started with Java Web Development in...






    © 2003-2008 by Developer Shed. All rights reserved. DS Cluster 6 hosted by Hostway
    Stay green...Green IT