Skullstone - a dungeon crawler game

Original soundtrack by Popiół Kurhanów. Enjoy!

8 Likes

Amazing! keep working!

There can’t be a dungeon game without doors locked by keys! So let’s do it here:

You can see a basic model of a keyhole in front of you and a key on the floor.

And now something about ‘programming the dungeons’:
To the right, in editor I have a simple line that connects keyhole with the doors. Both are treated as 2-state-machines, this simple line moves (M) the state from first machine ([XY:3|6,EE,KH]) to the second ([XY:3|7,NO,D]) without negation (0).

There are other types of ‘programs’: timers, locks and one, that I’m not sure how to translate: Object A is checking the state of B and if the state is different it switches to B’s stat after certain amount of time.

2 Likes

It’s time to spawn some mobs. Our testrobo is the first one!

We have our own GameTime controller with pause ability, so the animations needs to be paused when we enter game menu. Overriding AnimControl is not a solution, too much work. I need the pause to be made without any effort from my side.
I do it in simple way. From the begining… all objects on game scene are placed with some order: walls, pillars, ceiling and floor on _structNode, items on _itemNode, ‘on-wall-items’ on _wallNode etc. Because only Items and obejects placed on walls can have controllers I made an extended node with overriden updateLogicalState, which simply does not call its super method. I don’t like to waste CPU, so the idea is simple. Now, I need to AnimControl’s update be executed only when the GameTime is not paused, so I made a similar trick with node - mob’s node calls its super method only when the GameTime is running.

In the meantime I solved the problem introduced here: Skullstone - a dungeon crawler game - #28 by FrozenShade
How to detect an animated object as fast as possible? Trying to check if there is an AnimControl is not an solution, UserParam is not an solution, both are slow because they need to check too much (list, parent etc). The most simple solution is to mark such geometries with special name - if the shadow renderer find a geometry with name starting from char ‘_’ it will render the shadow, otherwise it will do all it’s optimization tests.

Some time ago I read that realtime computer graphics is essentially one giant dirty hack. I agree :wink:

4 Likes

Nothing special this time, just a simple pathfinding algorithm… see the map.

Now, as we wrote before, we are working on mobs. It’s not only models and animations, but AI as well, and pathfinding is just a part of it. Simple AI will allow mob to choose an destination point and walk to that point. When he see the player, he will ‘aggro’ and try to chase/attack the player. Every damage will increase aggro points, that points will decrease over time, which will allow mob to just give up.
Mobs will have ‘emotions’, a special animations triggered in certain situations. For example: if the mob does nothing he would animate ‘boring’ emotion, if he have aggro and see the player but can’t reach him (the player is behind the closed doors) he would be ‘angry’.

This time I played with graphics once again. Nothing special to be honest, just an mob status. I was able to extend my base Gui component so it can work like an status graphics. It shows the actual hp bar (temporary version) and damage the mob was taken. Custom shader makes the damage slowly disappearing and floating up, till it is not visible at all, so I can have a nice effect without repainting the texture.

Here is the SS:

2 Likes

@FrozenShade : I like what you did with the lights and shadows. I already see an “atmosphere” in your screenshots.
Which kind of mobs are you looking for ? Maybe there is one I made for my game which may fit in yours. Some kind of demon with a hole in the chest/abdomen. Just PM me if you want to and I’ll show you.

Finally, the deferred rendering:

http://postimg.org/image/u7dlrp90j/

It looks even better than on forward rendering. Ignore the bug with the light ray in the hole, it is fixed already. The difference in performance is not visible all the time but only on well lightened places of course.

Looks nice,

Sooo,
what defered system are you using?
Any chance in getting some code for it ? XD

I’ll think about sharing. For now the code is too dirty and it requires custom renderers on the java side.

I don’t understand the question.

Well deferend shading, vs deferend rendering? How do you handle transparencies, ect :smile:
Just interested in what choices you made.

Transparencies?
The first pass is made the same way as in standard JME rendering, using renderViewPortQueues for a special viewport with MRT framebuffer, so the Opaque and Transparent buckets are used. I write all the buffers at the same time and use m_AlphaDiscardThreshold the same way as it is used in standard shaders. Finally I have diffuse, specular and other maps drawn - because the transparent objects acts the same way as before, the maps have informations for visible pixels.
After that, in the second pass I just draw an quad or sphere (depends on the light source distance) for every light, using maps I draw in the first pass.

Notice the roots - it is a flat surface with transparency placed on the wall.

I did few last fixes, added glow map generation in first pass to eliminate the postQueue render in BloomFilter - it results in rewriting that filter.
We tested everything on the following machine:

