Change colors to grayscale when game is paused

I’m doing some testing with the example projects to get familiar with GD and I don’t find how can I do this.

When the game is paused I want change the colors to grayscale, so the player can notice the game is paused.

I thought create a static grayscale sprite for each object I have and when the game is paused change all animations inside the camera to those ones, or use the formula grayscale = 0.299R + 0.587G + 0.114*B but I’m not sure if GD can get each object’s color.

So, are there a easiest way to do this?

If you are talking about sprite color (there is an action to set that), this is just a filter (color components of each pixel is “multiplied” by the “color”). So, the color is white by default (so that everything look normal).

I don’t think you’ll be able to set the colors to grayscale with this action because you can only apply a filter on top of the picture.

Most games just bring up a game menu overlayed over the game to show when the game is paused. Why not just do that?

Ok, here are the facts:

Each color in a screen is represented by a combination of different red, green and blue values. These are called “channels”. But, you seem to already know that. Commonly, the scale used to represent the value of each one of this channels is represented between 0 and 255.

Any gray tone is a color wich red, blue and green values are equal. So, I don’t have idea how that formula of yours works, but what I know (and had always worked for me) is you can get the average of the channels values an apply the result value to each channel to get the equivalent gray tone for that color.

What most games do to achieve this effect is to take a screen capture of the game when you pause it and turn that picture to grayscale (but we know there other advanced effects in modern commercial 3D games, like everything turned to grayscale while still moving).

For an indie 2D game produced in an IDE as GDevelop the most effective way to apply an overall color effect is using a blend mode, that is, using a big sprite over all others and blending it with everything beneath. BUT… alas, there isn’t a way to apply a grayscale effect with the basic color blend modes.

Why this is so? Well, almost any graphic-focused software in a computer (from graphic design software as photoshop or GIMP to game dev IDE’s as GDevelop) has integrated ways to control the basic blend mode of colors, pictures, vectors, layers… in our case, sprites (and common blend modes directly derive from the basic bitwise arithmetic operations the computers internally use: NOT, AND, OR, XOR… the result of this arithmetic operations over two differents pixel colors are different kinds of transparency and color transformations). Apply an overall hue to a picture is really easy (that’s like to colorize or saturate a picture with a specific hue). But, that’s not the case with gray tones because, as simple as I can explain, the hue value for ANY gray tone is 0, so, said in other words, there is not arithmetic operation to apply. Summing up, in computational process terms, is easy and economical to colorize a picture with any color hue except with a gray tone.

In the other hand, it’s not impossible, in fact is a very common effect in many games around the websphere but it requires more complex custom arithmetics using the formula I previously show you (or another) and programatically implementing it as an algorithm over each pixel of each sprite you are turning to grayscale. Such specific operation over pixels don’t seems to be possible (and it don’t feels neccesary) in an IDE as GD at least you know C++ or Java and know how to use the code extensions. But in my opinion that’s more trouble than a color effect deserves.

