Java-Gaming.org Hi !
Featured games (81)
games approved by the League of Dukes
Games in Showcase (513)
Games in Android Showcase (119)
games submitted by our members
Games in WIP (575)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Savegames - how to?  (Read 3153 times)
0 Members and 1 Guest are viewing this topic.
Offline Evil-Devil

Senior Duke


Medals: 2


Fir Tree Master


« Posted 2004-09-19 13:19:30 »

Hey, I have a small game with an isometric map and I would like to save it in a file. But how can i do this?
I tried it with "toString()", but then I can't resolved it back to an int array. Any ideas how to solve the problem without using xml. Would be a very large xml file, if I do so.
Offline Malohkan

Senior Duke




while (true) System.out.println("WOO!!!!");


« Reply #1 - Posted 2004-09-19 14:11:01 »

I compress my save data using the Deflater/Inflater classes:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
      protected String compressed(String string) {
            byte[] data = deflaterCompressed(string);
            
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < data.length; i++) {
                  String toAdd = Integer.toString(data[i] - Byte.MIN_VALUE, Character.MAX_RADIX);
                  if (toAdd.length() == 1)
                        sb.append('0');
                  sb.append(toAdd);
            }
            return sb.toString();
      }
      
      protected String decompressed(String string) {
            try {
                  byte[] newData = new byte[string.length()/2];
                  for (int i = 0; i < string.length() - 1; i += 2) {
                        newData[i/2] = (byte)(Integer.parseInt(string.substring(i, i+2), Character.MAX_RADIX) + Byte.MIN_VALUE);
                  }
                  
                  return inflaterDecompressed(newData);
            }
            catch (Exception e) {
                  if (DEBUG)
                        System.out.println("decompression failed, returning origional");
                  return string;
            }
                  
      }
      
      private byte[] deflaterCompressed(String string) {
            byte[] input = string.getBytes();
          
          // Create the compressor with highest level of compression
          Deflater compressor = new Deflater();
          compressor.setLevel(Deflater.BEST_COMPRESSION);
          
          // Give the compressor the data to compress
          compressor.setInput(input);
          compressor.finish();
                    
          // Create an expandable byte array to hold the compressed data.
          // You cannot use an array that's the same size as the orginal because
          // there is no guarantee that the compressed data will be smaller than
          // the uncompressed data.
          ByteArrayOutputStream bos = new ByteArrayOutputStream(input.length);
          
          // Compress the data
          byte[] buf = new byte[1024];
          while (!compressor.finished()) {
              int count = compressor.deflate(buf);
              bos.write(buf, 0, count);
          }
          try {
                bos.close();
          } catch (IOException e) {
          }
    
          // Return the compressed data
          return bos.toByteArray();
      }
      
      private String inflaterDecompressed(byte[] data) throws DataFormatException {
            // Create the decompressor and give it the data to compress
          Inflater decompressor = new Inflater();
          decompressor.setInput(data);
          
          // Create an expandable byte array to hold the decompressed data
          ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);
          
          // Decompress the data
          byte[] buf = new byte[1024];
          int count = -1;
          while (!decompressor.finished() && count != 0) {
                count = decompressor.inflate(buf);
              bos.write(buf, 0, count);
          }
          try {
              bos.close();
          } catch (IOException e) {
          }
          
          // Get the decompressed data
          return new String(bos.toByteArray());
      }


The shifting you'll see there with the adding '0' to the String sometimes is so that I can save the byte data in a String without losing data.  If you plan on saving to a file, you can write it straight as bytes and save a little bit of extra space.  Try that out and see how it helps!

By the way, much of that code was thanks to www.javaalmanac.com

So essentially you can keep your XML structure, and just in one block have <Map>blah blah blah</Map> with all the compressed data inbetween.  It should help a lot!

However, there might be other ways to manage it.  For example, how are you creating the map?  If you create a new Random() object and just crunch out numbers and you want to save the whole map set up you just randomly generated, instead you should keep track of the seed:
1  
2  
3  
4  
5  
6  
Random rando = new Random();
long genKey = rando.nextLong();
rando = new Random(genKey);

generateMap(rando);
loadGame();

When you go to save your game, just save genKey, and you can call rando = new Random(genKey) later and get the same resulting map.

Admin and Game Developer at
GameLizard.com
Play Rimscape!    |    Play Conquer!
Offline gangrel-br

Junior Duke




Java and Scala! Thats the game =)


« Reply #2 - Posted 2004-09-19 14:45:04 »

GameDev.net has some articles on datafile format  Grin

Paulo "JCranky" Siqueira
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Evil-Devil

Senior Duke


Medals: 2


Fir Tree Master


« Reply #3 - Posted 2004-09-19 15:47:23 »

The maps might be created with a map editor or just random.  But i have to save the informationen. No one can play the whole game in one day, when it is finished Wink
Offline Malohkan

Senior Duke




while (true) System.out.println("WOO!!!!");


« Reply #4 - Posted 2004-09-19 16:17:39 »

If they're made at random, save the generation seed.  If they're made with a map editor, you could try saving the info as a gif.  I've heard of that idea once.  You have a .gif with the dimensions of your map, each pixel representing a tile, have a different color for each type.  That'd be easy to save compressed because you'd let gif do the work there.  Or you could use .png and tack on some of the PNGCrush functionality to compress them as much as you can.

At any rate, however you save, you can use that zipping code to compress what you have.

Admin and Game Developer at
GameLizard.com
Play Rimscape!    |    Play Conquer!
Offline Evil-Devil

Senior Duke


Medals: 2


Fir Tree Master


« Reply #5 - Posted 2004-09-19 16:38:40 »

Sounds nice. BUt how to save the other relevant data? like items that are placed on my tiles?
Offline Malohkan

Senior Duke




while (true) System.out.println("WOO!!!!");


« Reply #6 - Posted 2004-09-19 19:09:44 »

well the layout can go in the png, whereas the rest of the stuff could be in xml format, then compressed.

Admin and Game Developer at
GameLizard.com
Play Rimscape!    |    Play Conquer!
Offline Evil-Devil

Senior Duke


Medals: 2


Fir Tree Master


« Reply #7 - Posted 2004-09-19 20:25:08 »

Ok, i will give it a try. For the moment I did it with DataInputStream and DataOutputStream. The user don't know what the values are for and i have the data saved Wink

Maybe I will try a combine of DOS/DIS and the gif/png/xml stuff.
Offline DrBizzar0

Junior Duke




Raj raj!


« Reply #8 - Posted 2004-09-20 06:26:14 »

I think the absolutly simplest way to save game data is to use the XMLEncoder and XMLDecoder classes. It is no work at all. All you need to do is to make your data classes Java Bean compatible, which as you may know, in this case means your data classes only have to provide an empty costructor and get/set methods for all your variables.

My experience is that it's fast and creates small data files.

A quick example
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
 public void saveBeanToDisc(String url,Object o){
  try{
   XMLEncoder e = new XMLEncoder(
       new BufferedOutputStream(
       new FileOutputStream(url)));
 
   e.writeObject(o);
   e.close();
  }catch(FileNotFoundException ex){
 
  }
 }
 
public Object loadBeanFromDisc(String url){
 
  try{
   XMLDecoder e = new XMLDecoder(
    new BufferedInputStream(
    new FileInputStream(url)));
 
   Object o = e.readObject();
      e.close();
   return o;
  }catch(FileNotFoundException ex){
 
  }
 
  return null;
 
 }
Offline Evil-Devil

Senior Duke


Medals: 2


Fir Tree Master


« Reply #9 - Posted 2004-09-20 08:42:01 »

That won't be save against cheaters.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline CaptainJester

JGO Knight


Medals: 12
Projects: 2
Exp: 14 years


Make it work; make it better.


« Reply #10 - Posted 2004-09-20 08:53:11 »

Or you could combine XML with the built in zip library.  Then when you create your zip file, just don't use a zip extension.  That will deter most people from cheating.

Offline Malohkan

Senior Duke




while (true) System.out.println("WOO!!!!");


« Reply #11 - Posted 2004-09-20 09:55:49 »

right, you could use my Zip code I just gave you, and write it to anything you want.  In your save file, if they open it, they'll find crap.  Since the zip code above is nothing standard because of the shifts to make it work in String form, it's highly unlikely they'd ever make a "guess" to decode it.  If they do, they'll see, <gamedata>moreZippedCrap</gamedata> and they'll have to deal with that too Smiley

Admin and Game Developer at
GameLizard.com
Play Rimscape!    |    Play Conquer!
Offline Evil-Devil

Senior Duke


Medals: 2


Fir Tree Master


« Reply #12 - Posted 2004-09-20 12:07:23 »

Can you explain me the usage of the MAX_RADIX constant?
I did a search on google and find out that it defines the base for the given system. Like decimal -> Radix: 10

