I discovered delegates while working in C#, which supports them natively. Unfortunately, C++ doesn't handle them so elegantly.
Basically, sometimes it would be nice to "subscribe" to certain events or messages in a system. For example, it might be nice to get a callback when a particular object is destroyed so you can clean up any references you have to it. I ran into this particular problem when I had an "enemy" object holding a pointer to the "player" object - this caused a crash when the player died and their object was destroyed.
There are ways to handle this, though most of them are inelegant or require the object generating the event to know more about the receiver than we would like (say, a common base class that the receivers can derive from). This is also fairly straightforward if you just want to call a static function, but what if you want to call a member function?
The main problem is that C++ just really doesn't let you easily
create a collection of completely unrelated types, and pointers to
member functions in unrelated classes are basically completely
unrelated.
C# handles this quite nicely by declaring a delegate - basically, a prototype for the callback function - and storing references to the object/function in a list. When you "call" the list of functions, every object/function in the list receives the callback with the arguments you provide.
There are a lot of attempts to do this in C++. C++11 may improve things. I just went and rolled my own, taking ideas from here and there and trying to keep the code as simple as possible. It involves a few macros to wrap some complexity, but seems to work.
Saturday, August 31, 2013
Friday, August 30, 2013
Expression parsing is awesome
You know how I said that adding anything with overridden operators to the expression parser would be pretty easy?
Actually, it's ridiculously easy. I just added std::string as a basic type, and it took a whole 5 minutes.
I can use strings in my expression parser... that is equal parts exhilarating and terrifying. :)
Anyway, I'm going to bind UI controls to C++ code via expressions. The variable scoping rules mean I can bind an expression to a specific object/component and basically manipulate it directly.
I really need to get function calling working for button events. I can parse the argument list easily enough, I just haven't figured out exactly how I want to bind it to C++ code yet.
Actually, it's ridiculously easy. I just added std::string as a basic type, and it took a whole 5 minutes.
I can use strings in my expression parser... that is equal parts exhilarating and terrifying. :)
Anyway, I'm going to bind UI controls to C++ code via expressions. The variable scoping rules mean I can bind an expression to a specific object/component and basically manipulate it directly.
I really need to get function calling working for button events. I can parse the argument list easily enough, I just haven't figured out exactly how I want to bind it to C++ code yet.
Level Editor
I've been inching closer to getting going on actual level design for days now, and there always seems to be something else to do. Actually, that's not entirely true: every time I try to get started on actual level design, there doesn't seem to be any way to design a level.
Clearly, I need a level editor.
I had written a bunch of UI controls a while back. They have kind of been disabled in the switch to the component system, so today has mostly been resurrecting that system and integrating it with the component system. I was going to need GUI stuff again at some point, might as well do it now.
Making the switch was actually fairly easy. All of the base types can be constructed from attribute files. Maybe I can have something working by the end of the weekend.
Clearly, I need a level editor.
I had written a bunch of UI controls a while back. They have kind of been disabled in the switch to the component system, so today has mostly been resurrecting that system and integrating it with the component system. I was going to need GUI stuff again at some point, might as well do it now.
Making the switch was actually fairly easy. All of the base types can be constructed from attribute files. Maybe I can have something working by the end of the weekend.
Thursday, August 29, 2013
Let's Do Math! - Guidance Control
Down below you'll find some discussion of doing some "physics-based guidance control," but first the daily update:
I basically have two separate particle systems:
One is a pretty typical particle system, it just emits and renders mostly ballistic sprite particles, for explosions or smoke, that sort of thing.
The other is really more of a batch model-rendering system - it takes a single model and spawns multiple rigid bodies, so it has a physical presence in the physics simulation - good for bullets, swarms, that sort of thing.
So, what if you have a bullet, and you want a small explosion when it hits something?
I put together a sort of mediation component that waits for notifications from the physics particle system that a particle is being destroyed, and then it emits a particle on a an explosion particle system.
Which is fine, except now I have a cSpawnParticleOnPhysicsCollideComponent class, which is getting a bit wordy. There's also a cSpawnParticleOnPhysicsTimeoutComponent class. It also doesn't trigger any audio yet. This is going to grow out of control quickly, seems like it needs a rethink.
I wanted to work out the math required to solve this problem:
So, you want to start turning in a particular direction, then slow down and come to a stop directly facing your target. I'm assuming that your target is stationary, otherwise this gets complicated.
First, your velocity under maximum deceleration will look something like this:
where the y-axis is your current speed, x-axis is the amount of time it will take you to stop, and the area under the curve is the distance you will travel.
So what do we need to calculate?
Converting between angular acceleration and torque is pretty easy:
Then you just need to compute the optimal acceleration, and make sure you don't exceed it:
Which looks a bit more sensible in code:
OK, I'm not 100% certain that is all correct, but it seems to work, which is a good sign. :)
All of the math looks very similar for doing the same thing with linear acceleration.
Particle Event Components
I basically have two separate particle systems:
One is a pretty typical particle system, it just emits and renders mostly ballistic sprite particles, for explosions or smoke, that sort of thing.
The other is really more of a batch model-rendering system - it takes a single model and spawns multiple rigid bodies, so it has a physical presence in the physics simulation - good for bullets, swarms, that sort of thing.
So, what if you have a bullet, and you want a small explosion when it hits something?
I put together a sort of mediation component that waits for notifications from the physics particle system that a particle is being destroyed, and then it emits a particle on a an explosion particle system.
Which is fine, except now I have a cSpawnParticleOnPhysicsCollideComponent class, which is getting a bit wordy. There's also a cSpawnParticleOnPhysicsTimeoutComponent class. It also doesn't trigger any audio yet. This is going to grow out of control quickly, seems like it needs a rethink.
Now, Let's Do Math!
I wanted to work out the math required to solve this problem:
- Under a maximum acceleration, how do we turn to face a particular direction as quickly as possible without overshooting the target?
So, you want to start turning in a particular direction, then slow down and come to a stop directly facing your target. I'm assuming that your target is stationary, otherwise this gets complicated.
First, your velocity under maximum deceleration will look something like this:
where the y-axis is your current speed, x-axis is the amount of time it will take you to stop, and the area under the curve is the distance you will travel.
- If you are on the line, you just need to decelerate at the maximum rate, and when you hit zero angular velocity, you should be facing the right direction.
- If you are below the line, you basically want to get to the line as quickly as possible.
- If you are above the line, you can't slow down fast enough to avoid overshooting the target, but let's do our best...
So what do we need to calculate?
Then you just need to compute the optimal acceleration, and make sure you don't exceed it:
Which looks a bit more sensible in code:
VECTOR4 axis, angle; //Desired rotation turn_axis_angle(from, to, &axis, &angle); VECTOR4 w_opt = axis * VECTOR4::sqrt2() * sqrt(angle * max_ang_accel); //How fast we should be turning right now (w0) to decelerate to w=0 after turning angle radians VECTOR4 w_delta = w_opt - w0; //Difference between optimal and current angular velocities VECTOR4 w_delta_accel = length3(w_delta) / VECTOR4(GameLib::physics_dt); //Acceleration required to get to optimal by next frame VECTOR4 w_cmp = w_delta_accel > max_ang_accel; //Choose lesser of optimal and maximum acceleration VECTOR4 w_accel = sel(w_cmp, safe_normalize3(w_delta) * max_ang_accel, axis * w_delta_accel); VECTOR4 torque = I * w_accel; //Compute torque from acceleration
OK, I'm not 100% certain that is all correct, but it seems to work, which is a good sign. :)
All of the math looks very similar for doing the same thing with linear acceleration.
Wednesday, August 28, 2013
Leaking
So, yesterday's successful memory cleanup was mostly motivated by the observation that, according to the Task Manager, my game was leaking memory at about 70K per second. I was expecting to find it was my fault, but now that there are no memory leaks... it's still happening!
So, on to more data gathering.
Using HeapWalk, and dumping the entire contents of memory every frame, I discovered that... well, there's definitely a leak, but it's not one of the game allocations.
First, I pause the game, so there is nothing happening during Update, and we're only Rendering the same frame over and over again. Then, I put a breakpoint in HeapAlloc (the base level Windows allocator that everything else eventually calls).
So, there are a tiny number of (expected) allocations of mine... a bunch from NVIDIA's driver...
And finally I notice some allocations happening from my file monitor, which is a really handy class that I set up that stores a list of files, their last-modified times, and a callback function pointer. Once each frame, I check to see if any of the files were modified, and if they were, trigger the callback. This makes live asset changes really easy.
Apparently, in one case, I was not calling FindClose after calling FindFirstFile to check the current file time.
Fixed this, and my memory usage is nice and stable. Yay, no more sucking up all available memory if I leave the game running for a few hours!
So, on to more data gathering.
Using HeapWalk, and dumping the entire contents of memory every frame, I discovered that... well, there's definitely a leak, but it's not one of the game allocations.
First, I pause the game, so there is nothing happening during Update, and we're only Rendering the same frame over and over again. Then, I put a breakpoint in HeapAlloc (the base level Windows allocator that everything else eventually calls).
So, there are a tiny number of (expected) allocations of mine... a bunch from NVIDIA's driver...
And finally I notice some allocations happening from my file monitor, which is a really handy class that I set up that stores a list of files, their last-modified times, and a callback function pointer. Once each frame, I check to see if any of the files were modified, and if they were, trigger the callback. This makes live asset changes really easy.
Apparently, in one case, I was not calling FindClose after calling FindFirstFile to check the current file time.
Fixed this, and my memory usage is nice and stable. Yay, no more sucking up all available memory if I leave the game running for a few hours!
Tuesday, August 27, 2013
I Remember Nothing
I can shut down cleanly with no memory leaks! Whoo!
OK, not that big a deal... well, unless you've ever tried to make your game do it, and then maybe you can appreciated it. :) At least, it's the most I can mange through the fog of whatever it is that's ailing me.
Since I'm currently working on PC, this was made somewhat easier by using the Windows debug allocators:
_aligned_malloc_dbg
_aligned_free
I'm only using the aligned versions - it makes things a lot easier to just have everything 16-byte aligned (required for SIMD instructions and occasionally other things). Most allocations where this would make any difference at all go into a container or block allocator anyway.
In any case, these functions have one fairly nifty feature: _crtBreakAlloc.
When you exit your game, you will get a list of memory allocations that haven't been cleaned up, along with an allocation number associated with each one (and hopefully the file and line where the allocation happened).
So, if the 1065th allocation was not released, single-step to start the game again, put _crtBreakAlloc in a watch window, set it to 1065, and continue to run the game. When the 1065th allocation happens, you will get a break, and hopefully you can figure out why that particular allocation was not released.
This technique doesn't work once you have allocations happening in a non-deterministic order - say, after user input or random number generation - but for testing purposes it should be possible to work around those.
OK, not that big a deal... well, unless you've ever tried to make your game do it, and then maybe you can appreciated it. :) At least, it's the most I can mange through the fog of whatever it is that's ailing me.
Since I'm currently working on PC, this was made somewhat easier by using the Windows debug allocators:
_aligned_malloc_dbg
_aligned_free
I'm only using the aligned versions - it makes things a lot easier to just have everything 16-byte aligned (required for SIMD instructions and occasionally other things). Most allocations where this would make any difference at all go into a container or block allocator anyway.
In any case, these functions have one fairly nifty feature: _crtBreakAlloc.
When you exit your game, you will get a list of memory allocations that haven't been cleaned up, along with an allocation number associated with each one (and hopefully the file and line where the allocation happened).
So, if the 1065th allocation was not released, single-step to start the game again, put _crtBreakAlloc in a watch window, set it to 1065, and continue to run the game. When the 1065th allocation happens, you will get a break, and hopefully you can figure out why that particular allocation was not released.
This technique doesn't work once you have allocations happening in a non-deterministic order - say, after user input or random number generation - but for testing purposes it should be possible to work around those.
Monday, August 26, 2013
Rendering Layers
Sick day - still fighting whatever it is I caught last week. Still, no rest for the sick-ed.
So, what did I do today?
All of this was to try and get the Health component to display a health bar above whatever it's attached to. Still working on that.
So, what did I do today?
- There are a set of "layers" that can be rendered to (default, alpha-blend, HUD, etc.)
- Each game object has a layer mask, that specifies which layers it wants to render to
- Each component adds its layer mask (if any) to the parent game object's mask
- Each camera has a set of layers that it draws
- The camera broadcasts Render(layer) to each component in each game object for each of the camera's draw layers
- It's the responsibility of each component to decide what (if anything) it wants to draw on each layer
All of this was to try and get the Health component to display a health bar above whatever it's attached to. Still working on that.
- Engine exhaust particles bound at model space transform, not world space - now that I can get the model-space transform after Friday's model fix
Saturday, August 24, 2013
Base Metal Blog Weekend Edition, August 24-25, 2013
Assert Yourself Conditionally
How many times have you written this code:
void Fn(TYPE *val)
{
ASSERT(val);
if(val)
{
//Do some stuff
}
}
Or worse, this code:
void Fn(TYPE *val)
{
ASSERT(val && "You are about to crash!");
val->Fn();
}
Now there's a better way! Introducing the if_assert:
void Fn(TYPE *val)
{
if_assert(val)
{
//Do some stuff
}
}
Which is just defined as:
#ifdef DEBUG
#define if_assert(x) if(!!(x) || System::AssertFail(#x " " STRINGIFY(__FILE__) ":" STRINGIFY(__LINE__)))
#else
#define if_assert(x) if(x)
#endif
Some points on that code:
- You'll need to provide your own bool System::AssertFail(const char *msg) function
- It should return false.
- My System::AssertFail(...) just prints the message passed to it and does a normal ASSERT(0)
- I have this defined as extern rather than inline. That keeps the contents of System::AssertFail(...) out of the instruction cache unless the assert actually fails, which depending on the complexity of your ASSERT handler can be substantial.
- In non-DEBUG builds, this just reduces to if(x)
- The !!(x) basically means the same thing as (x), but the compiler doesn't complain about automatic conversion to bool
- Because C uses lazy evaluation, nothing after the || will get evaluated if (x) is true
- STRINGIFY just converts its argument to a string. There is some magic happening there, though, because you want the compiler to convert __FILE__ to a string before the macro converts it to the string (otherwise you just get "__FILE__" instead of the actual file name), so:
- #define _STRINGIFY(x) #x
- #define STRINGIFY(x) _STRINGIFY(x)
- Unfortunately, this doesn't support declaring variables inside the if_assert:
- Do:
- TYPE *val = GetValue();
- if_assert(val) ...
- not:
- if_assert(TYPE *val = GetValue()) ...
- though if you're dong this, you probably don't need an ASSERT:
- if(TYPE *val = GetValue()) ...
Friday, August 23, 2013
Unapologetically Technical Since Forever - August 23, 2013
Just a note: I'm sure this blog is starting out exceptionally technical. It will probably be more or less so over time, depending on what I happen to be working on each day. If something really doesn't make sense, just ask. :)
---------------------------------------------------------------------------------------
Anyway, enough expression parsing. I had to fix a couple bugs (operators of the same precedence were evaluating right-to-left instead of left-to-right, oops). I can set shader constants and effectively animate them by using the global "time" variable. This will have many more applications in the future, but for now...
Today has basically been a cleanup day. When I integrated my Model class into the component system, it was still structured around the idea of a model being an independent entity, rather than something attached to a game object transform. So a model object basically has this architecture:
Have a good weekend, we'll see if I get a weekend edition out or not.
---------------------------------------------------------------------------------------
Anyway, enough expression parsing. I had to fix a couple bugs (operators of the same precedence were evaluating right-to-left instead of left-to-right, oops). I can set shader constants and effectively animate them by using the global "time" variable. This will have many more applications in the future, but for now...
Today has basically been a cleanup day. When I integrated my Model class into the component system, it was still structured around the idea of a model being an independent entity, rather than something attached to a game object transform. So a model object basically has this architecture:
- GameObject -> Transform as far as rest of game is concerned
- ModelComponent
- Model
- Rendering Geometry -> Transform as far as rendering is concerned
- RigidBody -> Transform as far as physics is concerned
Have a good weekend, we'll see if I get a weekend edition out or not.
Thursday, August 22, 2013
Expression Parsing - August 22, 2013
Posting early today, non-work stuff going on that needs my attention this afternoon.
Despite having some cough/cold thing going on, 1700 lines of code later we have a functional multi-type expression parser. There's still some function-calling functionality to add, but I can evaluate with proper operator precedence at least.
I've written similar things before, but not supporting multiple types. Thanks to thehell magic of templates, anything that has overridden operators in C++ is pretty easy to add as a new type, though all of the permutations of <type1> <operator> <type2> are entered manually - I can't really think of any good way to get around that.
Current built in types:
bool
int
float
VECTOR4
COORD4
EULER
QUAT
SQT
MATRIX4
Variables are bound from C++ and looked up by name, so we can directly read (or modify) values from the game. Currently there is just a single set of variables, but it should be pretty easy to allow multiple sets, so you could have something like a set of "global" variables, and then have some local to the game object or component the script is attached to.
There's quite a bit of template stuff going on, this is basically the core of storing values:
//The base class for storing anything with a result type
template <typename T>
class cTypedExpr : public cExpr
{
public:
virtual eType Type() const { return GetType<T>(); }
};
//Stores a constant of a specific type
template <typename T>
class cTypedConstant : public cTypedExpr<T>
{
public:
cTypedConstant(const T &v) : mValue(v) { }
virtual void Eval(cResult<T> &result) { result.mValue = mValue; }
T mValue;
};
//Stores a pointer to a type, and lets us get it as an l-value
template <typename T>
class cTypedIdentifier : public cTypedExpr<T>
{
public:
cTypedIdentifier(T *v) : mValue(v) { }
virtual bool IsLValue() const { return true; }
virtual void Eval(cResult<T> &result) { result.mValue = *mValue; }
virtual void LValue(cLValue<T> &result) { result.mValue = mValue; }
T *mValue;
};
If you're not familiar with compilers, an l-value is, basically, the left side of an assignment operation, so you need to get the memory address to write to, not just the value.
Hopefully I'll get this tied into the game in some useful way tonight.
Now, if I add for/while/if statements, and variable declarations, I'll have my own programming language...
Despite having some cough/cold thing going on, 1700 lines of code later we have a functional multi-type expression parser. There's still some function-calling functionality to add, but I can evaluate with proper operator precedence at least.
I've written similar things before, but not supporting multiple types. Thanks to the
Current built in types:
bool
int
float
VECTOR4
COORD4
EULER
QUAT
SQT
MATRIX4
Variables are bound from C++ and looked up by name, so we can directly read (or modify) values from the game. Currently there is just a single set of variables, but it should be pretty easy to allow multiple sets, so you could have something like a set of "global" variables, and then have some local to the game object or component the script is attached to.
There's quite a bit of template stuff going on, this is basically the core of storing values:
//The base class for storing anything with a result type
template <typename T>
class cTypedExpr : public cExpr
{
public:
virtual eType Type() const { return GetType<T>(); }
};
//Stores a constant of a specific type
template <typename T>
class cTypedConstant : public cTypedExpr<T>
{
public:
cTypedConstant(const T &v) : mValue(v) { }
virtual void Eval(cResult<T> &result) { result.mValue = mValue; }
T mValue;
};
//Stores a pointer to a type, and lets us get it as an l-value
template <typename T>
class cTypedIdentifier : public cTypedExpr<T>
{
public:
cTypedIdentifier(T *v) : mValue(v) { }
virtual bool IsLValue() const { return true; }
virtual void Eval(cResult<T> &result) { result.mValue = *mValue; }
virtual void LValue(cLValue<T> &result) { result.mValue = mValue; }
T *mValue;
};
If you're not familiar with compilers, an l-value is, basically, the left side of an assignment operation, so you need to get the memory address to write to, not just the value.
Hopefully I'll get this tied into the game in some useful way tonight.
Now, if I add for/while/if statements, and variable declarations, I'll have my own programming language...
Wednesday, August 21, 2013
Express yourself, August 21, 2013
Today has been off to a slow start. Mostly it has been reading a bunch of lighting papers and experimenting with an expression parser.
Oh, and I made a RenderCubeComponent to complement the RenderSphereComponent from yesterday (settle down, let's not get too excited).
I've been missing having a good expression parser, particularly with the heavily data-driven design I'm going with right now. I noticed that after doing all of the shader constant binding stuff yesterday that I need to specify that certain shader constants are bound to things that aren't actually constant (say, the camera View transform, for example).
I was using Lua to do expression parsing type things, but... let's say I've fallen out of love with Lua. It's a cute language, but I found it was taking a lot of effort to bind everything to Lua, and ultimatley the lack of strict type checking meant that nothing ever worked the first time. Ever. With C++, if it compiles, at least you stand a fair chance offinding out you're an idiot before running the game it working.
So, I've been spending the day trying to write a good expression parser. I want to basically just use a parse tree rather than some bytecode compiled thing. That basically means that you have a base class that looks something like:
class cExpr
{
public:
virtual void Eval(cResult &result) = 0;
};
and then a bunch of values or operators that derive from that:
class cBinOp : public cExpr
{
public:
cBinOp(cExpr *lhs, cExpr *rhs) : mLHS(lhs), mRHS(rhs) { }
cExpr *mLHS;
cExpr *mRHS;
};
class cMulOp : public cBinOp
{
public:
cMulOp(cExpr *lhs, cExpr *rhs) : cBinOp(lhs, rhs) { }
virtual void Eval(cResult &result) { cResult lhs; cResult rhs; mLHS->Eval(lhs); mRHS->Eval(rhs); result = lhs * rhs; }
};
OK, the details are bit more complex than that, particularly when you're talking about multiple types, and especially if you want to do any sort of assignment operations. But basically, once you've built a whole tree of operations, you just do one function call, a bunch of virtual function calls happen, and you get a result.
This can be expanded to execute a full language by making loop and flow control nodes as well - I'm not going to be doing that today.
Oh, and I made a RenderCubeComponent to complement the RenderSphereComponent from yesterday (settle down, let's not get too excited).
I've been missing having a good expression parser, particularly with the heavily data-driven design I'm going with right now. I noticed that after doing all of the shader constant binding stuff yesterday that I need to specify that certain shader constants are bound to things that aren't actually constant (say, the camera View transform, for example).
I was using Lua to do expression parsing type things, but... let's say I've fallen out of love with Lua. It's a cute language, but I found it was taking a lot of effort to bind everything to Lua, and ultimatley the lack of strict type checking meant that nothing ever worked the first time. Ever. With C++, if it compiles, at least you stand a fair chance of
So, I've been spending the day trying to write a good expression parser. I want to basically just use a parse tree rather than some bytecode compiled thing. That basically means that you have a base class that looks something like:
class cExpr
{
public:
virtual void Eval(cResult &result) = 0;
};
and then a bunch of values or operators that derive from that:
class cBinOp : public cExpr
{
public:
cBinOp(cExpr *lhs, cExpr *rhs) : mLHS(lhs), mRHS(rhs) { }
cExpr *mLHS;
cExpr *mRHS;
};
class cMulOp : public cBinOp
{
public:
cMulOp(cExpr *lhs, cExpr *rhs) : cBinOp(lhs, rhs) { }
virtual void Eval(cResult &result) { cResult lhs; cResult rhs; mLHS->Eval(lhs); mRHS->Eval(rhs); result = lhs * rhs; }
};
OK, the details are bit more complex than that, particularly when you're talking about multiple types, and especially if you want to do any sort of assignment operations. But basically, once you've built a whole tree of operations, you just do one function call, a bunch of virtual function calls happen, and you get a result.
This can be expanded to execute a full language by making loop and flow control nodes as well - I'm not going to be doing that today.
Tuesday, August 20, 2013
Special Bonus Post!
OK, I got my render-to-cube-map working. Apparently writing the comment "Save original transform" is not enough of a hint that I should "Restore original transform" once I'm done spinning the camera all over the place.
In celebration, I give you a Test Cube Map texture, with red, green and blue for X, Y and Z axes respectively, and a large, friendly +/- sign indicator.
I have the .dds too, but you can just make your own.
In celebration, I give you a Test Cube Map texture, with red, green and blue for X, Y and Z axes respectively, and a large, friendly +/- sign indicator.
I have the .dds too, but you can just make your own.
Base Metal Blog - August 20, 2013
So, since I had to do an airport run today, transport family members to classes and make supper, I'm running a little late today. Actually, I'm surprised I got any work done at all.
Since the previous post:
Before I do that, I may switch back to working on some of the AI components, considering that I need to make an actual game at some point. I had a really nifty swarming enemy type working, but I need it to actually shoot something a the player.
----------
Seen on Twitter:
Creative process: 1) This is going to be awesome 2) This is hard 3) This is terrible 4) I'm terrible 5) Hey, not bad 6) That was awesome
Since the previous post:
- Skybox rendering is working.
- I decided that a specific light probe component was not exactly what I needed. Because the camera component can render to a texture, it made more sense for the camera to detect when the render target was a cube map and render all six faces itself.
- The Build tool was getting log output out of order (for example, when the asset compiler called the shader compiler via a system call) - fflush(stdout) in the asset compiler before calling system() seems to fix that.
- Reworked the way cameras gather / sort game object. Each game object can has a 32-bit mask of layers it belongs to, and each camera can specify which layers it renders to. These were somewhat hard-coded previously, but because I'm using my Very Awesome Attribute File Format to store everything, it was pretty easy to make this data-driven.
- Added a simple Render Sphere component. Then realized I needed a good way to bind arbitrary shader constants so I can use any effect on the sphere, so built a system to specify any number of textures or shader constants in the attribute file and set them when the sphere is rendered.
Before I do that, I may switch back to working on some of the AI components, considering that I need to make an actual game at some point. I had a really nifty swarming enemy type working, but I need it to actually shoot something a the player.
----------
Seen on Twitter:
Creative process: 1) This is going to be awesome 2) This is hard 3) This is terrible 4) I'm terrible 5) Hey, not bad 6) That was awesome
Monday, August 19, 2013
Indie Dev Blog August 19, 2013
Originally when I started Base Metal Games, I thought I might blog more frequently about what exactly I'm doing. It seems like it's about time to get on with it. :)
I have been working on a game (and game engine) since February 2013. I keep a written journal of what I worked on each day, so I'll try to put a quick update on things I worked on today, interesting things I learned or figured out, or just general programming or game development thoughts.
I typically try to write something at 6:00pm PST each day, though my family schedule will probably make that highly unreliable.
So, what I did today, August 19, 2013:
It has been a day of cleaning up some of my build tools and working on some lighting code. I wrote a simple build tool in C# / WPF months ago, but never really got it to "useful" status. I finally patched it up, and now I hit one button and see the color-coded error log of my asset pipeline. The full log is in the top window, and errors/warnings are separated out in the bottom window.
I also got my auto-dependency checker working. It has been mostly working for months, but wasn't working recursively (for programs called from other programs) and was failing to account for missing files when doing the dependency check. Seems much better now. It's a pain to debug because it's using API hooking - basically, you "trick" the executable you want to load into replacing a bunch of the standard Windows functions with your own copies. This way, you can monitor what files your tool is trying to access and see if anything has changed the next time you run it. Very cool, a pain to debug.
Finally, I have been working on putting light probe and skybox rendering components into my component system. I moved by whole engine architecture to a component-based system a few weeks ago, and it has been really nice to work with. Perhaps more on that later...
I have been working on a game (and game engine) since February 2013. I keep a written journal of what I worked on each day, so I'll try to put a quick update on things I worked on today, interesting things I learned or figured out, or just general programming or game development thoughts.
I typically try to write something at 6:00pm PST each day, though my family schedule will probably make that highly unreliable.
So, what I did today, August 19, 2013:
It has been a day of cleaning up some of my build tools and working on some lighting code. I wrote a simple build tool in C# / WPF months ago, but never really got it to "useful" status. I finally patched it up, and now I hit one button and see the color-coded error log of my asset pipeline. The full log is in the top window, and errors/warnings are separated out in the bottom window.
I also got my auto-dependency checker working. It has been mostly working for months, but wasn't working recursively (for programs called from other programs) and was failing to account for missing files when doing the dependency check. Seems much better now. It's a pain to debug because it's using API hooking - basically, you "trick" the executable you want to load into replacing a bunch of the standard Windows functions with your own copies. This way, you can monitor what files your tool is trying to access and see if anything has changed the next time you run it. Very cool, a pain to debug.
Finally, I have been working on putting light probe and skybox rendering components into my component system. I moved by whole engine architecture to a component-based system a few weeks ago, and it has been really nice to work with. Perhaps more on that later...
Subscribe to:
Posts (Atom)