Jump to content

  • Log In with Google      Sign In   
  • Create Account


Member Since 10 Oct 2005
Online Last Active Today, 01:35 PM

#5177265 Animation Manager ?

Posted by haegarr on 31 August 2014 - 01:52 PM

The details need attention, as always, and there are often more than a single way to do things.


For forward movement, how is the frame determined for all of the animations? Is there an animation frame index for each of the 3 at once, or are they expected to all be the same length and match. So at frame 5 the right leg is up in walk and the right leg is also up in the run animation. Otherwise the blending wouldn't work?

Let the moveWalk animation have a length of 2 seconds for a single cycle. After this 2 seconds the animation loops and hence starts at the beginning. If forwardSpeed has the value of 3, the animation is played at nominal speed, i.e. one cycle in 2 * 3 / 3 = 2 seconds. If forwardSpeed is 1.5 (the half value), then the full cycle of the animation need to be played in 2 * 3 / 1.5 = 4 seconds (the double value). If forwardSpeed has the value of 4.5, the full cycle lasts 2 * 3 / 4.5 = 1.33 seconds. This means that the animation is played back with an adapted speed.


The same is true for the moveRun animation, but here the duration of a cycle is, say, 1 second. Again, this duration is defined for the nominal forwardSpeed of 6. So, when forwardSpeed is 4.5, the full cycle just lasts for 1 * 6 / 4.5 = 1.33 seconds which is, not by accident, the same duration of a full cycle of moveWalk when forwardSpeed is 4.5.


Fine so far, but not enough to make the animation look good when moveWalk and moveRun are blended. It is also required that the both animation run in the same motion phase. E.g. both animations have the left foot on the ground at the beginning and at the end of the cycle, and both have the right foot on the ground in the middle of the cycle. In other words, both animations are in the same motion phase for a given percentage of the cycle.


How keyframes are distributed over a cycle is not important in this sense. Both the cycles of moveWalk and moveRun may have a different count and/or spacing of keyframes. The distribution of keyframes depends only on the question of motion quality. Thing is, you need to use the accordingly adapted animation time.


For the meleeAttack, when the condition is false it does 2 things, 1) it doesn't blend anything into the animation 2) it sets the frame index to -1, so when the condition becomes true and the frame is incremented it'll be "0"?

1) Yes, the meleeAttack is needed to be suppressed.

2) When the animation is triggered, its local playback time can be reset, so ever staring at 0.


So rather than using a state machine to manage the animation, it'd be possible to use a state machine to manage the objects state. So if i am in a state "climbing wall", that state would make sure meleeAttack's condition is set to false as you can't melee while climbing a wall?

It is okay to combine all this with a state machine, where blend trees are embedded in nodes. For example, "normal" and "climbing" are states, where the state "climbing" may be entered only if forwardSpeed is 0, so that the "normal" state would show idleStand.

#5177239 Animation Manager ?

Posted by haegarr on 31 August 2014 - 12:05 PM

So as an example, i choose the animation "running melee" and then i go to the blend tree which defines "running melee" as the two animations "running" and "melee" and mixes them (or in my case overwrites the needed nodes with the melee animation)? I might be getting that wrong, but how would the blend tree know then which frame the running is on and which frame the melee is on? Maybe that's a bad example on my part...

Let us say there are the animations idleStand, moveWalk, moveRun, leanLeft, leanRight, meleeAttack.


The first thing to do is to use a variable forwardSpeed to mix the animations idleStand, moveWalk, moveRun by blending so that e.g. for a speed greater or equal 0 and lesser than 3 the animations idleStand and moveWalk, and for a speed greater or equal 3 and lesser then 6 (the maximum speed) the animations moveWalk and moveRun are blended. The blend weights are then computed e.g. like so:

    w_idleStand = ( forwardSpeed < 3 ) ? ( 1 - forwardSpeed / 3 ) : ( 0 )

    w_moveWalk = ( forwardSpeed < 3 ) ? ( forwardSpeed / 3 ) : ( 1 - ( forwardSpeed - 3 ) / 3 )

    w_moveRun = ( forwardSpeed < 3 ) ? ( 0 ) : ( ( forwardSpeed - 3 ) / 3 )

