Tutorial 2: Creating your First Game

From Uzebox Wiki
Jump to navigation Jump to search

Getting your Development Environment ready:

Installing and configuring The GIMP

The Uzebox has a specific color palette that you will need to use so that the images that you create are displayed correctly on the Uzebox. You’ll need a new color palette file and the GIMP. The GIMP allows you to save an image in the PNG-8 format. Gconvert requires either raw 8ppp or PNG-8. You can create or paste an image into the GIMP and use the color palette to match your image to the Uzebox colors. Here is how to set up the color palette using the GIMP:

Steps:

  1. First, download the the uzebox_algorithmic.hex file from: http://uzebox.org/forums/download/file.php?id=582 .
  2. You will need to rename the file to uzebox.gpl.
  3. Next, go to your GIMP directory (example: C:\Program Files\GIMP 2\share\gimp\2.0\palettes).
  4. You will need to give yourself write permissions (or just full control) to the palette directory first.
    1. Just go up one directory then right-click on ‘palettes’, click properties, click security, click edit then click add.
    2. Type your username into the box and click check names. Your full username should appear. Now click ok.
    3. With your name selected click the checkbox for allow for full control and then click ok and then ok again.
  5. Now you can copy the file into the palette directory.
  6. To use this palette, in GIMP click image > Mode > Indexed.
  7. Click use custom palette.
  8. Click on the entry for Uzebox.
  9. Ensure that you uncheck Remove unused colors from colormap.
  10. To save an image file:
    1. When you are done with your image editing (or have copy and pasted the image from another editor) save it by clicking File > Export As.
    2. At the lower-left click Select File_Type (By Extension) and choose PNG image.
    3. Click Export. Leave the default options and then click Export.
    4. This file should now be convertible by gconvert.

Install WinAVR

WinAVR does not need any special configuration. Once it is installed, its command line programs can be called from any other directories. WinAVR comes with the tools that will compile your Uzebox program.

Unzip the dev trunk

Image of how your folders are to be laid out.

You will put your code into this folder. I would suggest that you use an automatic backup program for your program code. I use Dropbox. Feel free to use this referral ID as it gives us both additional space. https://db.tt/1KpIzFb . Believe me, if you lose your code suddenly and don’t have a backup, you will regret it. If you don’t use Dropbox then make sure you have some sort of backup method. Losing all your stuff is a bad feeling.

Unzip the dev trunk folder

  • Unzip the dev trunk folder. Inside will be several directories.
    • The bin directory has the Uzebox utilities such as gconvert, and the Uzem Uzebox emulator.
    • The demos directory has the source code and graphics for many games and demos. You can learn a lot by studying the code here.
    • Gfx has font graphics and a few other miscellaneous graphics.
    • The kernel directory is very important and is heart of the Uzebox. Contained here is the code that consists of the Uzebox environment and also the code for the video modes. If you know assembly and don’t mind getting your hands really dirty then great. However, if you have no idea what I just said then stay away from that directory. Just remember that it is important.
    • The roms directory has some pre-compiled games that you can try out with the Uzem emulator.

My suggestion is to create a “MY_GAMES” folder and put your code there. Each folder inside of “MY_GAMES” would be the name of a different game or experiment separate from other code. You will be making one called “demoprogram” for this tutorial. Go ahead and make that folder now.

Recap: Unzip the dev trunk, create a folder inside called "MY_GAMES", and inside of that create a "demoprogram" folder.

Download Notepad++

Get Notepad++: http://notepad-plus-plus.org/ We will be using this program to write our code. AVR Studio and Eclipse can also be used but this guide assumes Notepad++. Notepad++ does code keyword highlighting for many languages and you can open up files into separate tabs. There are many good features of this program if you would like to explore.

Setup the folders for your work environment

Inside of the MY_GAMES\demoprogram folder you will need a couple of files. The demoprogram directory will soon contain the game’s C program (demoprogram.c) and gameinfo.properties which has the game title, author, and other miscellaneous info.