I offer to you another very simple and equally effective option (but it ISN’T a grayscale effect):

  • Create a sprite the size of your game window and place it over all other sprites in your game (let’s call it color_effect)
  • The color_effect sprite can be just a rectangle of some color (for this example let’s say blue)
    [list][*]If you have some HUD elements (like the sprites of the menu usually displayed when a game is paused) you don’t want to be affected by the colorization, place them above the color_effect sprite
  • If your game has some kind of scrolling (like in most common platformers), you don’t want the color_effect object to be moving around so place it in a separate layer and DON’T touch the camera of that layer to keep it fixed over your game
    [/:m]
    [
    ]Set an action under the condition “at the scene start” to change the visual mode [blend mode] of the color_effect sprite to 2 [multiply mode] (you can find this action in sprite/effects/visual mode)[/:m]
    [
    ]If you’re following this instructions and test your game running it you’ll see the color_effect sprite has blended with all other sprites above it and they look deeply blueish now[/:m]
    [
    ]Now you just need to keep this sprite invisible the most of the time and show it when you pause your game[/*:m][/list:u]

A very simple example of this here:
[size=85]Lazy readers: this is not a grayscale effect example.[/size]
blend_mode_example.zip (75 KB)

Maybe it’s not a grayscale effect but it’s a cool color effect. If you feel tempted to use a gray sprite to see if you can blend the colors into a grayscale effect, let me tell you it don’t will work because all technical stuff detailed above… that will just darken the image.

Hope it helps :wink:

EDIT: fixed some bad english grammar.

1 Like

Surely GD can’t handle the grayscale formula, since global color works only per-object (not per-pixel) and is multiplicative: Even if your sprite have one color, for example a green box (0;255;0), any global color you set will return the color (0; global_color_green; 0), that is a green tone or black, while the grayscale of green is (120;120;120).
So I suggest you to use statics sprites :wink:

Out of topic:

Grayscale is not very advanced, just use a post-process filter (framebuffer in OpenGL, set-texture-as-render-target? in Direct3D… yeah Microsoft is not very “visionary” about names ¬¬). Finally set the shader for the post-process, wich just is a formula (very compressed), for example this set the final color as a grayscale from the texture color “text_color” saved in a framebuffer: gl_FragColor = vec4( vec3( dot( text_color, vec3( 0.2125, 0.7154, 0.0721 ) ) ), 1.0 );

EDIT: Fixed minor error

Yes I was thinking in use sprite color with visualmode but now I see I was wrong.

The idea is that. First obscure the game, then show a pause menu and also change colors to grayscale (but not the menu elements).

The equation I wrote is used (one of multiple uses) to set the luminance on CVBS and RGB video signals but I wrote it wrong. The formula I wrote is (if I’m not mistaken again) for NTSC systems and the equation I usually use is the standard: Luminance = 0.2126 R + 0.7152 G + 0.0722 B

This formula is based in how the human eye perceive the red, green and blue colors. The eyes are more sensitive to the red than blue and green colors. My english level is poor to explain this better but if this subject is of your interest you can search information about RGB to Luma conversion and you’ll find better and more detailed explanations that I could say.

Yes, it’s a cool effect. I probably will use it. Thanks!

Sure! your amazing explanation about the problem helps me a lot :slight_smile:

Now I’m discussing with myself about use the grayscale sprites or erdo’s alternative and reconsider my initial idea because if I use grayscale sprites I also need to know the exactly animation of each object in screen and change it for the gray one. It´s going too complicated for a simple game pause and I prefer keep the things easiest possible.

Sure, keep the things easy is the best choice; the erdo’s alterative is great, if you can use it instead grayscale and you like it… well, I would use it :wink:

If your game is native game, it can be done with the help of a little C++ event.
First, you get the screen as a picture (there is an action for that in the “Primitive drawing” extension) and then you can modify it using a C++ event (and change each pixel color). Then, you display it inside a sprite. I’ll try to do an example when I’ll have some time. :wink:

You are right, you can change SFML images color per-pixel.
But I think you can do it in HTML5 with JavaScript too, PIXI has a built-in grayscale filter, of course it works only for WebGL compatible devices. I can check it later :slight_smile:

EDIT: Ok, this is possible, of course you lose some performance, but for a pause menu will work like a charm :smiley: :
Grayscale.rar (25.7 KB)
The ugly side is that I have to use the _sprite and _tiledSprite PIXI.Sprite variables directly, I didn’t found a common way to get the PIXI sprite (getPIXISprite() for example), and the links for the GDJS documentation (the JS game engine) are broken :frowning:

1 Like

Out of topic too:

Ok,now I understand how and where that formula is applied but what I can’t figure out is why that specific values works (I understand there are in the scale 0-1, not in 0-255, but why those values?)

Anyways, nothing important, just my curiosity working against me :unamused:

Not just in the scale 0-1, but their sum is = 1. I’m reading some info now, seems that our eyes are more sensible to green, then red and finally blue, that is the reason to give these weights to each component. As their sum in 1, and each component of the original color is in the range 0-1, the dot product can’t be > 1. Finally, in GLSL, vec3(int) returns vec3(int, int, int) = gray :sunglasses:
About eyes sensitivity, it means blue would be even more blue?.. I mean, we only perceive ~7% of blue light? :confused:

Coming back to topic, I could try to add a global filter, instead a per object one, maybe the performance increase. Even I could make a big PIXI filters demo, as PIXI has in their examples, what do you think guys? :smiley:

1 Like

Excuse me about double post, just want to ensure you read it :slight_smile:
WebGL rocks! The global filter works, and it seems to run better (no FPS drop vs drop-to-20 in my PC) :smiley: :
Grayscale2.rar (25.5 KB)

That makes sense.

Found this article about 3 different algorithms to calculate a grayscale image:
http://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/

Colors are just a neural interpretation of light values transmitted by photons roaming the environment. Outside our brain light and colors don’t exist as we know. So I think the right thing would be to say our interpretation of blue could be more intense if our photoreceptor cells were able to perceive the entire blue spectrum (and our brain able to process it) :stuck_out_tongue:

Good work! That’s amazing! It feels like GD might have a native grayscale effect for HTML5 games in the future.

If you make it, it would fantastic :smiley:. I don’t know C++ so I probably won’t learn about the c++ event code you write but I will enjoy it.

Wonderful! And I’ve learn a new form to implement the pause :stuck_out_tongue:

Is this a topic people would still like an answer to? I have a possible solution in mind.

Actually I would love to hear your solution, this is something I would like to add to my bag of tricks within GD5!

There’s actually an exceptionally easy way to do this now. With the new “Layer” filters, you can just add a “Black and White” filter to each layer you have in the game. Then at the start of the scene, use the “Enable an effect on a layer” and set the filter effect to “No” for each layer.

When you pause the game, set the effect to “Yes”. When you unpause, set it back to “No”.

4 Likes