This would be the job of the "move forward" branch of the animation tree.


The next would be to use a variable lean to mix the result from above with either leanLeft or leanRight. It may be implemented as an additive animation, or perhaps also by linear blending with appropriate weights.


With the above set-up the entire skeleton is animated (e.g. also the upper body and the arms are animated accordingly). Now when the meleeAttack animation comes into play, it should override what the above animation defines for upper body and arms. This is done by defining a new layer for meleeAttack. This layer works on the upper body and the arms only, not on the legs. One possibility to implement the layering is to give each part (or perhaps each bone) and contingent of 100%. If a layer write animation data to a part / bone, then the contingent is reduced by a defined amount. Any layer below is allowed to mix in as much as the remaining contingent says.


An example: At the beginning of computing the pose, the contingent is initialized with 100%. The top layer with the meleeAttack is not playing, so the contingent is not reduced. The lower layer where the forward movement is handled has 100% control over the entire body. Later on the meleeAttack is triggered. The upper layer takes control of the parts upper body and arms, sets them into an appropriate pose, and reduced the contingent by, say, 95%. So the lower layer with the forward movement is able to influence the upper body and arms with just 5%. For a total override a layer would reduce the contingent by 100%, of course.


Seen as an animation tree, we have 3 leaf nodes with the animations idleStand, moveWalk, and moveRun. These 3 nodes are the leafs of a one axis linear blend node. The output of that blend node is forward movement. Further we have 3 leaf nodes for the animations leanLeft, leanRight, and Identity. These nodes are the leafs of a blend node which effectively selects one if its children. Both the forward movement and leaning nodes are children of an additive blend node. Further we have a leaf node with meleeAttack. Both the output of the additive blend node and the meleeAttack node are children of a layering node parametrized as described above.


As can be seen from this description, animations are not directly chosen. Instead, the animation parameters are set accordingly to the situation. E.g. the forwardSpeed variable is set to 1.5, the leaning variable to -0.25, and the attack variable to true. These settings are driven from the player controller in the case of the PC or from the animation controller in case of an NPC.



EDIT: BTW, all this does not mean that a state machine cannot be useful. Just notice that a state machine is good for discrete distinctions (the states), while the mechanisms described above easily allow for continuos mixing.

#5177230 Animation Manager ?

Posted by haegarr on 31 August 2014 - 11:05 AM

As an example, for a 3d character. "Static" would be something like a running animation. Overwrite would be something like a melee (so you can run and hit something at the same time). Additive would be aiming, the rotation of the head and arms to modify depending on where you are aiming.
So now there are some conflict as when a melee animation is happening, then there shouldn't be any aiming, otherwise it would distort the melee animation.
I know i've read about state machines but i can't wrap my head around some ideas. ...

Look for the keywords

* animation blending: mixing animations on the same parts using weights,

* animation layering: overriding animations or suppressing them,

* animation masking: applying an animation only to the parts that are marked (e.g. specific body parts of a skeleton).


A state machine is useful to select animations, but its isn't useful for the mentioned purposes. The construct to control above mechanisms is often called animation tree or blend tree.

#5176156 FBO: Render to Texture not working!

Posted by haegarr on 26 August 2014 - 03:10 AM

A guess: Are width and height both POTs? You use GL_TEXTURE_2D as attachment. Maybe you need to use GL_TEXTURE_RECTANGLE.


I see that you speak of "doubling 320 x 480" ... that may hint at that they are not POTs.

#5176145 FBO: Render to Texture not working!

Posted by haegarr on 26 August 2014 - 01:44 AM