Create a directory called “data”, and directory called “default”. The data directory will contain data for your game such as tile sheets, the gconvert convert.xml file and anything else media-related. The default directory for now will only contain a Makefile (created later in this tutorial). When the program is compiled, the resulting .hex file will be in this directory too. A complete Makefile will be provided in this tutorial.

Creating your first ‘game’

Creating and preparing graphics

Graphics are what the player will see on the screen. The player might be controlling a character that runs through a level collecting coins and going through many different areas. Remember, the Uzebox doesn’t know what a game is. Really, all it does is display graphics and control those graphics based on the programming logic of your game. You must create these graphics and the control logic. We first need to create a tileset and some maps from that tileset.

Creating a tileset

The video mode that you choose will determine what the size of your tiles will be as well as things such as the ability to scroll the screen and how much you can put on the screen. This tutorial assumes video mode 3. Let’s create a few overworld screens from The Legend of Zelda from the NES. We can use this tile sheet image to create our tile sheet. Fortunately, the NES color palette is similar enough to the Uzebox color palette so don’t worry about that now.

Creating maps from the tileset

You’ll notice that the tile sheet has gray grid lines and that each of these squares are a 16x16 pixel image. Our tiles will need to be made of 8x8 pixel image. Keeping them together is not a bad idea. However, these grid lines need to be removed. I suggest that you copy and paste each 16x16 square into a new image. This way we will only put the tiles that we need in our tile sheet. It is okay for the images to be touching (directly touching another image) as long as they all line up on 8x8 boundaries (or 16x16 for simplicity.) Take the black square, the solid beige square, and the green rocks. We should be able to recreate the first screen from the over-world with these tiles. These tiles were created by someone else and a Google Images search can yield tilesheets (or spritesheets.) However, you can get tiles from screenshots taken from an emulator.

We will only focus on the main screen for now and not the top screen section. Just fill that part in with the black square. In your image editing software, use the tiles that you copied and recreate the above screen using only those tiles. It took me about 15 minutes and I used MS Paint to do it. Pressing CTRL+G will turn on the grid lines which can help you to line up the parts of your image.

The standard display resolution of the NES is 256 horizontal pixels by 240 vertical pixels. However, the Uzebox in video mode 3 only allows for 240x224 with scrolling or 224x224 without scrolling. You will need to adjust your map as you cannot 100% clone the maps of this game due to this limitation. You can change it to look like however you would like though. Let’s remove two 16x16 squares on the width and one 16x16 square on the height. Go ahead and make it look like this picture. The top black section should be three squares high. Remove two columns of squares from the middle of the right side of the screen. This image should now be 224x224.

Original and converted maps.

Okay, good work! You have created a large map using only 8 tiles. Right now you have a map and we are about to add the hero that the user will control.

Creating sprite maps and tile maps

Sprites for Link in Zelda 1 for NES. These are the tiles that you should currently have in your tilesheet at this point.

Sprites are special tiles or arrangement of tiles that are designed to be moved around the board and overlap other tiles. Tiles need to align any placement or movement on an 8x8 boundary line. Sprites do not have this limitation and can be placed anywhere on the screen with pixel-precision. Let’s now gather the sprites used by the hero.

As before, let’s only grab the images that we need. We will need the 8 images of movement by Link (non-attacking.) Copy these images into the tile sheet that we started earlier. Your tile current tile sheet should look like this image.

We will need to create a map for each position that Link has. This is 8 positions and each position is a 16x16 square. The 16x16 square contains four 8x8 tiles. Each of these four tiles will need to be combined into a map so that each group can be individually addressed by the game.

We can use the gconvert program to create our sprite maps and final tile sheet.

Generating Tiles and Maps with gconvert

http://uzebox.org/wiki/index.php?title=Generating_Tiles_and_Maps_with_gconvert

Gconvert is actually rather easy to use although initially it may appear scary. It will take a raw 8ppp image or PNG-8 image and determine which tiles (8x8 squares) are unique tiles. This will create your tileset. Additionally, gconvert can create your maps too. Draw the map yourself and tell gconvert where each map starts and ends. You may end up with a large graphic but gconvert will reduce it to only the unique tiles to save space in your game.

