Create Custom Binary File Formats for Your Game's Data

Your game has data - sprites, sound effects, music, text - and you need to store it somehow. Sometimes you can encapsulate everything into a single SWF, .unity3d or EXE file, but in some cases that won't be suitable. In this technical tutorial, we'll look at using custom binary files for this purpose.

Note: This tutorial assumes you have a basic understanding of bits and bytes. Check out An Introduction to Binary, Hexadecimal, and More and Understanding Bitwise Operators on Activetuts+ if you need to revise!


 

There are a few pros and cons to using custom binary file formats.

Creating something like a resource container (as this tutorial will do) will reduce disk/server thrashing and will typically make resource loading a lot easier because multiple files will not need to be loaded. Custom file formats can also add an extra layer of security in the form of obfuscation to game resources.

On the flip side you will need to actually generate the custom files one way or another before you can use them in a game, but that is not as difficult as it might sound -- especially if you or someone you know can create something like a JAR file that can be dropped into a build process with relative ease.


 

Before you can begin to design your own binary file formats you will need an understanding of the primitive data types (building blocks) that are available to you. The number of primitive data types is actually limitless but there is a common set that most programmers are familiar with and use, and these data types typically represent multiples of 8 bits.

As you can see, these primitive data types provide a wide range of integer values and you will find them at the core of most binary file specifications. There are a few more primitive data types, such as floating point numbers, but the integer data types listed above are more than adequate for this introduction and for most binary file formats.


 

Structured data types (or complex data types) represent specific elements (chunks) of a binary file, and they consist of primitive data types or other structured data types.

You can think of structured data types as objects or class instances in a programming language, with each object declaring a set of properties. Structured data types can be visualised using simple object notation.

Here is an example of a fictitious file header:

So here the structured data type is named HEADER and it has three properties labeled signature, version and length. Each property in this example is declared as a primitive data type but properties can also be declared as structured data types.

If you are a programmer you are probably beginning to realise how easy it would be to represent a binary file in an OOP based programming language; let's take a quick look at how this HEADER data type could be represented in Java:


 

At this point you should be familiar with the basics of binary file structures, so now is the time to take a look at the process of designing a working custom file format. This file format will be designed to hold a collection of game resources including images and sounds.

The first thing that should be designed is a data structure for the file header so the file can be identified before the remainder of the file is loaded into memory. Ideally the file header should at least contain a signature field and a version field:

The file signature you choose to use is up to you: it can be any number of bytes, but most file formats have a human-readable signature containing three or four ASCII characters. For my purposes, the signature field will hold the character codes of three ASCII characters (one byte per character) and will represent the string "RES" (short for "RESOURCE"), so the byte values will be 0x52, 0x45 and 0x53.

The version field will initially be 0x01 because this is Version 1 of the file format.

The resource file itself is actually a structured data type which contains a header and will later contain other elements. It currently looks like this:

The next thing will we take a look at is the data structure for images.

The resource file will store an array of ARGB colour values (one per pixel) and allow that data to be optionally compressed using the ZLIB algorithm. The image dimensions will also need to be included in the file along with an identifier for the image (so the image can be accessed after it has been loaded into memory):

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

There are a couple of things in that structure that need your attention; the first is the U8[dataLength] part of the structure and the second is the STRING data structure used for the id, which was not defined in the table of data types above.

The former is basic array notation -- it simply means that dataLength number of U8 values need to be read from the file. The data field contains the image pixels, and the compressed field indicates whether the the data field is compressed. If the compressed value is 0x01 then the data field is ZLIB compressed, otherwise the file decoder can assume the data field is not compressed. The benefit of using ZLIB compression here is the IMAGE file structure will end up being a similar size to a PNG encoded version of the image.

The STRING data structure is as follows:

For this file format all strings will be encoded as UTF-8 and the bytes of the encoded string will be located in the data field of the STRING data structure. The dataLength field indicates the number of bytes in the data field.

The resource file structure now looks like this:

As you can see the file now contains a header, a new imageCount field that indicates the number of images in the file, and a new imageList field for the images. This in itself would be a useful file format to store multiple images, but it would be even more useful if it held multiple resource types, so will will now take a look at adding sounds to the file.

Sounds will be stored in the file in a similar way to images, but instead of storing raw pixel colour values the file will store raw sound samples in varying bit resolutions:

Oh my goodness, conditional statements! Because the dataFormat field indicates the bit rate of the sound, the format of the data field needs to be variable, and that is where the simple and programmer friendly conditional statement syntax comes into play.

Looking at the data structure you can easily see which format the data field values (sound samples) will be using, given a specific dataFormat value. When adding fields like dataFormat to a data structure the values those fields can contain is entirely up to you. The values 0x01, 0x02 and 0x03 are being used in this example simply because they are the first unused values available in the byte.

The resource file structure now looks like this:

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수

등록된 글이 없습니다.

대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED