Wednesday, October 30, 2013

The Constants of Change

Another busy level editing day.

The BezierPathComponent thing is working out decently well.  Travelling along the path and allowing starting/stopping at specific endpoints is doing it's thing, and being able to specify a speed along the curve, rather than relying on spacing the points consistently, is very nice.

It's actually kind of nice to be able to actually play basically the entire level with nav points and dialog now.  :)  The only things not really working are the opening camera pan and the small puzzle right at the end.

The opening camera pan... well, I need to get a better method for animating the camera.  I partially wonder if it would be worth getting animation export working from Blender so I can just animate a scene there and replay it in-game...but that seems a bit excessive at the moment.

The puzzle at the end presented some more troubles.  I basically just want to player to arrange a bunch of objects into the correct sequence.  The arrangement part isn't too hard, but when I went to make a test model for it, I realized that I want to be able to modify certain shader constants to be able to change the colors of certain meshes at runtime.  Unfortunately, my shader pipeline was not exactly set up to support this, so I dove back into the asset compiler again to make that work.  The shader generation is fixed, but I still need to deal with the runtime side of it.


Tuesday, October 29, 2013

So, you want to travel along a Bezier curve

So today was a bunch more playing around with Bezier curves.

I got the curve editor basically working well, but how to actually travel along the curve?  The thing about Bezier curves is that, as you evaluate them over a specific t∈[0,1], the change in distance travelled is not directly proportional to the change in t.

Even worse, if you are joining multiple curves together, using time elapsed as the t value could give wild discontinuities in velocity as you cross the boundary between a long curve and a short curve.  It's also very difficult to control acceleration at the beginning and end of travel along the curve.

So, today has been about evaluating a Bezier curve in terms of distance travelled, rather than elapsed time.
It appears that evaluating the length of a Bezier curve is fairly expensive as there is no closed form for computing it.  You basically have to recursively divide it up into a bunch of line segments and sum up their lengths, with improved accuracy the smaller you make the segments.  The error is just the difference between the sum of the lengths between the control points vs. the length between the first and last points - that is, keep subdividing until the segment is close enough to a straight line.

This is fairly straightforward, so my current approach is:
  • The BezierPathComponent takes an associated BezierCurveComponent and breaks it down into a bunch of segments (storing length, t0 and t1 for each segment)
  • Store the sum of the length all of the segments for a total curve length
  • Set a constant target distance along curve, target (maximum) speed and acceleration value
  • Keep track of the total distance travelled and the current speed
Then, we can update the speed each frame, update the total distance travelled, and figure out which segment we are in based on the total distance travelled so far.  After figuring out which segment we are in, we can either linearly interpolate along the segment, or figure out a t value based on the stored range of the segment to compute the position directly from the Bezier curve.

That should let us move at a controlled speed along a set of curves of varying shapes and lengths.

Monday, October 28, 2013

Curves

Lots of little things going on today.

Some cleanup of the level editor interface.  I'm still working on figuring out exactly what the "template code" (not actually using templates) should look like as far as handling input and object selection.  I decided on having the actual editing be a different mode from selection, as there is typically all sorts of stuff overlapping on the screen and it's too easy to select a different object when you're trying to move, say, a control point on a Bezier curve.

Which leads to, yes, I got a Bezier curve editor of a fashion up and running.  It looks like it will work well for plotting paths in 2D, though it's not currently suited to doing something like camera animation.  As just a curve in space, you can get a point, and a tangent/direction, but a camera needs to be able to have a clearer sense of "up" and can be rotated differently from its direction of motion.

I current have a nav point component, which basically uses physics calculations to "fly" a ship to a particular point.  This works tolerably well, and is good for starting from an arbitrary location, but for flying a fixed path through a level, it's a bit much.  Plus it's a bit flaky when arriving at a target - I have an approach vector specified, but it's not used properly yet, and overshooting the target causes frantic turns to compensate.  :)  It's good, but needs some work still.

So, that's in progress.  Then I fiddled around with generating some sound effects for various events, and possibly some ambient sounds.  I have the Native Instruments Komplete 9 package, which has a TON of stuff, all though it's not really geared for sound effects.  The Massive synth actually seemed pretty easy to use for building some generic FM sounds, and the Evolve Mutations packages have a lot of cool stuff in them.  The Giant piano also has some really cool piano noises, though I having exactly found a good place to use them yet.