So, you create your tiles and images in the graphics editor of your choice, convert the image to 8ppp raw or PNG-8, tell gconvert about the maps that you want, and then include the resulting gconvert code into your program code. Let’s do this!

We already have our image of the overworld and we have our tilesheet but they are in separate files. We should combine those files to look something like this image. Notice how the map is still separate? You may also be asking why we are allowing the tiles to be repeated so much. This image is easier to edit. Besides, the job of gconvert is to remove any duplicate tiles anyway. The resulting datafile will be much smaller than the datafile that you feed into gconvert.

You see a full map and you see the maps of your hero characters. Link is a 2x2 collection of 8x8 pixel tiles. The square would be 16x16 pixels. It is simpler to think about a 16x16 square than a 2x2 collection of 8x8 pixel tiles.

Tiles and map drawn with gridlines.

If you aren't already using the GIMP paste your image into it. Then you should configure a 16x16 grid so that you can make sure that your tiles all line up. Click View > Show Grid, Image > Configure Grid. Set the spacing to width 16 and height 16 and click ok. Your tiles need to line up or the graphics will look glitched and the results from gconvert will be much bigger than you want.

The file is XML-based and for our purposes it is kind of like HTML. You’ll need to fill in the input file and type. Tile-width and tile-height should both be 8 for this video mode 3. You’ll need to specify the actual width and height of the input image in pixels ONLY if you are using the raw image format. The output file will be the gconvert converted file of the source image.

  • You can name the tiles whatever you would like.
  • Leave maps pointers at 8.
  • The next two lines are where you create maps that you can reference from your game code.
    • This example creates a link_up1 and a screen1. The link_up1 is for link facing up. You’ll see from the tilesheet that link has 8 walking images with 2 images for each direction.
    • You should create a map link_up2, link_right1, link_right2, link_left1, link_left2, link_down1, and link_down2.

Here is a review on how to do it.

Think of those grid boxes having coordinates. The top-left-most corner would be (0, 0). Going one space down and one space right would be (1, 1) and so on. Keep this image up on your screen and edit the convert.xml file for gconvert. Make your file look like this one:

<?xml version="1.0" ?>
<gfx-xform version="1">
    <input file="untitled.png" type="png" tile-width="8" tile-height="8" />
    <output file="untitled.inc">
        <tiles var-name="uMTiles"/>
        <maps pointers-size="8">
	    <map var-name="link_up1" left="6" top="0" width="2" height="2"/>
	    <map var-name="screen1" left="0" top="5" width="28" height="26"/>
	</maps>	
    </output>
</gfx-xform>

Each of those squares has four 8x8 sections in them. Keep that in mind as you count the squares. Let’s do the link_up2 map. This is 4 squares right and 1 square down. Double those numbers and you have 8 tiles right and 2 tiles down. Copy and paste the link_up1 line and make the necessary changes then lather, rinse, repeat as necessary. This should be the result of those map lines:

Let’s figure out the map for link_up1. Horizontally count each square except the square that you want. You want to count the tiles up to the square that you want. You want the start position. The 4th square has 3 squares to its left, correct? Each of those squares counts for 2 tiles (horizontally). So, you would go ‘left’ a total of 6 tiles (two tiles per square horizontally.) It works similarly for going down. Since link_up1 is on the top row you just leave ‘top’ at 0. However, link_up2 is not on the top row. That one is two tiles down therefore, it would have a top of 2. Try to figure out a few more maps before you look at the answers below.

<?xml version="1.0" ?>
<gfx-xform version="1">
    <input file="untitled.png" type="png" tile-width="8" tile-height="8" />
    <output file="untitled.inc">
        <tiles var-name="uMTiles"/>
        <maps pointers-size="8">
	    <map var-name="link_down1" left="2" top="0" width="2" height="2"/>
		<map var-name="link_down2" left="2" top="2" width="2" height="2"/>
		<map var-name="link_left1" left="4" top="0" width="2" height="2"/>
		<map var-name="link_left2" left="4" top="2" width="2" height="2"/>
		<map var-name="link_up1" left="6" top="0" width="2" height="2"/>
		<map var-name="link_up2" left="6" top="0" width="2" height="2"/>
		<map var-name="link_right1" left="8" top="0" width="2" height="2"/>
		<map var-name="link_right2" left="8" top="2" width="2" height="2"/>
	    <map var-name="screen1" left="0" top="5" width="28" height="26"/>
	</maps>	
    </output>
