The Reality Factory 2 Design Thread

Discuss the development of Reality Factory 2
Post Reply
User avatar
AndyCR
Posts: 1449
Joined: Wed Jul 06, 2005 5:08 pm
Location: Colorado, USA
Contact:

The Reality Factory 2 Design Thread

Post by AndyCR »

I constantly get asked about various aspects of the RF2 design, and I have no place to point to when the questions come up. I am writing this thread to finally have a place to put down the design of RF2, and rather than have a giant block of text to write I can write it here in small installments with users commenting on the design in between. Some time later the posts will be gathered into the final RF2 documentation.

Each post will have an aspect of the design, and explain it. No part of the design is concrete, even the part is already implemented - if it can be done better, I plan to do it at some point, even if not immediately.

When RF2 starts, it executes setup.py, which is located in the scripts folder. setup.py is the script which sets options for RF2 to start with - resolution, fullscreen, color depth, etc. If any attribute in the script is not changed, it will use a default - for instance, if you don't set whether RF2 should start fullscreen, it will start in a window. This script is where you could show a dialog asking the user for video options - it's completely up to you, and RF2 is paused until you're done in setup.py. It runs the script just as you would if you executed "import setup" in the Python console, adding the scripts folder to the Python path (so it can find other scripts, if you wish to import other scripts into setup). After setup.py has finished executing, it initializes Ogre with the parameters set in the script, creating the window. Some of the parameters set in setup are ignored in the editor - things like resolution (which depends on the viewport size), fullscreen (it's always windowed), and so on.

A module called "rfsetup" is created before setup.py is run, and the options are stored in there. They are preset to their defaults, and can be changed as you wish - for instance, "rfsetup.fullscreen = True".

Brief example, loading fullscreen attribute from a file and using it appropriately:

Code: Select all

import rfsetup

options_file = file("options.cfg")

for line in options_file:
    split_line = line.split()
    if line.startswith("fullscreen") and len(split_line) == 2:
        rfsetup.fullscreen = (split_line[1] == 'true')

options_file.close()
With this simple (and imperfect) script, we read from "options.cfg" and if it contains a line that starts with "fullscreen" and is followed by a space and more text, we start in fullscreen mode if the additional text is "true" and start in windowed mode otherwise. This would be handled automatically by the scriptset unless you specifically want to change the behavior (RF2 will ship with default scripts), but it's completely flexible if you do want to change it.
User avatar
AndyCR
Posts: 1449
Joined: Wed Jul 06, 2005 5:08 pm
Location: Colorado, USA
Contact:

Re: The Reality Factory 2 Design Thread

Post by AndyCR »

The other script RF2 runs is main.py. After setup.py is executed, RF2 finishes setting up and runs main.py in the same way it ran setup.py, but before running main.py it adds several new modules, including rfobjects, rfevents, rfinput, and so on.

rfobjects contains all objects used by RF2. To create a light, for instance, you simply do:

Code: Select all

import rfobjects

my_light = rfobjects.light("Name")
By default, you must give it a name - I plan to change this, either by waiting for Ogre to remove the requirement of having a name or by generating a unique name for each object in code, depending on how long it takes the Ogre team to do this.

Objects have properties, too. You can set them in much the same way you set the setup parameters:

Code: Select all

my_light.position = rfobjects.vector(0, 200, 100)
my_light.color = rfobjects.color(0.5, 0.75, 0.75)
You can perform operations on the object properties as you would expect, like:

Code: Select all

my_light.position += rfobjects.vector(0.5, 0.1, 0.23)
One thing you can't do yet due to a Boost::Python issue I'm working on a workaround for is:

Code: Select all

my_light.position.x += 5
You can of course use Python's convenience shortcuts to do things like this more easily, such as:

Code: Select all

from rfobjects import vector, color

my_light.position = vector(0, 200, 100)
my_light.color = color(0.5, 0.75, 0.75)
There are many objects in rfobjects, and I'll be explaining more of them later on.
User avatar
AndyCR
Posts: 1449
Joined: Wed Jul 06, 2005 5:08 pm
Location: Colorado, USA
Contact:

Re: The Reality Factory 2 Design Thread

Post by AndyCR »

Another "rfobjects" class is camera, which is a necessary addition to any game. It is what you view the world through.

Code: Select all

import rfobjects
from rfobjects import light, camera, vector

light1 = light("Light1")
light1.range = 1000

cam = camera("NewCamera")
cam.position = vector(0, 100, 400)
cam.lookat(light1.position)
User avatar
zany_001
Posts: 1047
Joined: Fri Mar 02, 2007 8:36 am
Location: Aotearoa

Re: The Reality Factory 2 Design Thread

Post by zany_001 »

Would we have to use this entity to clip a camera to actors? And could we have multiple cameras, with outputs to textures, so you could have a live security camera console, as well as the player view?
Once I was sad, and I stopped being sad and was awesome instead.
True story.
User avatar
AndyCR
Posts: 1449
Joined: Wed Jul 06, 2005 5:08 pm
Location: Colorado, USA
Contact:

Re: The Reality Factory 2 Design Thread

Post by AndyCR »