So, decent start to the week.  Hopefully I can mostly focus on laying down objects and paths this week.

Thursday, October 24, 2013

Late post

Somehow I keep missing my blog schedule.  :)

There has been so much stuff going on, not all work related.  I have pretty much been focused on level editing and content creation, while patching up and improving the editor.

I finally ended up doing what I suggested a while ago, and am loading the "root" level attribute file in and editing the text directly in the level editor.  This works pretty well for item placement and nav point editing.  It took a lot of tweaking things to get it working well, but it cleaned up a bunch of code.  I made improvements to the base class for game objects and components to allow for identification by type or unique string ID, and added insertion functionality into my queue container, which I seem to have neglected to do previously. 

I spent a bit of time putting together a small piano piece for the introduction.  That actually turned out OK and went into the game pretty easily.  Then I got sucked into playing around with music software and didn't get a whole lot more done.



Next up, I may look at putting a Bezier curve editor in, and adding editor functionality for some other existing components.  Mostly I'm focused on level layout and navigation though.

Tuesday, October 22, 2013

Bug Day

I picked up an inexpensive graphics tablet to give it a try.  I was starting to feel the limitations of using just a mouse - touch sensitivity is pretty nice!  Things have come a long way since the last time I tried anything that resembled a tablet.  :)

After spending some time getting acquainted and configuring a few applications to cooperate, it was time to get down to some programming again.

At which point I ran headlong into stupid pipeline problems.  Again. 

It seems that the way I'm exporting model data doesn't really allow for having multiple "root" objects.  This is a little bit important because of various other stupid limitations of Blender/Bullet that require independent rigid bodies to be parented to nothing at all (not even an empty transform), otherwise they just become a single physics object.  >Headache<

All of this makes arranging a scene tree in a sensible fashion pretty much impossible.  There are ways to work around it in Blender, but they don't export properly.  >Headache<


I can modify my asset compiler to handle multiple root objects at least.  Going to be a long day...

Monday, October 21, 2013

Deviations


Sorry, nothing to exciting today, just gritty details of game development.  :)
Today was kind of all over the place.  I started off with a good push towards doing some level editing, but got sidetracked on some pipeline bugs and miscellaneous other things.

I made some progress getting the nav point editor started.  At least it displays the nav points now.  :)  I then went to make some placeholder art for a broken object in the scene.  After taking a few minutes to patch it up properly, because the cell fracturing tool does not get along with non-manifold meshes, I finally got it into the game and quickly discovered that the collision mesh and render meshes were not at all aligned.

I had discovered this problem earlier with some other models, but didn't really take the time to look into it.  Today it was severe enough to call for another look.  It turns out to have been a problem with the way I'm converting from the right-handed to left-handed coordinate system in the pipeline.  The Bullet importer doesn't really support this, so I have to go in and manually transform everything.  There was a bug when the pivot for the object was not at the origin, and basically everything was getting doubly-offset on the Y-axis, for mathematical reasons too tedious to explain right now.

Then I encountered a problem with binding the rigid body to the render mesh, which is done by name.  The COLLADA exporter replaces all periods in names with an underscore.  The Bullet exporter does not.  Not a really big deal, but took some time to track down and fix.

So, at last, I actually got a little work done on adding some new components to the engine.  The one thing I really wanted to add was the ability to script various operations on models.  In particular, I wanted to give every individual piece of an "exploded" model some random angular velocity when it is spawned, so I'm looking into a ModifyPhysicsComponent that will spin over all of the rigid bodies in a model and use a script/expression to modify them.  We'll see how it goes, looks fairly good so far.


So, overall, progress, but I really need to get past all of the expository bits in the first few levels of the game and get to the blowy-up bits.  :)

Saturday, October 19, 2013

Character Modeling, Take Four

I should have posted this a couple days ago:






After much mucking about with creases and cheek bones and eyebrow ridges and eyelids, I just took a giant Smooth brush and flattened everything.  Suddenly, everything looked right.  :)

I think the anime look works much better.  Next up, maybe I'll try for some better hair.

Friday, October 18, 2013

Bullet Trigger

Today started off with a daring rescue operation after the main mission ran out of fuel and the previous rescue operation went awry due to lack of power, leaving two astronauts stranded in lunar orbit.  All three astronauts have returned home safely and are eager to perform more ill-conceived celestial antics science.

But enough Kerbal Space Program.

I spent most of the day putting trigger volume support into the game engine.  Integrating it into Bullet was a little troublesome.  Bullet has callbacks for contact added/destroyed... but they don't actually seem to do what you would expect from the names.  Actually, the Add only works if you set special flags, and I have no idea what's up with the Destroy - it doesn't even take the objects in question as arguments, and only gets called... well, never as far as I can tell.

No worries, the Hacker Within shall prevail.  Without modifying 3rd party code if at all possible.

It looks like the collision callback happens every frame if two objects are touching, so I just set up the TriggerVolumeComponent to track if anything was touching it last physics tick, and if anything is touching it this tick.  In the post-physics update, if the flags don't match, the appropriate notification function is called.

This kind of limits the options for passing around which objects were actually causing the trigger, but ultimately I don't think that's too important.  Mostly I want to know the on/off state of the trigger.  The collision filtering takes care of most of that (only objects of the correct type affects a trigger) and each object can handle the regular collision callback if it cares that it's touching a trigger.

This opens the door to some other fairly useful components for building a level. 

An EnableOnTriggerComponent can mediate between a trigger volume and any other game object to enable or disable it.  If, for instance, a SpawnComponent is created disabled, it can be activated when the player enters a specific area.

For puzzle-type things, it could also be used to detect when the player has placed an object in the right location.
Basically, it enables the actual Game bit to work in the game.  :)

Thursday, October 17, 2013

Express Post

Back to programming again.

I decided to expand the expression parser to allow for if/while/for constructs and statement lists.  Those are actually pretty straightforward, though I also thought it might be a good idea to wedge in local variable declarations, and that is a little less straightforward.

Currently an Eval() call in the parse tree is expecting a templated "result" variable of the appropriate type generated by the sub-tree of the expression at each node.  I'm thinking this should just use a system stack structure of some sort - the return value just gets written above the stack pointer, and all of the local variables can then just sit below it.  That makes it just a short hop to proper function definitions.

So, there's some progress there.  Kerbal Space Program 0.22 was also released today, which makes it slightly more difficult to get any real work done.  :)

Wednesday, October 16, 2013

Seeing Through Time and Face

This morning I thought to myself, "If you start modeling, you know you're just going to spend all day doing it."

If only I could turn this future-telling prowess into money...

Despite the lack of meaningful level development, I might be getting better at the face modeling thing.  Having no artistic background at all is making for a steep learning curve.  Really,  I think I'm nearly face-blind.  But now, after studying facial details for two days, just going out to the store has been weird.  I keep seeing faces as collections of features rather than just generic facial blobs.

I think this is the best part of being an indie developer - learning new stuff that blows your mind.  :)

(I also took a look at 3D-Coat.  Apparently they have taken some lessons from Blender in interface incomprehensibilty.  Looks neat, but I'm not sure the 30 day trial is going to be enough to get it figured out...)


Character Modeling, Take Three

OK, this is way better.  :)


Not there yet, but definitely better.


Tuesday, October 15, 2013

Character Modeling, Take Two

I was going to do some more level work, but somehow ended up spending all day trying my hand at character modeling again.



At least this time I got something that might actually pass for a person.  Perhaps my artist friends can take a look and tell me everything I'm doing wrong.  :) 

It's still a work in progress, don't be too harsh.

Friday, October 11, 2013

Cut and Paste

After yesterday's coding fiasco, I got out the Giant Code Axe to fix the problem.  Actually, the Small Code Hatchet probably would have done the job.  Or maybe the Lesser Code Butter Knife.

Ultimately, the problem was that I was trying to use the same piece of data to solve incompatible problems (immediate input response, and inter-frame state).  The code was basically fine, I just needed to track two separate states. 

I also added an UpdateInput() event that gets broadcast for every mouse or keyboard event so they can get responded to properly for UI.  For gameplay, I basically just want to know how far the mouse moved in a frame, and which buttons were pressed.

Once I realized the problem, it was surprisingly easy to fix.

The peril of being a solo developer:  instead of explaining your problem to a co-worker before realizing you're being an idiot, you have to explain how you're being an idiot to the whole internet first.  Or at least to a bunch of loyal followers.  Or a bunch of spam-bots.  Is there anybody out there?  Hello?

The rest of the day was spent working on some level editing stuff.  I ran into a little trouble with my "spawn" component, which randomly fills an area with instances chosen from a set of models.  Editing the component live doesn't work very well, since it doesn't actually track what it spawned, so resetting it just spawns new models without deleting the old ones first.  Since it tries not to overlap models on spawn, it typically just can't find a spawn location and asserts.

This might be a good time to get level reset / restart working.

Thursday, October 10, 2013

Mouse Trap

Today started with making some meaningful progress on level editing, and devolved into re-writing most of the low-level mouse input API.  Bah.

I did make some progress rearranging and designing things such that each component can basically handle its own editor functionality (deciding how do draw its selection box, whether it's clicked or not, and what to display when it's the active object).  This looks like it will work better than having some sort of master "editor" class running the show.

Then I started to notice some weird input problems.  After clicking on an object and selecting Rotate, it wouldn't let me rotate for some reason.  Trying a second time would work.  It turns out the "mouse up" event from selecting the object was basically being saved as the last mouse event, and was then being read as the "mouse up" event for committing the edit immediately after entering the edit mode.

Bah.

The thing with handling mouse input is that it's possible to get multiple mouse events in a single frame, or it's possible to get none.  It's also important to know the mouse location at each button event.  During the game update, if you only look at the last event each frame, or even some sort of union of the states on a frame, you miss some meaningful information. 

The keyboard is a little more forgiving - generally, you only want to know if a key is down right now, or if a key was pressed for the first time since the last update.  Mouse input cares a lot more about both button up and button down events, where the cursor was when it happened, and what order it happened in.

So, the current solution is to buffer the mouse input for a frame so I can play it back, basically like a keyboard buffer.  This works OK, except where I have some key-checking and mouse-checking code mixed together, and the key-checking code doesn't execute unless there has been a mouse event on that frame.


I get the feeling I have caught teh dumb and that there is a simple, clean and obvious solution that I am just not seeing.

The only thing that really comes to mind is to do the input processing from the mouse event callback, so there is only ever one mouse event in the queue... which I was actually doing at one point, but abandoned when I moved to the component architecture.

I hear the Giant Code Axe being sharpened.

Wednesday, October 9, 2013

Real Life Intercedes