</gfx-xform>

Great, now you have configured gconvert. It is time to run it. This works from the command prompt. You’ll need to type in the path to gconvert (or cd into it) put a space and convert.xml.

You should copy the bin folder from the dev trunk Google Code and put it in your project folder if you haven’t already.

Gconvert console output.

This image shows the result. Notice the number of unique tiles found? Go back and count them. You’ll see lots of white squares at the top and a black square. Those will be reduced. 16 squares which each have 4 tiles in them equals 64 tiles. Add a tile for the black and white and you have a total of 66. The gconvert output shows 52 unique tiles? Some of the other tiles must have been the same so they were canceled out as well. This is good news. You have a limit of around 256 tiles and 52 is better than 66, right? We have graphics now we need to do something with them. Let’s write some code and test it out on the Uzebox Uzem emulator!

Displaying your graphics on the screen

Short Intro to Code

Before Bowser steals the princess or the Triforce of Wisdom is split up someone had to create the world. This will be the first thing that we do. We are going to put things on the screen and be introducing the functions that allow this to happen.

C is one of the best known and widely used languages. It has lots of support. Finding resources for learning it shouldn’t be hard and I will provide a few to you. This part will serve as an Uzebox-themed crash course. I currently am not using AVR Studio. When I looked at everything required to get AVR Studio up and running I said that there must be other ways. AVR Studio has its perks but I’m just trying to get the Uzebox to do something at this point I don’t feel like learning all the interworking of AVR. I usually just use Notepad++. It’s free and allows for multiple tabs, keyword highlighting, and has a plug-in system for things like FTP. It also supports macros and can run programs just by using certain key combinations. If you want to get those parts, that’s fine but that’s not what I’m covering here.

I originally took the C code from the “Generating Tiles and Maps with gconvert” wiki article which covered a ‘game’ called Urban Mess. At this point we have created our own graphics we just need the C code. There is a link near the bottom of the page that has all of the UrbanMess files in a zip file. This is a direct link: http://uzebox.nebososo.com/urbanmess.zip

Open it up and you’ll see an urbanmess.hex file and an UrbanMess directory. The .hex file can be fed into the emulator and we will get to that later. For now, open up the directory. Here you see a data and a default directory and an urbanmess.c file. Copy that .c file out of the zip. We will be opening it in a moment. Look in the data directory and the default directory. The data directory has the files that the author used for gconvert. The default directory has the Makefile. The Makefile is very important and it determines things such as the name of your game and where all the key files are located. Copy this file out of the zip file too. The Makefile will remain mostly the way it is. We are only going to change the settings for the game name and kernel_dir. Later though.

Open the urbanmess.c file. Anything in green and surrounded by /* */ or beginning with // are comments and not code. Use comments to explain parts of the game and get in the habit of commenting your code or you WILL regret it later when you forget what some complex piece of code does and how it works. Notice the #include section at the top? You will need all of it. The last line will have the location of your tile sheet(s). Below you will see int main() { . This is the game’s code.