But I don't understand the contex with it in your deflater/inflater example Sad
Offline Malohkan

Senior Duke




while (true) System.out.println("WOO!!!!");


« Reply #13 - Posted 2004-09-20 18:19:10 »

You're right, radix is the base, and can also be thought of as a descriptor for the method of converting Bytes to numbers and letters.  The higher the radix, the more letters will be included in the conversion, so that the max radix will enable you to store a byte in 1 or 2 characters.  Converting with a radix of 10 instead of MAX_RADIX will result in a MUCH longer String of data.  So say you set the radix to be 16, that would mean the byte would be converted into hexadecimal format.  I set it to be the maximum possible radix so that the compression of space would be the highest.  If the language ever somehow supports a higher radix, that code will compress even further

Admin and Game Developer at
GameLizard.com
Play Rimscape!    |    Play Conquer!
Offline Evil-Devil

Senior Duke


Medals: 2


Fir Tree Master


« Reply #14 - Posted 2004-09-21 09:47:44 »

Ah, thx :)

Is this code ok, or does there is a better way to compare the pixel color with a specific value? My image load code:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
// loads a map from a given map file
public void load(String map) {
    File mapFile = new File(map);
    BufferedImage mapImage = null;
       
    // try to read the map file
    try {
        mapImage = ImageIO.read(mapFile);
    } catch (IOException ioe) {
        System.err.println("error while loading map\n\n"+ioe);
        // create a random map :P
        init(true);            
    }
       
    // if we loaded our image, get the data and move on :)
    if (mapImage != null) {
        int bandNum = mapImage.getRaster().getNumBands();
        int pixelSample[] = new int[bandNum];
        int baseTile = 0;
        Color color;            
        // reassign xTiles and yTiles
        xTiles = mapImage.getWidth();
        yTiles = mapImage.getHeight();
        // init the new map
        init(false);
        // populate our map with the image pixel data
        for (int i=0; i<xTiles; i++) {
            for (int j=0; j<yTiles; j++) {
                // get the pixel sample from the current position
                mapImage.getRaster().getPixel(i,j,pixelSample);
                color = new Color(pixelSample[0],pixelSample[1],pixelSample[2]);
                if (color.equals(Color.GREEN))
                    baseTile = 0;
                else if (color.equals(Color.ORANGE))
                    baseTile = 1;
                else if (color.equals(Color.GRAY))
                    baseTile = 2;
                else if (color.equals(Color.BLUE))
                    baseTile = 3;
                // assign the basetile
                    fields[i][j][1] = baseTile;                                      
            }
        }
    }
}

the code tag is mad, it destroys my syntax : /
Offline MBrenaman

Junior Duke




Javanaut


« Reply #15 - Posted 2004-09-22 06:45:11 »

This seems kinda strange to me but no one metioned Serialization? Is it that bad?  Huh I use it.

-Mathew Brenaman
Offline Malohkan

Senior Duke




while (true) System.out.println("WOO!!!!");


« Reply #16 - Posted 2004-09-22 11:15:18 »

If you make a code change, old save files become unusable.  Since I change code daily, that'd be real bad Wink

Admin and Game Developer at
GameLizard.com
Play Rimscape!    |    Play Conquer!
Offline Evil-Devil

Senior Duke


Medals: 2


Fir Tree Master


« Reply #17 - Posted 2004-09-22 11:24:46 »

My question hasn't been answered yet Sad

Is there any better way to obtain the color and comparing?
Offline dranonymous

Junior Duke




Hoping to become a Java Titan someday!


« Reply #18 - Posted 2004-09-22 11:41:28 »

EvilD -

It appears your code should work.  Have you tried it?

I might recommend doing something similiar, but using less memory.  Just write out a binary file that maps to your tiles.  Make byte 0 be the width, byte 1, be the height and the rest of the file the tiles to use.  It would take potentially much less file space, unless the image is using indexed color, where it would then be a wash.

For a 3x4 map, you would have 2 + 3 * 4 bytes = 14 bytes for the map.  You would have 256 differrent types of tiles using that format.

You could also use ints for the format, then you could mask the bytes to determine different things.  Bytes one and two could hold state info such as: treasure here, trap, hidden/secret area, etc.  The third byte could give you an index into a graphic to use for the floor or whatever.  The fourth byte would be your base tile info.

HTH,
Dr. A>
Offline MBrenaman

Junior Duke




Javanaut


« Reply #19 - Posted 2004-09-22 12:16:13 »