Short update today, as real life has decided that "making games" is "optional," while "ferrying people about" is "mandatory."

  • Nearly had a panic attack because CTRL-Z was no longer working in any application.  Turns out the `/~ key was jammed down somehow.
  • Working on editor related things - getting transform tools to work.
  • Reviewing / tweaking character concept art.
  • Did some modeling, trying my hand at character modeling.  Discovered I should stick with spaceships.  :)
  • Blender's sculpting tool is actually kind of nifty, if you can memorize all of the hotkeys.  The same thing is true for the rest of Blender, of course.


That's it, gotta run.

Tuesday, October 8, 2013

The Hacker Within

OK, level editor == monumental && monumentally boring task.  (@pedants: no, that doesn't parse meaningfully as a C++ expression, deal)

In an effort to make some meaningful progress, the Hacker Within has emerged and said those four most dreaded words (when coming from the Hacker Within):  "Why don't you just..."

Sayeth the Hacker Within, "Since everything is specified in text files anyway, why do you actually want to make a UI?  You've been editing attribute files by hand and it's fine.  The file monitor already knows which file was used to define an object.  When the text file changes, it auto-refreshes the object anyway.  Why don't you just do a system call and edit the attribute file of the currently selected object in Notepad++?"

"Well, because that's a stupid idea!  It's inelegant, hackish, brutish, and... oh, it's already done.  I suppose it has that going for it."

"But what about..." I begin to protest.

Sayeth the Hacker Within, "Look, just make some buttons to copy attributes to the Windows clipboard if you want to edit something like, I don't know, transforms in-game."

This has got to be the worst best idea ever.  At least it's progress.

Monday, October 7, 2013

Apparently I Still Remember How To Write Code

Back to coding again.  And just when modeling was getting fun.

Most of the day has been spent doing level-editor type things.  Mostly looking at ray/AABB intersection tests so I can figure out what I'm clicking on... though now that I'm writing this, I realize it probably makes more sense to project the AABB into screen space and do the test there (see, it pays to blog this stuff).

I spent part of the day decluttering my render library API.  I had added a bunch of "draw" functions in the main render class - things for drawing lines, circles, rectangles, boxes, etc.  This also involved loading a couple default shaders, creating the various vertex and index buffers for these objects, and a bunch of default textures.

That's all good and useful stuff, but really the base render class really has a single purpose:  translate application render calls to hardware API calls.  That mostly consists of setting render targets, vertex declarations, vertex streams and index buffers, and actually drawing primitives.  Since all of that "draw" stuff was taking up over half of the file, it was time for a split.

The change was actually pretty straightforward.  The draw functions really just use the application API and aren't hardware specific at all.  It was mostly a matter of making them call various functions in the other class instead of "this," and then patch up several places in the game code to use the new class rather than the main render API.  This took a lot less time than expected.

This cleaned up a few things too.  The virtual coordinate system stuff I was doing was kind of getting mingled into the print function.  With this change, the main API keeps a very base level of functionality - it just prints what it's told - and the "draw" API has its own print function that can scale for different resolutions before calling the low-level function.

Sunday, October 6, 2013

Playing With Blender

The weekend was spent playing with Blender.  I'm justifying it by saying that I will probably eventually need to stage proper background and camera angles for dialog and cut scenes, but mostly I'm just having fun. :)

Ship in nebula:



The majority of the time was probably spent doing the cockpit controls (visible at the beginning of the video).  Working with Blender's Cycles render engine is pretty nice.  Being able to set up materials and shaders in a sensible manner is good, especially being able to set up proper emissive materials and textures.

Also, after looking at several pictures of fighter jets, I realized that that the visibility from my ship was horrible, so I totally reworked the cockpit canopy to give better rear and side visibility.  This also resulted in putting in a proper seat, and then a second seat (which didn't really have any story purpose, but hey why not), and then a test character for size, and a few other details.

Because Blender is doing proper caustics, I ran into some problems with the whole volume of the canopy essentially being considered one big slab of glass and distorting the light, so I had to give it some thickness.  That's just totally unnecessary for game-side, but, whatever, it's really low poly and most of it will just get backface culled anyway.

I'm almost tempted to bring the whole thing into the game to see what will explode.  :)

And then I delved back into Blender's animation system and decided to render the whole thing at 1080p, and there you have my weekend.  Rendering at 1080p takes forever, fortunately the middle parts end up being mostly sky and go pretty quick.


Wednesday, October 2, 2013

Shattered

No update yesterday - there was really nothing to update about.  And today I was still not in a coding mood.  Fortunately, there is a lot of other stuff to do.

Today was mostly getting character reference in place because I finally contracted a concept artist.  It's good to start getting a better picture of characters that have been slowly forming in my head over the last several months, and hopefully getting that together will solidify my focus.

After that, today was mostly spent putting together some generic spaceship debris that I need for the opening scene. That went OK, though kind of slowly.  Most of the time was spent figuring out Blender's cell fracturing tool - and more specifically, why it wasn't doing what I wanted.  The short version is, manifold meshes are fairly important.  

My biggest complaint is that most tutorials seem to have "gone to video" recently.  That's fine to some extent, if people would actually edit their videos down to the important bits.  Rather than being able to skim text and glean what I want in a matter of seconds, I'm forced to watch half an hour of fiddling around, or hopelessly jump around the video trying to find something useful.  The other real problem with video is that by the time something really educational happens, it happens so fast you miss it completely and have to rewind endlessly.  Seriously, "needle in a haystack" is the only way to describe it.

OK, rant done.