System: WinXP
Java 1.7.something
CPU: Core 2 Duo E8400
GPU: GTX 750 Ti
Resolution: 1280x1024

Test 1: empty room, player’s light (no shadows), one torch (no shadows)
FPS: ~160

Test 2: corridor, player’s light (no shadows), 2 torches (no shadows), 1 torch (shadows), one monster with 50k verts + bones, HW Skinning
FPS: >100

Test 3: corridor, player’s light (no shadows), 3 torches (shadows), 5 monsters with 50k verts + bones, HW Skinning
FPS: >75

Test 4: corridor, player’s light (no shadows), 3 torches (shadows), 4 monsters with 50k verts + bones, Software Skinning
FPS: >33

We know that 50k verts for monster is an extreme example, so we choose 15k as the upper limit. But we know that there is possible to make very nice models with even less tan 2k verts.
An little explanation what’s going on with torches - why there are torches with and without shadows: it depends if there is an moving or animating object near the torch. If nothing is changing, then there is no point to generate shadowmap every frame. On tests 3 and 4 all 3 torches were forced do update their shadowmaps because of the monsters walking next to them.

3 Likes

Here is an improved arrows panel:

Here we have two tabs: you can switch the view between arrows and character’s action skills.
Every character can have 3 action skills, like heal, rage, fortress etc.
There is no good place for them on the screen - the bottom of the screen is reserved for floor, we cannot take more space next to the party area, so the only solution is to share the arrows area. Switching between characters will change the visible skills.

5 Likes

Next things are done: character status windows and skills.
In this example we have only two skills, one during reuse, the second is an activated toggle.

Because the whole GUI is painted using Java’s class Graphics2D, I decided to paint those ‘animations’ using shader. Repainting in Java is just too slow.
Reuse animation: the dark mask is slowly removed, it is the same effect like in popular games.
Toggle: there is an white ribbon moving from one corner to another.

The question is: how I did it on shaders? :slight_smile: Is anyone able to guess?

6 Likes

looking great, keep up the good work!

Ok, so we have bright lights and very deep shadows. If you don’t have any torch in party’s member hand and there is no light on the wall, you are in darkness. It is natural, but I’m sure that players won’t like it.
So, the simple solution is to add a (0.05, 0.05, 0.05) light for party even if none of them have torch. Looks cool? IMO not enough.

So maybe it is good idea to make black shadow a bit blue? Nice!. Giving a (0.10, 0.10, 0.20) produces nice effect but ONLY if there is no other lights in range. After that everything goes too blue, even surfaces covered by light.
Sooo, do we can subtract some blue from torch on the wall? No! What if there are two torches, or we are too far away from one to give the blue factor? The effect is bad, trust me.

Let’s play with shaders again.
In second pass I render every light (including player’s own) using maps from first pass. The player’s light is the last one. It is important!
I can pass to the shader an extra map, the current framebuffer’s main texture.
Then, at the end of the whole calculation I simply test the pixel’s brightness. If it’s too dark I can add some values to it.

Here is the effect:


Tell me what you think of it.

4 Likes

maybe your fragment shader could return

fragData.rgb = min(vec3(0.1, 0.1, 0.2), color);

Then every dark will be a bit blue, without impact on brighter color.

Then every dark surface would be blue. Plain blue…

In my solution I’m affecting the light color value used in final calculation:

    vec3 color = vec3(m_LightColor.rgb   * diffuseColor.rgb  * vec3(light.x) +      
                      lightColorSpec.rgb * specularColor.rgb * vec3(light.y));
                      
    vec3 currcolor = texture2D(m_CurrentScene, newTexCoord).rgb;    
    currcolor += color;
    float br = (currcolor.r + currcolor.g + currcolor.b) / 3.0;
    if (br > 0.25)
    {
        gl_FragColor.rgba = vec4(color, 1.0);
        return;
    }
    
    vec3 lightColor = m_LightColor.rgb;
    float val = (0.25 - br);
    lightColor.r += val / 1.8;
    lightColor.g += val / 1.8;
    lightColor.b += val; //(val * 0.9) + (specularColor.b * 0.1);
    
    gl_FragColor.rgba =  vec4(lightColor         * diffuseColor.rgb  * vec3(light.x) +      
                              lightColorSpec.rgb * specularColor.rgb * vec3(light.y), 1.0);

EDIT: Are you sure of that ‘min’?

https://www.opengl.org/sdk/docs/man4/html/min.xhtml

min(vec3(0.0, 1.0, 2.0), vec3(2.0, 1.0, 0.0)) => vec3(2.0, 1.0, 2.0)