Reconstructed Core

posted in A Keyboard and the Truth for project 96 Mill
Published August 03, 2007
Advertisement
Yay, this week has seen some major work on the new engine.

First off, I played with lua some more and finally was able to get 'exactly' what I wanted in an elegant way, yay!

So with the scripting system finally settled it was time to finalize the new object system.

A problem that plagued the S3Engine was that only 'entities' were 'addressable objects', an entity was an element of a scene, like a character, or a tree. Now the reason addressable objects were so handy is that they had a flexible key-value dictionary bound to them and could have properties defined through scripting:

setKeyString(entity,"key","value");
value=getKeyString(entity,"key");

this is a very powerful feature for changing the properties of an object. problem was there were lots of other objects that could have used this feature, but due to the lack of foresight in design these things could not be 'entities'

things such as:

- The Game (the game world)
- Maps
- Animated Planes
- Etc.

this meant that specialzed api functions had to be written to manipulate properties of these objects.

such as setAmbientLight(1,1,1,1);
where setKeyVector(game,"lightColor",1,1,1,1); would have been much nicer.

Also maps were referenced by their 'key name' which is a string alias:

createMap("portPlacid","data/portPlacid.script");
selectMap("portPlacid");

this worked fine, however it wasn't in keeping with 'object referencing' parameters.

So this was the main feature I wanted to change in the core, and the problem was that most of the functionality that I wanted was implemented in Entity, which was exclusively a display object that existed inside a map; I needed to implement this functionality at a lower level.

And so, StateObject was born, the state object is considred the base element of all elements that happen to be in a game state. The state object knows what script it sends it's events to, has a reference to the main lua state, can raise script events, knows it's logical 'object id' used for referencing in-script, contains a key/value dictionary and accessors for it, contains a list of Lock objects, which are events waiting to happen that will resume execution of a script, contain virtual update and render methods, contain virtual save and load serialization methods, contain a mutex lock (for synchronizing access, to an object (not for multithreading though)) and lots of other stuff. It basically embodies the base of any object that can cause script events and be manipulated through script api functions.

The Engine object (which is not stated) maintains a vector of these objects, which is essentially 'the game state', element 0 of this vector is always the World object, which is a subclass of StateObject, and is in charge of setting up the root lua_state and registering itself as the global variable 'world' with id 0; from there the World object contains methods for creating various other objects such as Rooms (maps) and Actors, both which inherit from StateObject.

Another improvement is storing the objects in a vector, the placement in the vector corresponds to the object's internal id, this id number is used as the object's reference in script; using the vector placement index means there is no need for a 'nextID' registration system and it means an 'instant' random access lookup from script object ID to internal engine object pointer.

Through a bit of type inference magic I was also able to shave off some typing work:

Instead of:

setKeyString(this,"key","val");
getKeyString(this,"key");
setKeyNumber(this,"key",100);
getKeyNumber(this,"key");
setKeyBool(this,"key",true);
getKeyBool(this,"key");
setKeyVector(this,"key",1,1,1,1);
getKeyVector(this,"key");

It's now:

setKey(this,"key","val");
getKey(this,"key");
setKey(this,"key",100);
getKey(this,"key");
setKey(this,"key",true);
getKey(this,"key");
setKey(this,"key",1,1,1,1);
getKey(this,"key");

Yay, less typing, of course I could have called it just get and set, but I figure getKey is short enough :)

Another scripting improvement is a change to how the syncable script api functions work; in the S3Engine a typical move command would look like this:

w0=move(rebecca,"node2");
...
...
wait(rebecca,w0);

The move function would start the entity 'rebecca' moving to "node2", this function returned an "Syncronization Object" though it is considered transparent it was really just an integer 'eventID';

Later this action could be waited on if we wanted to, via the wait function;
the inconvience is the redundance of data, having to pass in rebecca again.

The solution to this was to have the move function reutrn a lua table instead, with two keys objectID and eventID, this is then passed to wait, and it extracts the two needed pieces of information, resulting in:

w0=move(rebecca,"node2");
...
...
wait(w0);

much nicer, and it removes the chance of error, such as in:

w0=move(rebecca,"node2");
...
...
wait(ivy,w0);

which I have done before, yay copy and paste :)

Another improvement is that certain functions, such as Talk and Pause, are now automatically sychronized.

Before writing dialogue was 50% more tedious:

w0=talk(rebecca,"this is line one");
wait(rebecca,w0);
w0=talk(rebecca,"this is line two");
wait(rebecca,w0);

it is extremely rare, and always avoidable to have a talk command which isn't to be waited upon, so making the programmer put in the wait is just a waste of effort.

Instead now we have:

talk(rebecca,"this is line one");
talk(rebecca,"this is line two");

wait is called automatically via the talk api in C, same with pause.

currently the only commands which support a waitable object are move and act, since it is quite common to want to move several objects and do other actions then later create a common wait point.