The first line of int main() is SetTileTable(uMTiles). This tells the Uzebox the name of your tileset. You would have specified this name in the convert.xml file earlier. You will then see DrawMap2(. This draws a map as the name implies. The first two values specify the coordinates to draw the map and the last piece specifies what map to draw. The dimensions of the map are stored in the map already. At the end you will see while(1);. This is an infinite loop. Usually while is like “while(condition==true)”. Since 1 will always be 1 and we aren't checking it against anything the while loop will never end. This code was just a graphical demo so there is no other code other than drawing the screen.

Change the last #include line to specify the location of your gconvert file. Have only the following in your code:

#include <stdbool.h>
#include <avr/io.h>
#include <stdlib.h>
#include <avr/pgmspace.h>
#include <uzebox.h>

#include "data/untitled.inc" // Your tilesheet

int main(){
	SetTileTable(uMTiles);      // Sets tile table to the specified tilesheet
	ClearVram();                // Fills the video RAM with the first tile (0, 0)

	//Draw the title
	DrawMap2(0,0,screen1);      // Draws the background
	DrawMap2(15,23,link_down1); // Draws the Link tiles
	while(1);
}

That’s it. This code will draw the background map and one of the Link images. Let’s set up a folder with your code in it. Make it similar to the urbanmess.zip setup. Create a folder called data and put your convert.xml and your gconvert .inc file in it. Make a default folder and put the Makefile into it. If you have not installed WinAVR then you need to do this now. Did you download the latest dev trunk from Google Code? Open it up and find the kernel directory and copy it into your folder. It should be right along the data and default directories. See the pictures to confirm that your folders are set up correctly. Also make sure that you have copied the ‘bin’ directory to your folder. The bin directory has gconvert, the emulator, and other things.

You may notice a file named makeit.bat in the default folder.. This is a file that I created that will run gconvert, compile the game, and then feed it to the emulator. It will be included in a download for this guide. You don’t NEED it, but it really helps to speed things up.

There are a couple of changes that you will need to make to the Makefile.

  1. Change “PROJECT” to “Demo Program”.
  2. Change “GAME” to “demoprogram”.
  3. Change “KERNEL_DIR” to “../kernel”. Note that forward slashes and not backslashes (/ vs \) must be used, even with Windows as your Operating System.
  4. Now go to (or search/find) “$(GAME).o: ../urbanmess.c” and change the urbanmess.c part to demoprogram.c.
  5. Make sure that the line “all: $(TARGET) $(GAME).hex $(GAME).eep $(GAME).lss $(GAME).uze” has “ size” on the end (including the space.)
  6. Lastly, add the following right above “## Clean Target”:
    1. UNAME := $(shell sh -c 'uname -s 2>/dev/null || echo not')
    2. AVRSIZEFLAGS := -A ${TARGET}
    3. ifneq (,$(findstring MINGW,$(UNAME)))
    4. AVRSIZEFLAGS := -C --mcu=${MCU} ${TARGET}
    5. endif
    1. size: ${TARGET}
      1. @echo
      2. @avr-size ${AVRSIZEFLAGS}


Here is the complete makefile:

###############################################################################
# Makefile for the Generating Tiles and Maps with gconvert tutorial
###############################################################################
 
## General Flags
PROJECT = Demo Program
GAME= demoprogram
MCU = atmega644
TARGET = $(GAME).elf
CC = avr-gcc
INFO=../gameinfo.properties

## Kernel settings
KERNEL_DIR = ../../../kernel
KERNEL_OPTIONS  = -DVIDEO_MODE=3 -DINTRO_LOGO=0 -DSCROLLING=0
#KERNEL_OPTIONS += -DMAX_SPRITES=14 -DRAM_TILES_COUNT=30 -DSCREEN_TILES_V=27 -DFIRST_RENDER_LINE=24 
#KERNEL_OPTIONS += -DOVERLAY_LINES=4 -DVRAM_TILES_V=24

## Options common to compile, link and assembly rules
COMMON = -mmcu=$(MCU)

## Compile options common for all C compilation units.
CFLAGS = $(COMMON)
CFLAGS += -Wall -gdwarf-2 -std=gnu99 -DF_CPU=28636360UL -Os -fsigned-char -ffunction-sections -fno-inline 
CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d 
CFLAGS += $(KERNEL_OPTIONS)


## Assembly specific flags
ASMFLAGS = $(COMMON)
ASMFLAGS += $(CFLAGS)
ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2

## Linker flags
LDFLAGS = $(COMMON)
LDFLAGS += -Wl,-Map=$(GAME).map 
LDFLAGS += -Wl,-gc-sections 


## Intel Hex file production flags
HEX_FLASH_FLAGS = -R .eeprom

HEX_EEPROM_FLAGS = -j .eeprom
HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"
HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings


## Objects that must be built in order to link
OBJECTS = uzeboxVideoEngineCore.o  uzeboxCore.o uzeboxSoundEngine.o uzeboxSoundEngineCore.o uzeboxVideoEngine.o $(GAME).o 

## Objects explicitly added by the user
LINKONLYOBJECTS = 

## Include Directories
INCLUDES = -I"$(KERNEL_DIR)" 

## Build
all: $(TARGET) $(GAME).hex $(GAME).eep $(GAME).lss $(GAME).uze size

## Compile Kernel files
uzeboxVideoEngineCore.o: $(KERNEL_DIR)/uzeboxVideoEngineCore.s
	$(CC) $(INCLUDES) $(ASMFLAGS) -c  $<

uzeboxSoundEngineCore.o: $(KERNEL_DIR)/uzeboxSoundEngineCore.s
	$(CC) $(INCLUDES) $(ASMFLAGS) -c  $<

uzeboxCore.o: $(KERNEL_DIR)/uzeboxCore.c
	$(CC) $(INCLUDES) $(CFLAGS) -c  $<

uzeboxSoundEngine.o: $(KERNEL_DIR)/uzeboxSoundEngine.c
	$(CC) $(INCLUDES) $(CFLAGS) -c  $<

uzeboxVideoEngine.o: $(KERNEL_DIR)/uzeboxVideoEngine.c
	$(CC) $(INCLUDES) $(CFLAGS) -c  $<

## Compile game sources
$(GAME).o: ../demoprogram.c
	$(CC) $(INCLUDES) $(CFLAGS) -c  $<

##Link
$(TARGET): $(OBJECTS)
	 $(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET)

%.hex: $(TARGET)
	avr-objcopy -O ihex $(HEX_FLASH_FLAGS)  $< $@

%.eep: $(TARGET)
	-avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0

%.lss: $(TARGET)
	avr-objdump -h -S $< > $@

%.uze: $(TARGET)
	-$(UZEBIN_DIR)packrom $(GAME).hex $@ $(INFO)	
	
UNAME := $(shell sh -c 'uname -s 2>/dev/null || echo not')
AVRSIZEFLAGS := -A ${TARGET}
ifneq (,$(findstring MINGW,$(UNAME)))
AVRSIZEFLAGS := -C --mcu=${MCU} ${TARGET}
endif

size: ${TARGET}
	@echo
	@avr-size ${AVRSIZEFLAGS}
	
## Clean target
.PHONY: clean
clean:
	-rm -rf $(OBJECTS) $(GAME).* dep/*


## Other dependencies
-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)

Those last two additions will output the space used in flash (program) and in RAM (data). Very important as your game grows.

Now you can just reuse the same Makefile unless you change the game’s name or learn how to modify the Makefile. You have everything you need at the moment and your game should start. Let’s compile it and then start it!

These next two parts need to be done from the command line. First we must ‘make’ our program. Drop to a command prompt and the cd into the directory that your game folder lives. Go into the default directory. All that should be there is the Makefile. All you have to do here is run ‘make’. That’s it, 4 letters at the command prompt then press enter. Lots of technical stuff will appear. Do a dir afterwards and you should see ‘demoprogram.hex.”

Completed overworld screen with Link.

THIS IS YOUR GAME! It took the tiles from gconvert and it took the game code and made a program that works with the emulator. Next the emulator. The emulator should be in the bin directory. Type in “..\bin\uzem2 demoprogram.hex”. This should start the game.

Do you see it? Link has been drawn in the center of the background. I suggest that you draw the other link frames above in the black area. Experiment with positioning and add any other graphics that you would like.

This tutorial has indicated the tools that you need and how to use some of them to get images on the Uzebox screen. Now that you can put graphics up. You can read through the Uzebox wiki and the forums to learn more.

TO DO

  • Add the graphics
  • Fix all formatting (Wow, copy and paste from MS Word is not awesome.)