zany_001 wrote:Would we have to use this entity to clip a camera to actors?
No, not in the end. There will be a gameobject.attach function, so you can do things like "player.attach(playercam)". That's just not done at the moment; I've been working on other things, but it will be rather trivial to add.
zany_001 wrote:And could we have multiple cameras, with outputs to textures, so you could have a live security camera console, as well as the player view?
Yes, that is planned but not yet implemented as well. As above, it's nearly trivial to implement but has not been yet.
User avatar
AndyCR
Posts: 1449
Joined: Wed Jul 06, 2005 5:08 pm
Location: Colorado, USA
Contact:

Re: The Reality Factory 2 Design Thread

Post by AndyCR »

Now for a rather important class: rfobjects.actor. Actors are what you might expect: a no-logic dynamic model placed in the world. Example:

Code: Select all

import rfobjects
from rfobjects import vector, color, camera, light, actor

act = actor("ogre head", "ogrehead.mesh")
light1 = light("light1")
light1.position = vector(0, 50, 100)
light1.color = color(0.9, 0.9, 1)
cam = camera("cam1")
cam.position = vector(0, 0, 100)
cam.lookat(act.position)
This does what you would think; an actor is created, a light is created to cast light on it, and a camera is created to look at it.

Actors have other attributes as well. Materials, which will be explained further later, can be applied simply by:

Code: Select all

act.material = "MyMaterial"
Where "MyMaterial" was defined earlier in a .material script. MyMaterial can even be a shader, if you wish. Soon you will be able to apply materials you have defined in script as well as through material files.

You can also rotate, scale, set whether shadows are cast from the actor, etc...

Code: Select all

act.yaw(90)
act.scale = vector(1, 2, 2)
act.casts_shadows = False
At the moment, animation and bone functions aren't implemented, but should be soon.
User avatar
Sorington
Posts: 77
Joined: Tue Jun 17, 2008 3:42 pm
Contact:

Re: The Reality Factory 2 Design Thread

Post by Sorington »

this looks interesting :)
Greetings, Sorington
User avatar
AndyCR
Posts: 1449
Joined: Wed Jul 06, 2005 5:08 pm
Location: Colorado, USA
Contact:

Re: The Reality Factory 2 Design Thread

Post by AndyCR »

Thanks :)

Now, for an object to move, we have to have a way of telling it to move. In the end there will be various animation functions which take non-mesh animation (like lifts going up) off the hands of the scripter, but for now you have to do this manually. RF2 has an event system which handles objects doing things. There are 3 main types of events, but today I'll be focusing on global events - the metaphor I use for them is someone standing up and shouting something in a room. Everyone can hear and react to it if they choose to.

There are going to be many kinds of global events, but for now there is only one type - frame. There will be (buffered) input events, network events, etc.

So say you want the example above to have the model spin constantly. To handle events, you need to have your own class for them to arrive into. So we'll modify the code above like this:

Code: Select all

import rfobjects, rfevents
from rfobjects import vector, color, camera, light, actor

class spinning_head(actor):
    def __init__(self):
        actor.__init__(self, "ogre head", "ogrehead.mesh")
        rfevents.globalsocket(self.frame, "frame")
    def frame(self, event, sender, data):
        self.yaw(0.1*data)

head = spinning_head()
light1 = light("light1")
light1.position = vector(0, 50, 100)
light1.color = color(0.9, 0.9, 1)
cam = camera("cam1")
cam.position = vector(0, 0, 100)
cam.lookat(head.position)
Ok, this is a bit much to absorb all at once.

Code: Select all

import rfobjects, rfevents
As you can see, we're importing a new module, rfevents.

Code: Select all

class spinning_head(actor):
We're creating a new class based on the RF2 actor class.

Code: Select all

actor.__init__(self, "ogre head", "ogrehead.mesh")
We're initializing the RF2 actor class with the values we want. -Make sure to do this when you subclass classes in Python.-

Code: Select all

rfevents.globalsocket(self.frame, "frame")
This is the key line. This is saying "I want to listen for "frame" events, so send them to my frame function (self.frame)." This makes it's frame function get called every time a frame is about to be rendered. (Again, in the case of something so trivial as spinning something, you would want to use the RF2 animation system I'll be implementing, but for an example this works.)

Code: Select all

def frame(self, event, sender, data):
Event is the type of event, in case you have one handler for multiple types of events - in this case event would be "frame". Sender is the object which caused the event - in this case it's RF2 itself, so it is None. Data can be anything, and varies depending on the event - in the case of frame events, it's the time since the last frame (for smoothing).

Code: Select all

self.yaw(0.1*data)
Yaw, of course, means "spin side to side". Multiplying by data, however, requires some explanation. If there are 60 frames per second, data will be about 0.016. If you multiply the amount you want to go in one second by data, you will get the same movement on all PC's.
User avatar
Juutis
Posts: 1511
Joined: Thu Jan 12, 2006 12:46 pm
Location: Finland

Re: The Reality Factory 2 Design Thread

Post by Juutis »

Awesome thread, Andy!

Not only do we get info about RF2 and its development but also learn the scripting language. When you posted the first examples of scripting in RF2 ages ago I didn't understand much but now I'm starting to get the hang of it. Keep the information coming and we'll be writing our own scripts before RF2 is even released. :)

Great work.
Pain is only psychological.
Post Reply