I haven't been around much lately. I'm suffering from strep throat and have been very sick for two weeks now. Fever, Pain in my throat and neck (swallowing and swollen glands) - penicillin destroyed my stomach - and 'finally' I got back and neck pain from lying down too much.. Headaches almost gone now and I'm back at work.. These last weeks have been pure hell for me.. Naturally - sadly - this means no work have been done, but like we say here in our team: 'real life wins' for better or for worse.
Illness..
April 28, 2008, 12:36 pmWOF nice old refernce gfx card passed away ...
April 18, 2008, 11:31 pm
my nice old nVidia Fx5200, that much of WOF was developed on / for, decided its time to go...


Materialization of a Mine Field
April 17, 2008, 1:40 pm
Source code, basically, is
the materialization of an idea, and the more complex the idea is the
more you see an explosion of possible ways to materialize it.
When in the process of materializing an idea (coding), multiple competing constraints emerge and try to influence the final materialized form.
Examples of constraints are performance, readability, maintainability, extensibility, time, elegance, typing economization and probably others as well.
This happens even when writing something as simple as the declaration of the function.
inline? virtual? pass arguments by reference? which arguments to pass? how to name the function, how to name the arguments, implement inside the header file?
each of those decisions can satisfy or break constraints and there is most often no way to satisfy all of them, and all we wanted is to declare a simple function.
One might thank that choosing which arguments to pass is obvious, but many times it is not, there are many variations and optional arguments that are handled and the decision has to be made to code many 'interfaces' to the function accepting slightly different arguments, this might satisfy readability constraints, but violate maintainability ones as I will in some examples at the end.
Moreover, the more the idea materializes, the more important 'piping' becomes, and the exact declarations start to become a big role, since nice 'piping' is also a very valid constraint. This means that it is not even possible to design beforehand a 'perfect' materialization, because the constraints we mention operate on the most microscopic level, and this would mean that the perfect design would need to go down to the lowest level, but then the design is the same as the actual coding, which beats the purpose of a high level design.
So all these decisions have to happen at the time of materialization (coding) and as soon as one form is chosen, some constraints are violated, this cannot be avoided, following the great wisdom of Japanese Anime Black Lagoon II: 'when you choose, you loose something', this is in fact unavoidable.
It is a really annoying fact, the better one wants to satisfy all constraints the more impossible it gets. This is a usual problem manifesting itself everywhere really, science, philosophy, every day life, everywhere really. One might say that achieving a balanced form which satisfies most of the chosen constraints for the current context is optimal, and yes this is what we usually strive for, but it is still, a compromise and we still 'loose something'.
The important thing however when it comes to coding is to be AWARE of the chosen constraints and of any compromises that were made, and the consequences of all the forms that were chosen.
Awareness puts us in control instead of being unknowingly controlled by constraints sitting in our sub-conscious mind (readability freak, micro-optimization freak, code elegance freak, ...) and allows us to walk through the mine field with a headlight and a baseball bat, instead of blindly stepping on the mines totally unarmed.
In the examples, and yes they are almost ridiculous, I chose very simple functions, and one might think that this is exaggerated, but one can notice that at every example decision some constraint were broken in the favor or others and hence a compromise was made.
Example1:
1. float dist(const Vector3 &a, const Vector3 &b);
nice and short, however, 'distance' is more precise, more readable, but needs more typing ...
2. float distance(const Vector3 &a, const Vector3 &b); //more readable
but it is more performant to determine the squared distance and it is all whats needed in many cases
float distanceSquared(const Vector3 &a, const Vector3 &b);
this is too much typing
float distSq(const Vector3 &a, const Vector3 &b);
this is too cryptic
float distanceSq(const Vector3 &a, const Vector3 &b);
but how to implement this?
inline float distance(const Vector3 &a, const Vector3 &b) { return sqrtf(distanceSq(a, b); }
but makes the header file look dirty, let the compiler do the inline optimization for us
float distanceSq(const Vector3 &a, const Vector3 &b); //implemented inside .cpp
Example2:
1. float distance(const Vector3& segA, const Vector3& segB, const Vector3& pt);
segA? what's that? too cryptic
2. float distance(const Vector3& segmentPointA, const Vector3& segmentPointB, const Vector3& point);
that cost more typing, but ok, now I have an Idea why don't we write it like this?
3. float distance(const Segment& segment, const Vector3& point);
let's make this cleaner and move it into the Segment class.
3. float Segment::distance(const Vector3& point);
but sometimes the code needs to compute the distance directly from 2 points, without having a segment,
but we still want this version, saves typing when dealing with segments.
4. inline float distance(const Segment& segment, const Vector3& point) { ... }
or
inline float Segment::distance(const Segment& segment, const Vector3& point) { ... }
now we need that squared version again
5. float distanceSq(const Vector3& segmentPointA, const Vector3& segmentPointB, const Vector3& point);
but now we need to maintain 2 functions that do the same because of decision 3, so now we need to add
6. inline float distanceSq(const Segment& segment, const Vector3& point) { ... }
that's all!!, but no wait, many times, we need to extract the closest point at the same time, ok, add
5. float distanceSq(const Vector3& segmentPointA, const Vector3& segmentPointB, const Vector3& point, ector3& closestPt);
but wait, we can merge the 2 to have less maintenance into
6. float distanceSq(const Vector3& segmentPointA, const Vector3& segmentPointB, const Vector3& point, Vector3* pClosestPt = NULL);
but that costs the callers that don't need to calculate the closest point some performance.
doesn't matter, this is good enough.
there is one more thing though sometimes all we need is the resulting interpolation value 'u',
specially when using this implementation:
float u = ((point.x - segmentA.x)*(segmentB.x - segmentA.x) + (point.y - segmentA.y)*(segmentB.y - segmentA.y) + (point.z - segmentA.z)*(segmentB.z - segmentA.z))
/ ((segmentB.x - segmentA.x)*(segmentB.x - segmentA.x) + (segmentB.y - segmentA.y)*(segmentB.y - segmentA.y) + (segmentB.z - segmentA.z)*(segmentB.z - segmentA.z));
interpolate using u
no need to calculate the exact closest point... ok
7. float distanceSq(const Vector3& segmentPointA, const Vector3& segmentPointB, const Vector3& point, float& u);
or maybe
8. float distanceSq(const Vector3& segmentPointA, const Vector3& segmentPointB, const Vector3& point, float* pU = NULL);
or even
8. float distanceSq(const Vector3& segmentPointA, const Vector3& segmentPointB, const Vector3& point, float* pU = NULL, Vector3* pClosestPt = NULL);
nah, too much checking NULL pointers, so better write many versions, but that's more annoying to maintain
9. ......................you get the point, and those are only declaration of simple functions................
When in the process of materializing an idea (coding), multiple competing constraints emerge and try to influence the final materialized form.
Examples of constraints are performance, readability, maintainability, extensibility, time, elegance, typing economization and probably others as well.
This happens even when writing something as simple as the declaration of the function.
inline? virtual? pass arguments by reference? which arguments to pass? how to name the function, how to name the arguments, implement inside the header file?
each of those decisions can satisfy or break constraints and there is most often no way to satisfy all of them, and all we wanted is to declare a simple function.
One might thank that choosing which arguments to pass is obvious, but many times it is not, there are many variations and optional arguments that are handled and the decision has to be made to code many 'interfaces' to the function accepting slightly different arguments, this might satisfy readability constraints, but violate maintainability ones as I will in some examples at the end.
Moreover, the more the idea materializes, the more important 'piping' becomes, and the exact declarations start to become a big role, since nice 'piping' is also a very valid constraint. This means that it is not even possible to design beforehand a 'perfect' materialization, because the constraints we mention operate on the most microscopic level, and this would mean that the perfect design would need to go down to the lowest level, but then the design is the same as the actual coding, which beats the purpose of a high level design.
So all these decisions have to happen at the time of materialization (coding) and as soon as one form is chosen, some constraints are violated, this cannot be avoided, following the great wisdom of Japanese Anime Black Lagoon II: 'when you choose, you loose something', this is in fact unavoidable.
It is a really annoying fact, the better one wants to satisfy all constraints the more impossible it gets. This is a usual problem manifesting itself everywhere really, science, philosophy, every day life, everywhere really. One might say that achieving a balanced form which satisfies most of the chosen constraints for the current context is optimal, and yes this is what we usually strive for, but it is still, a compromise and we still 'loose something'.
The important thing however when it comes to coding is to be AWARE of the chosen constraints and of any compromises that were made, and the consequences of all the forms that were chosen.
Awareness puts us in control instead of being unknowingly controlled by constraints sitting in our sub-conscious mind (readability freak, micro-optimization freak, code elegance freak, ...) and allows us to walk through the mine field with a headlight and a baseball bat, instead of blindly stepping on the mines totally unarmed.
In the examples, and yes they are almost ridiculous, I chose very simple functions, and one might think that this is exaggerated, but one can notice that at every example decision some constraint were broken in the favor or others and hence a compromise was made.
Example1:
1. float dist(const Vector3 &a, const Vector3 &b);
nice and short, however, 'distance' is more precise, more readable, but needs more typing ...
2. float distance(const Vector3 &a, const Vector3 &b); //more readable
but it is more performant to determine the squared distance and it is all whats needed in many cases
float distanceSquared(const Vector3 &a, const Vector3 &b);
this is too much typing
float distSq(const Vector3 &a, const Vector3 &b);
this is too cryptic
float distanceSq(const Vector3 &a, const Vector3 &b);
but how to implement this?
inline float distance(const Vector3 &a, const Vector3 &b) { return sqrtf(distanceSq(a, b); }
but makes the header file look dirty, let the compiler do the inline optimization for us
float distanceSq(const Vector3 &a, const Vector3 &b); //implemented inside .cpp
Example2:
1. float distance(const Vector3& segA, const Vector3& segB, const Vector3& pt);
segA? what's that? too cryptic
2. float distance(const Vector3& segmentPointA, const Vector3& segmentPointB, const Vector3& point);
that cost more typing, but ok, now I have an Idea why don't we write it like this?
3. float distance(const Segment& segment, const Vector3& point);
let's make this cleaner and move it into the Segment class.
3. float Segment::distance(const Vector3& point);
but sometimes the code needs to compute the distance directly from 2 points, without having a segment,
but we still want this version, saves typing when dealing with segments.
4. inline float distance(const Segment& segment, const Vector3& point) { ... }
or
inline float Segment::distance(const Segment& segment, const Vector3& point) { ... }
now we need that squared version again
5. float distanceSq(const Vector3& segmentPointA, const Vector3& segmentPointB, const Vector3& point);
but now we need to maintain 2 functions that do the same because of decision 3, so now we need to add
6. inline float distanceSq(const Segment& segment, const Vector3& point) { ... }
that's all!!, but no wait, many times, we need to extract the closest point at the same time, ok, add
5. float distanceSq(const Vector3& segmentPointA, const Vector3& segmentPointB, const Vector3& point, ector3& closestPt);
but wait, we can merge the 2 to have less maintenance into
6. float distanceSq(const Vector3& segmentPointA, const Vector3& segmentPointB, const Vector3& point, Vector3* pClosestPt = NULL);
but that costs the callers that don't need to calculate the closest point some performance.
doesn't matter, this is good enough.
there is one more thing though sometimes all we need is the resulting interpolation value 'u',
specially when using this implementation:
float u = ((point.x - segmentA.x)*(segmentB.x - segmentA.x) + (point.y - segmentA.y)*(segmentB.y - segmentA.y) + (point.z - segmentA.z)*(segmentB.z - segmentA.z))
/ ((segmentB.x - segmentA.x)*(segmentB.x - segmentA.x) + (segmentB.y - segmentA.y)*(segmentB.y - segmentA.y) + (segmentB.z - segmentA.z)*(segmentB.z - segmentA.z));
interpolate using u
no need to calculate the exact closest point... ok
7. float distanceSq(const Vector3& segmentPointA, const Vector3& segmentPointB, const Vector3& point, float& u);
or maybe
8. float distanceSq(const Vector3& segmentPointA, const Vector3& segmentPointB, const Vector3& point, float* pU = NULL);
or even
8. float distanceSq(const Vector3& segmentPointA, const Vector3& segmentPointB, const Vector3& point, float* pU = NULL, Vector3* pClosestPt = NULL);
nah, too much checking NULL pointers, so better write many versions, but that's more annoying to maintain
9. ......................you get the point, and those are only declaration of simple functions................
'Experienced' AI
April 3, 2008, 3:45 pm
Since some time, and you would know it if you have been following our blog, we are at the stage of working on WOF's AI since the basic gameplay mechanics are finally in place.
We had a first 'flirt with AI' iteration and posted videos of the results.
We are now at the second iteration which should already produce some useful fun-playable behavior. I decided to start with the goalie. after some coding and much thinking I came to the conclusion that I will probably have to include some AI 'experience' that the AI footballers' brains will be able to use.
The reasons for this are simple: without this, a goalie's brain would be running full steam the whole time trying to estimate and reestimate the same things. things that real life goalies know by 'experience' because when a footballer steps in the pitch ... he has years of playing experience and training behind him ... can this be simply discarded? well yes and no.
If we choose to give the footballers no experience, they will need much more processing power to compute potential ball positions after shots, potential shots to make, how dangerous a shot could be given the situation..... it's possible but both expensive in terms of processing power and therefore hurting game performance, too 'machinistic' in terms of precision ...
the footballer would be able to estimate to with exact precision if per example the goalie can catch a ball if it was shot in some way, but also and on a finer level probably too predictable for the human player who would then find a situation where he could score once and repeat it forever because the AI would never try to fix whatever went wrong with their estimation.
Now how on earth do we give our AI experience?
A neural network brain comes to mind ... a brain that knows nothing at first and is trained through a huge number of iterations until it has learned something... but nahhhh its too unpredictable, fragile, uncontrollable, unmoddable and is better left as an exercise to academics. the goal here is a fun game ...
I will try to use some time at load time, before the match starts, and use it to make the AI learn a bit about what shots can be made using the current match situation (ball paramters, pitch parameters, player characteristics) and they will then be able to use this as 'experience' and in a totally human way act based on approximations and even try to fine those approximations when they find they didn't work.
its more or less like sending the team to the pitch for a short training before the game, so that they get their brains in-tune with the match's parameters and so that u don't play against a totally 'unexperienced machine precise hard coded AI' team.
I hope it will work well. this might again take some time ... but it is a topic of huge importance!
so until the next vids, stay tuned!
We had a first 'flirt with AI' iteration and posted videos of the results.
We are now at the second iteration which should already produce some useful fun-playable behavior. I decided to start with the goalie. after some coding and much thinking I came to the conclusion that I will probably have to include some AI 'experience' that the AI footballers' brains will be able to use.
The reasons for this are simple: without this, a goalie's brain would be running full steam the whole time trying to estimate and reestimate the same things. things that real life goalies know by 'experience' because when a footballer steps in the pitch ... he has years of playing experience and training behind him ... can this be simply discarded? well yes and no.
If we choose to give the footballers no experience, they will need much more processing power to compute potential ball positions after shots, potential shots to make, how dangerous a shot could be given the situation..... it's possible but both expensive in terms of processing power and therefore hurting game performance, too 'machinistic' in terms of precision ...
the footballer would be able to estimate to with exact precision if per example the goalie can catch a ball if it was shot in some way, but also and on a finer level probably too predictable for the human player who would then find a situation where he could score once and repeat it forever because the AI would never try to fix whatever went wrong with their estimation.
Now how on earth do we give our AI experience?
A neural network brain comes to mind ... a brain that knows nothing at first and is trained through a huge number of iterations until it has learned something... but nahhhh its too unpredictable, fragile, uncontrollable, unmoddable and is better left as an exercise to academics. the goal here is a fun game ...
I will try to use some time at load time, before the match starts, and use it to make the AI learn a bit about what shots can be made using the current match situation (ball paramters, pitch parameters, player characteristics) and they will then be able to use this as 'experience' and in a totally human way act based on approximations and even try to fine those approximations when they find they didn't work.
its more or less like sending the team to the pitch for a short training before the game, so that they get their brains in-tune with the match's parameters and so that u don't play against a totally 'unexperienced machine precise hard coded AI' team.
I hope it will work well. this might again take some time ... but it is a topic of huge importance!
so until the next vids, stay tuned!
Kimera Studios site updated..
April 1, 2008, 7:38 pm
Page :
1