1.) In create_render_target you are creating a render buffer as well as a texture, and attach both to the same attachment point COLOR_ATTACHMENT0. That makes no sense. Use a render buffer or else a texture for a single attachment point. Since you probably want to use the result later for mapping, it should probably be a texture.


2.) Does rendering require depth buffer? Your FBO lacks a depth buffer.



EDIT: No really related to the problem, but glBindFrameBuffer( GL_FRAMEBUFFER, 0 ) should also be invoked when returning due to an incomplete buffer.

#5176033 room escape engine

Posted by haegarr on 25 August 2014 - 12:02 PM

What exactly is a room escape game?


When looking at the game you referenced in the OP, it seems me to use the classic point-&-click graphic adventure mechanics. So perhaps ... you may find the Adventure Game Studio fit your needs.

#5175972 How to program tile transitions (C++/SFML)

Posted by haegarr on 25 August 2014 - 05:10 AM

A possible technique for what Servant describes is named texture splatting. It can be done with a manually generated map but also with a map derived automatically from the surrounding tiles. The latter process is described in detail in Charles Bloom's good ol' article here.

#5175950 Storing level data in grids

Posted by haegarr on 25 August 2014 - 02:19 AM

I want to place a new room I've created on the [--] grid, and I can't for the love of God figure out how the heck do I automate the process of linking the new room to the rooms below and right side. ...

We're speaking of editor functionality here. What programming language do you use to program the editor? I'm using some pseudo code in the following:


Possibility 1: 2D array


Allocate a 2D array with the size specified within the level creation dialog, say N by M cells. The array stores pointers to Room structure instances. Initially the array elements are all set to nil, denoting that no room is associated with that cell. Each cell in the grid uses 2 numbers as address, directly useable as index into the 2D array. If a new room is placed at index (n,m), then the editor checks for neighbored rooms as follows:

if (n>0 and array2d[n-1, m] != nil ) then "room to the left exists";
if (n<N-1 and array2d[n+1, m] != nil ) then "room to the right exists";
if (m>0 and array2d[n, m-1] != nil ) then "room above exists";
if (m<M-1 and array2d[n, m+1] != nil ) then "room below exists";

What "room ... exists" may mean is explained below.


Possibility 2: 1D array


Perhaps 2D array are not your friend. There is this little trick with calculates a 1D array index from a 2D index. For a grid of N by M cells, an index (n,m) can be used to calculate

i := n * M + m

or alternatively

i := m * N + n

for an array of size N*M, of course.


Since this just is the indexing scheme, it can be hidden up until directly accessing the array, so the usage is the same as in possibility 1.


Possibility 3: associative map


The standard library of your programming environment supports an associative container, usually called a map or sometimes also dictionary. Such a map associates a key with a value. The key is the 2D index like above, or perhaps better the 1D index as shown above, while the value is a Room structure instance. A map has as many entries as rooms actually exist (as opposed to an array which has as many entries as cells are specified, i.e. equal to the amount of possibly existing rooms).


Asking a map for the existence of a room is a bit easier since an "index out of bounds" cannot occur. 

if (map(index(n-1, m)) != nil ) then "room to the left exists";
if (map(index(n+1, m)) != nil ) then "room to the right exists";
if (map(index(n, m-1)) != nil ) then "room above exists";
if (map(index(n, m+1)) != nil ) then "room below exists"; 

Again, what "room ... exists" may mean is explained below.


Possibility 4: sequence / vector


This possibility uses a self growing linear storage. As opposed to an array solution, there is not an entry for each cell but only for each existing room. The Room structure itself has a field that stores its own 2D or 1D index. Whenever you want to know whether a room exists, you iterate the sequence and compare the values of the stored room index fields with the given index. If such search is implemented as routine "lookup", it looks like so:

if (seq.kookup(n-1,m) != nil) then "room to the left exists";

And now ...


"room ... exists" in detail


So, when the above code enters an "room ... exists", you have to store the link correct inside the Room structure. Again, I don't know how this link should look like. You may store the pointer to the other room directly, or the 2D or 1D index. If we use "storage" for one of the possibilities shown above, that may look like so: 

if (storage(n, m))
    then "there is already a room in that cell"
    else {
        Room* newRoom = createRoom(n, m);
        Room* neighbor = nil;
        // looking to the left ...
        neighbor = storage(n-1, m);
        if (neighbor != nil)
            then {
                newRoom.leftNeighbor = neighbor;
                neighbor.rightNeighbor = newRoom;
        // looking to the right ...
        neighbor = storage(n+1, m);
        if (neighbor != nil)
            then {
                newRoom.rightNeighbor = neighbor;
                neighbor.leftNeighbor = newRoom;
        ... similarly for above and below ...

#5175773 Storing level data in grids

Posted by haegarr on 24 August 2014 - 04:50 AM

I'm quite not sure what your goals are. The original mechanics seems me to be a 2D map (called "room") in side view, build by predefined tiles, a non moving sight, where explicitly modeled exits are used to switch over to the next room. You want a concept where switching rooms is no longer done, but the sight is moving so that the player avatar is more or less centered on the screen every time, and portions of the level (e.g. formerly other rooms) scroll in synchronous to the movement.


First issue may be that you deprive yourself of going into the 3rd dimension. An explicit exit may not only lead up, down, left, or right, but also backwards and forwards, and it allows to use an elevator or stairs in the backdrop (I remember such a feature in this kind of games).


Second issue is that, although you don't need exits from room to room in a level if you simply follow the concept "one room one level", you still have to model the transit from one level to the next.


Now coming to the question of how to store the data.


First of, notice that the data format in the editor and the data format in the game need not be identical. If you think about the different requirements in those use cases, you probably see that a structure suitable for the one case is not so suitable in the other. In the editor, you want to check whether a place is covered, move tiles around, check for validity / playability, and so on. During gameplay you are interested in whether movement in a direction is possible, a trigger must be fired, and so on. This means that the editor need to either distinguish between saving a project from saving a game level, or it needs to interpret the data in another way than the game engine.


Second, you have to decide whether you want to use blobs or regular structures. In the former case you load the level data and that's it. This is called "in-place loading". It shortens load time (okay, not to do much in that kind of game anyhow) since preparation is already done by the editor before saving, but it may require a more sophisticated addressing scheme. The latter case (regular structures) means to load data into a buffer, and building a new structure from it during interpreting the data. For example, you make a std::map (when using C++) from it, where the key in the map is given by the tile index.


Third, you have to think on the density of the map: How many holes may be there (i.e. where no tile is placed simply because the player cannot reach that tiles anyway)? A full grid makes sense mainly if holes are rare and small. For a sparsely covered map a linking scheme would be more efficient.


In a game like shown probably neither load time nor memory footprint are hard conditions, so probably any way will work. My personal preference is to "compile" editor data into game data, and to use in-place loadable blobs for game data.


... a way on doing this without changing how the old level works ...

What features exactly you want to preserve?

#5175193 Storing level data in grids

Posted by haegarr on 21 August 2014 - 01:59 AM

Explicitly modelled exits (and perhaps also entrees) grants a much greater flexibility:

1.) They allow the rooms to be stored in sequence in any order, since the rooms are linked.

2.) They allow also for not having an exit on a particular side.

3.) They allow to have more than a single exit on a particular side.

4.) They simply support for varying room forms and sizes.

5.) They give you a natural place where door locking happens.

6.) They give you a natural place for "look at exit" belonging data (if your game allows for that).

7.) They give you a place where specific onExit and onEnter handlers can be placed.


They allow for some spurious behavior, too:

8.) Conditional re-linking allows magic passages or adaptable mazes.

9.) Random choose from a set of entrees attached to a specific exit allows for spurious room sequels.