@Malohkan

If you want to keep versions of a serialized class compatible then override

1  
private static final long serialVersionUID = 1234567L


With your own version number and take care of the new vars, or any other changes in your class yourself.

I was just suggesting it beacuse it sounded like he wanted to save more then a 2D map. But I do like the idea of saving it in a gif  Grin

-Mathew Brenaman
Offline Evil-Devil

Senior Duke


Medals: 2


Fir Tree Master


« Reply #20 - Posted 2004-09-22 13:08:41 »

@dranonymous:
Yes my image load code works. And thanks for the idea with the binary file. But I am not that familar with retrieving byte informations from a file and convert them to their needed data types.

I took a look at the DataInput/OutputStream example in the java tutorial, but that wasn't that good. I got the informations stored, but retrieving failed in some manners.

Can you give a piece of example code? Please.

Evil
Offline dranonymous

Junior Duke




Hoping to become a Java Titan someday!


« Reply #21 - Posted 2004-10-12 18:06:07 »

ED - Sorry about not getting back to you.  I forgot about this thread until today when someone asked about XML serialization.

To easily serialize out your game state I'd look here -

xStream

It works really well.

As for the example about storing your map as a binary mapped to bytes or ints, I'll see what I can work up.

Again, sorry for the delay!

Dr. A>
Offline Evil-Devil

Senior Duke


Medals: 2


Fir Tree Master


« Reply #22 - Posted 2004-10-15 18:46:18 »

Thx for replay.
I got a workaround running, but have some problems left.
My mapsize is an integer value, and iam not sure if i should save it with writeInt() or with writeByte(). I hope that there is no big deal with those to functions and i can use them to avoid dataloss from converting int to byte.

So i did my mapfileformat.
I saved the mapnames characters each as byte in the file, but the name stands there in plaintext when i open the file. Is there a way to avoid this?

questions over questions Wink
Offline dranonymous

Junior Duke




Hoping to become a Java Titan someday!


« Reply #23 - Posted 2004-10-18 17:37:01 »

Since you changed your image, I cna't tell its you.  Smiley

You could take each byte of the map name and do a bit shift on it. Something like -

1  
2  
3  
4  
5  
6  
byte newByte = 0;

newByte = originalByte << 1;

if(originalByte > 128)  // This wraps the top bit to the beginning
     newByte += 1;


Then just write out newByte.

To 'decode' the bytes do this -
1  
2  
3  
4  
5  
6  
byte originalByte;

originalByte = newByte >>> 1;

if(originalByte & (byte)0x01 == 1) // Adds the top bit back on
     originalByte = originalByte | (byte)(0x80);


Does that make sense?

Dr. A>
Offline Evil-Devil

Senior Duke


Medals: 2


Fir Tree Master


« Reply #24 - Posted 2004-10-19 14:44:07 »

Yea its still me. I just changed my avatar to the one i use in most forums. My rave pant ^^

@code: Sounds fine. I just shift the bit and a textedit won't display the mapname anyway Smiley

Thx.

But what about my integer values? Can i store them as byte too? Or does i have to use writeInt()?
Offline dranonymous

Junior Duke




Hoping to become a Java Titan someday!


« Reply #25 - Posted 2004-10-20 06:29:35 »

Well, it depends.  This might be a bit confusing, unless you a comfortable with number formats.

If you ints don't go above 255, then you can store them as bytes.  To store them just cast the int to a byte.  Reading them back in won't be so straightforward.  If the original number was greater than 127, you'll need to mask off the top 24 bits, to remove the sign change that will occur.  You can do this by -

1  
int realInt = myByte & 0xff00;


On the other hand, if your ints are greater than 255, you're 'stuck' and have to write out 4 bytes per int.  The only way around that would be to test for how large your numbers are and see if they will fit into a 2 byte short.

Dr. A>
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Longarmx (35 views)
2014-10-17 03:59:02

Norakomi (26 views)
2014-10-16 15:22:06

Norakomi (24 views)
2014-10-16 15:20:20

lcass (26 views)
2014-10-15 16:18:58

TehJavaDev (50 views)
2014-10-14 00:39:48

TehJavaDev (52 views)
2014-10-14 00:35:47

TehJavaDev (40 views)
2014-10-14 00:32:37

BurntPizza (63 views)
2014-10-11 23:24:42

BurntPizza (36 views)
2014-10-11 23:10:45

BurntPizza (76 views)
2014-10-11 22:30:10
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!