Talk:Tutorial: Hello World from scratch

From FIFE development wiki
Jump to: navigation, search
wiki
Proposed for removal! Contents of this article doesn't fulfill its original purpose
Wiki administrators will decide its removal!

See the following for how to write less text:

See an example of your page edited (I also removed the personal part), but needs deleting all [[remove and other minor fixes


Intro

N/A How to create a temporary variable pointing to fife root and then use the variable (to be able to test with packaged release, portable (completely in userspace) and from source

Create a folder in root and browse to it Folder.png <FIFE>\hello world. Create a file called File.png run_py. remove : FIFE has a long way, if ever, to need to explain about creating a file without formatting

Command.pngmkdir "hello world";cd "hello world" to be modified with variable for OS, I don't find a use for mkdir -p without automated scripts and only with existing files)

Code for FIFE dependencies

Import the FIFE modules

File.png hello_world/run.py

#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 
import sys, os
 
fife_path = os.path.join('..', 'fife', 'engine', 'python')
if os.path.isdir(fife_path) and fife_path not in sys.path:
	sys.path.insert(0, fife_path)
 
from fife import fife
print 'FIFE path: ' + os.path.dirname(fife.__file__)

On execution it should be something like:

$ ./run.py 
FIFE path: ../fife/engine/python/fife

Load settings.xml

File.png hello_world/run.py

#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 
import sys, os
 
fife_path = os.path.join('..', 'fife', 'engine', 'python')
if os.path.isdir(fife_path) and fife_path not in sys.path:
	sys.path.insert(0, fife_path)
 
from fife import fife
print 'FIFE path: ' + os.path.dirname(fife.__file__)
 
from fife.extensions.fife_settings import Setting 
settings = Setting(app_name='hello_world',	settings_file='./settings.xml')


Note that I did two things: I added the import for the class 'Setting' and I created an object called 'setting' of that type. In the demos, the name TDS is used instead of 'setting', but I have no clue what it means (I hazard that the 'S' is short for Settings).

Creating the Application Class

We need a class that is derived from 'ApplicationBase' that allows us to start the application using the method 'run()'. Following the conventions from the demo, we will put the class into a module called 'scripts'. To do so, we have to perform the following steps (read up on Python modules if you are interested in the details):

  • Folder.png hello_world/scripts File.png scripts/__init__.py(this essentially tells Python that the directory contains packages)
    • Command.pngmkdir scripts/ ; touch scripts/__init__.py
  • File.png scripts/helloworld.py that contains the class definition

File.png scripts/helloworld.py

#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 
from fife.extensions.basicapplication import ApplicationBase
 
class HelloWorldApplication(ApplicationBase):
	def __init__(self, settings):
		super(HelloWorldApplication, self).__init__(settings)


For the moment, this simply defines a class called 'HelloWorldApplication' whose parent is 'ApplicationBase'.

Starting the main application

Currently, the application class is not used at all. In order to change this, we need to add code to 'run.py' that creates an object of this type and invokes its 'run()' method: File.png hello_world/run.py

#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 
import sys, os
 
fife_path = os.path.join('..', 'fife', 'engine', 'python')
if os.path.isdir(fife_path) and fife_path not in sys.path:
	sys.path.insert(0, fife_path)
 
from fife import fife
print 'FIFE path: ' + os.path.dirname(fife.__file__)
 
from fife.extensions.fife_settings import Setting
from scripts.helloworld import HelloWorldApplication 
settings = Setting(app_name='hello_world',
	settings_file='./settings.xml')
 
def main():	app = HelloWorldApplication(settings)	app.run() if __name__ == '__main__':	main()


Note the following changes:

  • We import the class HelloWorldApplication using "from scripts.helloworld import HelloWorldApplication"
  • We define a function called 'main()' that instantiates a new object of type 'HelloWorldApplication' and invokes its 'run()' method
  • If 'run.py' is being executed as script (__name__ == '__main__'), call the function defined previously

NOTE:I suppose that the last step could be omitted (i.e. I think it would be OK to unconditionally call main(), but since I don't know much about Python, I am not sure about the implications of not using the __name__ == '__main__' check, and all the demos use it, so I didn't touch that).

OutputFile.png run.py

tobi-wan@tesla ~/src/hello_world $ ./run.py 
FIFE path: ../fife/engine/python/fife
Traceback (most recent call last):
  File "./run.py", line 25, in <module>
    main()
  File "./run.py", line 21, in main
    app = HelloWorldApplication(settings)
  File "/home/tobi-wan/src/hello_world/scripts/helloworld.py", line 9, in __init__
    super(HelloWorldApplication, self).__init__(settings)
  File "../fife/engine/python/fife/extensions/basicapplication.py", line 80, in __init__
    self.initLogging()
  File "../fife/engine/python/fife/extensions/basicapplication.py", line 170, in initLogging
    logmodules = self._setting.get("FIFE", "LogModules", ["controller"])
  File "../fife/engine/python/fife/extensions/fife_settings.py", line 455, in get
    if self._readSettingsCompleted[module] is not True:
KeyError: 'FIFE'


Ouch! Maybe now is a good time to create and populate the file 'settings.xml'.

Special files

settings.xml

Here's the contents of a minimal File.png hello_world/settings.xml:

<?xml version='1.0' encoding='UTF-8'?>
<Settings>
	<Module name="FIFE">
		<Setting name="FullScreen" type="bool">False</Setting>
		<Setting name="PlaySounds" type="bool">True</Setting>
		<Setting name="RenderBackend" type="str">OpenGL</Setting>
		<Setting name="ScreenResolution" type="str">1024x768</Setting>
		<Setting name="Lighting" type="int">0</Setting>
	</Module>
</Settings>


File.png settings.xml contains one (or multiple) 'Module' sections identified by their 'name' attribute, and each module contains settings.

Ah, finally some progress! If we now execute our 'run.py', we get a load of output and - for a very short time - even something that looks like it could be an application window! Output

tobi-wan@tesla ~/src/hello_world $ ./run.py 
FIFE path: ../fife/engine/python/fife
Controller:LOG:================== Engine initialize start =================
Controller:LOG:Time manager created
Controller:LOG:Creating VFS
Controller:LOG:Adding root directory to VFS
Controller:LOG:Adding zip provider to VFS
Controller:LOG:Engine pre-init done
Controller:LOG:Creating event manager
Controller:LOG:Creating resource managers
Controller:LOG:Creating render backend
Controller:LOG:OpenGL Render backend created
Controller:LOG:Initializing render backend
Controller:LOG:Querying device capabilities
Controller:LOG:Creating main screen
Controller:LOG:Main screen created
Controller:LOG:Creating sound manager
Controller:LOG:Creating renderers
Controller:LOG:Creating model
Controller:LOG:Adding pathers to model
Controller:LOG:Adding grid prototypes to model
Controller:LOG:Engine intialized
Traceback (most recent call last):
  File "./run.py", line 25, in <module>
    main()
  File "./run.py", line 21, in main
    app = HelloWorldApplication(settings)
  File "/home/tobi-wan/src/hello_world/scripts/helloworld.py", line 9, in __init__
    super(HelloWorldApplication, self).__init__(settings)
  File "../fife/engine/python/fife/extensions/basicapplication.py", line 95, in __init__
    pychan.init(self.engine, debug = self._finalSetting['PychanDebug'])
  File "../fife/engine/python/fife/extensions/pychan/__init__.py", line 290, in init
    manager = Manager(_munge_engine_hook(engine),debug,compat_layout)
  File "../fife/engine/python/fife/extensions/pychan/compat.py", line 68, in _munge_engine_hook
    engine.getSettings().getDefaultFontGlyphs()
  File "../fife/engine/python/fife/fife.py", line 3596, in setDefaultFont
    return _fife.GUIChanManager_setDefaultFont(self, *args)
RuntimeError
Controller:LOG:Destructing engine
Controller:LOG:================== Engine destructed ==================


That looks nice except for the 'runtimeError'.

What I figured out so far is that this seems to indicate that the application is unable to load the default font. Here's how I solved that problem:

Font

First, I copied the directory (and its contents) Folder.png src/fife/demos/rpg/fonts/ to Folder.png hello_world: Command.png cp -r ~/src/fife/demos/rpg/fonts/ . Next, I added a setting for 'Font' to 'settings.xml':

<?xml version='1.0' encoding='UTF-8'?>
<Settings>
	<Module name="FIFE">
		<Setting name="FullScreen" type="bool">False</Setting>
		<Setting name="PlaySounds" type="bool">True</Setting>
		<Setting name="RenderBackend" type="str">OpenGL</Setting>
		<Setting name="ScreenResolution" type="str">1024x768</Setting>
		<Setting name="Lighting" type="int">0</Setting>
		<Setting name="Font" type="str">fonts/FreeSans.ttf</Setting>
	</Module>
</Settings>

If we start our application now, we get some output and a black window that does not terminate immediately (actually, it only terminates once you press Ctrl+C in the terminal). Not bad, not bad at all. Now we have something to work with.

Creating a map

As a next step, we want to replace the black window with a map of our own. The tutorials I found until now recommend to take the map of an existing demo, but I'd like to walk you through creating a very simple map using the FIFE Editor.

Before we can create the map, however, we need some tiles for it. For that, we need to create so-called objects. We want the objects to be located in the subdirectory 'objects/ground/' and the maps in 'maps/', so we create those directories:

tobi-wan@tesla ~/src/hello_world $ mkdir -p objects/ground/
tobi-wan@tesla ~/src/hello_world $ mkdir maps/


Creating some ground tiles

Next, we create some graphics (using any graphics program you are comfortable with, as long as it can produce PNG graphics). For our application, we want the graphic to be 64x64 pixels, and the corners of the ground tile within it should be at the pixel locations (0, 32), (32, 48), (64, 32) and (32, 16).

This sounds complicated, but becomes clear with a few examples (as you can probably tell from them, I'm not an artist). NOTE:The background of the graphic must be transparent!

File.png hello_world/objects/ground/grass01.png Tutorial5 grass01.png File.png hello_world/objects/ground/water01.png Tutorial5 water01.png

For each object, we also need an corresponding XML file to describe the object (this will be particularly important later, as far as I understand, when it comes to rotation of objects).

File.png hello_world/objects/ground/grass01.xml

<?fife type="object"?>
<object id="grass01" namespace="http://www.fifengine.de/xml/hello_world" blocking="0" static="1">
	<image source="grass01.png" direction=”45” />
</object>

File.png hello_world/objects/ground/water01.xml

<?fife type="object"?>
<object id="water01" namespace="http://www.fifengine.de/xml/hello_world" blocking="0" static="1">
	<image source="water01.png" direction=”45” />
</object>

The object ID should be some unique identifier for the object. Regarding rules for selecting a good namespace: I have absolutely no clue, I just stuck with what the demos suggested - maybe just using "hello_world" would also be OK, but I always understood XML namespaces to be URIs. Whatever.

Also, later, we might want to make the water tile 'blocking', but I'm not sure myself yet on how to make water 'non-walkable'. Let's wait and see ;-)

Now that we have two objects (on for grass, one for water), we can start creating the map.

Using the FIFE Editor

First, let's start the editor:

tobi-wan@tesla ~/src/fife/tools/editor $ ./run.py


Here's what I did afterwards (for everything else, I just used the default settings):

  • 'File' -> 'New map'
  • Map name: hello -> OK
  • Layer ID: ground -> OK
  • Camera ID: camera01; Reference cell Width: 72; Reference cell Height: 36; Rotation: 45; Tilt: 60 -> OK

The values for the reference cell, the rotation and the tilt of the camera create a 'perfect isometric' view. I got that information here: [1]


Now that we have the basic map, we need to load our object:

  • 'File' -> 'Import directory'
  • Navigate to ~/src/hello_world/objects/ and press 'Select'
  • Now you should be able to select the two tiles in the Object selector (see screenshot below):

Tutorial5 fife editor objects imported.png


Using the pencil, we can now draw some tiles and save the resulting map using 'File' -> 'Save as' and save the map as <File.png hello_world/maps/hello.xml.

Tutorial5 fife editor hello map.png


Loading a map

Now, finally, we can load that map in our application. To do so, we create a new class called 'World' that will later control our whole world:

File.png hello_world/scripts/world.py

#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 
import os
 
from fife.extensions.loaders import loadMapFile
 
class World(object):
	def __init__(self, engine):
		self._engine = engine
		self._map = None
 
	def loadMap(self, filename):
		self._map = loadMapFile(os.path.join('maps', filename + '.xml'),
			self._engine, extensions = { 'lights': True })


Next, we need to create a 'World' object somewhere and load the first map. We will do that within the application class (HelloWorldApplication) and load the map file name from the settings.

File.png hello_world/scripts/helloworld.py

#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 
from fife.extensions.basicapplication import ApplicationBase
from scripts.world import World 
class HelloWorldApplication(ApplicationBase):
	def __init__(self, settings):
		super(HelloWorldApplication, self).__init__(settings)
		self._world = World(self.engine)		self._world.loadMap(str(settings.get('helloworld',			'MapFile')))


Note the following changes:

  • We import the class 'World' from 'scripts.world'
  • In the constructor, we create a 'self._world' object of type 'World' and load the map defined in the settings within the module 'helloworld' in the setting named 'MapFile'

Now, we need to add that setting to the file 'settings.xml' and set it to 'hello' (the name of the map file):

<?xml version='1.0' encoding='UTF-8'?>
<Settings>
	<Module name="FIFE">
		<Setting name="FullScreen" type="bool">False</Setting>
		<Setting name="PlaySounds" type="bool">True</Setting>
		<Setting name="RenderBackend" type="str">OpenGL</Setting>
		<Setting name="ScreenResolution" type="str">1024x768</Setting>
		<Setting name="Lighting" type="int">0</Setting>
		<Setting name="Font" type="str">fonts/FreeSans.ttf</Setting>
	</Module>
	<Module name="helloworld">		<Setting name="MapFile" type="str">hello</Setting>	</Module></Settings>

Voila! If you now start the application, you should see the map you just created (but nothing else yet)!

Going further

I am planning to extend this tutorial as my knowledge of FIFE progresses (if I find enough spare time). If, in the meantime, anybody wants to add to the content or correct me where I am wrong, please be invited to do so!