That said, I would not drop the mechanism of explicit exits / entrees without a good reason. However, you don't gave any detail in your opening post, so I may not aware of such good reasons you may have.

#5174945 Does a red and white RCA plug to 3.5mm keep stereo or does it go to mono?

Posted by haegarr on 20 August 2014 - 01:59 AM

You need both the white and the red plugs to be connected to get a stereo signal. If you connect only one you don't get the mono signal but just the left or right signal alone (a correct mono signal would be another mix of left and right signals).


Because such low frequencies as are emitted by subwoofers cannot be spatially located by humans, a subwoofers is not supplied with a stereo signal. However, a subwoofer is usually supplied with a signal preprocessed especially for it. I do not expect that plugging in a half stereo signal would do at all, regardless of potential signal level probelms and such.

#5174705 Weapon statistics visualization

Posted by haegarr on 19 August 2014 - 06:28 AM

I'm...not sure i see where you are going with this.

I'm just looking for an alternative way...


The background fact is: The player, using a given weapon, needs N seconds in average to destroy an enemy. Here N depends on the fire rate, momentum, and probability of hitting the (same) target. You don't want to express those values as numbers.


Although two weapons may show the nearly the same value for N, they may be differently effective because of the situation. A distant enemy may be shot with a sniper rifle which has a low fire rate but high precision. Due to the distance the player has enough time, and s/he doesn't waste ammo because the spread is low. So that weapon is fine for the situation of a distant enemy, and hence it may be memorized as such.


The other weapon is a machine gun, showing a much higher fire rate but also a much higher spread. Using it against a distant enemy will kill it also in N seconds (that was our condition), but at the costs of running out of ammo. So it isn't suited for this situation. However, if the situation is that the enemies approach in a throng and are relatively close, then a sniper rifle is too slow, and spreading is an advantage if each damage will slow down the hit enemy.


That said, I'd select the weapon based on the situation. Whether weapon A and weapon B differ just in N and 1.01*N is mostly irrelevant in a game (if it is though, like in a quartet, then perhaps using number is the best choice). So the alternative idea was to let the player test the weapons and classify them suitably for the situations the game may throw them into.

#5174682 Weapon statistics visualization

Posted by haegarr on 19 August 2014 - 05:16 AM

Don't know about your setting. I just throw some ideas around ;)


How does the player equip the avatar with armor? Are already pictures / representations used for this, which may be re-used for above purposes? Is it possible to introduce how hostile armor looks like during, say, a briefing?


Some situation dependent icons (for which also optical variations may exist):

 * A helmet for trench warfare,

 * a bulletproof vest for street fight,

 * a shield for defending a storming,

 * a metal plate for ironclad armor,

 * a crosshairs for sniping,

 * ...

#5174659 Weapon statistics visualization

Posted by haegarr on 19 August 2014 - 03:45 AM

It can be perhaps combined with training. E.g. in training with a weapon one actually learns to use it and how effective it is by shooting selected armor instead of dummies. A trainer may tell you something about the weapon, too, so that a preselection can be established.


During gameplay, the "statistics" may then be displayed as "effective against" with some thumbnail images of armor types. The player may also be allowed to use such an icon based system for memorizing their own preferences, e.g. a "use in case of" field can be populated with icons of armor at own decision.

#5174447 How to react on KeyPress + Release?

Posted by haegarr on 18 August 2014 - 08:25 AM

After the first run through display() both keyStates and keyPreviousState point to the same memory area. You probably want to use memcpy to copy the memory area pointed to by keyStates to the memory area pointed to by keyPreviousStates, but actually you copy the pointer keyStates to keyPreviousStates.


EDIT: To avoid such problems and clearly denote the situation, you should use const to make the variables read-only, in this case

bool* const keyStates = new bool[256]();
bool* const keyPreviousStates = new bool[256]();

Notice that this does not make the array elements read-only but just the pointers themselves.