w0=move(rebecca,"node2");
w1=move(ivy,"node3);

wait(w0);
wait(w1);

engage(rebecca,ivy);
act(rebecca,"wave",true,true);


The result of all this work is a very well-designed object base and improved scripting api.

In addition i've taken the time to re-introduce a few systems that got pruned during the modification.

The first is the 'Topic' system, which includes the relationship of Topics and Actors and the TopicMenu, which is the Visual UI for doing conversations in the game, this is a straight port from the S3Engine, it was well written then and still good now :)

Then I reintroduced the Inventory object, along with the script functions takeItem and dropItem, which support input and output to the inventory; soon I will be reintroducing the ItemMenu, which is the inventory UI

Soon, I'll be at a point where I can dedicate 100% of the time twoards the new 3D graphics components and the Physics system.

Comments? Questions?
Previous Entry More Scripting
Next Entry From 3rd to 1st
0 likes 4 comments

Comments

shadowcomplex
Hey Raymond, been meaning to drop a note here for a while, and just wanted to say it is nice to see you back in the game. I find your use of lua interesting, as I've never used it (or heavy scripting in general).

Quick question though: I know you thought that the previous S3 engine wasn't graphically capable of competing with modern commercial quality games, but what exactly are you shooting for with this graphics engine? Lots of shaders and top end systems? Mostly just curious as to your target demographic in that regard.

Keep the progress flowing!
August 03, 2007 09:56 AM
EDI
Thanks for the good word Shadowcomplex;

First off, my current attempt for my next game can be sumped up with the slogan "Gameplay Gameplay Gameplay", it's not even really about graphics so much as it is gameplay, we like that things look awesome, it's what get's us to play the game, but gameplay hooks us, considering we estimate from portal values that Morning's Wrath was played tens of thousands of times, it means that perhaps with better gameplay those could have converted into sales.

Now, here's the big progblem, classic adventure gameplay is old and tired, I hate to admit it; sure I find it fun to play it, but myself and those like me are a small minority. So the goal is to keep classic adventure gameplay and introduce some new gameplay flairs, this doesn't neccesarily mean inventing somthig new, but rather mixing elements of gameplay that adventure games don't usually see.

One complain in adventure games are action sequences, so chances are we won't be having many of those; one thing that people can't get enough of, is interaction, and the use of a physics engine is going to get me that kind of interesting interaction that I need.

The use of a 3D Graphics engine is for many resons:

- we were already using direct3D with shaders, so going that extra step isn't really a technological leap
- 3D Graphics gives an extra dimension of imersion, the ability to see things from all sides in different directions
- it's what today's non-casual gaming audience expects
- graphics hardware is made for it
- it's the best way to visualize the effect of physics

So the goal is to make the game environments prettier AND more dynamic, the ability to rotate things and blend animations cuts down on major art overhead.

But as I said what separates this engine from the S3Engine is the new system of gameplay, which is almost entirely physics driven, while the game will still have lots of classic adventure concepts (character conversations, item interactions,humor) it will also include a whole new way to interact with the environment in very unpredictable ways.

While I don't want to give too much away (until I figure out if I can 'REALLY' do it), the idea is to use the mouse as a physics force.

when simply clicking on somthing, it executes a contextual action, usually 'look', which gives the player more information about the thing, however, a click and drag, exerts a force on the object (asuming it's physics enabled, which most things will be), pulling back on the mouse exerts a pull force, and pushing forward, exerts a pushing force.

The rate of motion over time, determines the force strength exerted, as well as the original click-drag origin determins the force contact point.

This will allow you to flick on and off light switches, knock over vases, open refridgerator doors, push boulders off cliffs, etc.

As an additional feature, when you are holding an item in your hand, you inherit it's physics properties, thus, a pick-axe exerts far more pushing force than just your hands, also there are non-physics conceptual properties, such as sharpness, which can be used to sever ropes, chains, etc.

With this kind of gameplay ability the game will be set up as almost all 'physics puzzles', and it presents ample oppourtunity for 'just for fun' areas of the game, where a player could easily lose themselvs for an hour or two, just playing around with the environment, that's quality gameplay right there :)
August 03, 2007 10:45 AM
johnhattan
Quote:Original post by EDI

Comments? Questions?


I'll post comments when you start talking about game development.
August 03, 2007 01:46 PM
coderx75
Quote:Original post by EDI
With this kind of gameplay ability the game will be set up as almost all 'physics puzzles', and it presents ample oppourtunity for 'just for fun' areas of the game, where a player could easily lose themselvs for an hour or two, just playing around with the environment, that's quality gameplay right there :)

Sounds like fun! It also sounds pretty ambitious. Have you decided on a physics engine? I'd be interested in reading up on your progress since I've been struggling with physics lately.
August 03, 2007 02:29 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement