Skip to content

Commit 76d420a

Browse files
Merge pull request MonoGame#40 from AristurtleDev/24-shaders
Chapter 24: Shaders
2 parents ab6c4ee + 0f0d41a commit 76d420a

File tree

13 files changed

+681
-0
lines changed

13 files changed

+681
-0
lines changed

articles/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@
158158
href: tutorials/building_2d_games/22_snake_game_mechanics/
159159
- name: "23: Completing the Game"
160160
href: tutorials/building_2d_games/23_completing_the_game/
161+
- name: "24: Shaders"
162+
href: tutorials/building_2d_games/24_shaders/
161163
- name: Console Access
162164
href: console_access.md
163165
- name: Help and Support
Loading

articles/tutorials/building_2d_games/24_shaders/index.md

Lines changed: 444 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#if OPENGL
2+
#define SV_POSITION POSITION
3+
#define VS_SHADERMODEL vs_3_0
4+
#define PS_SHADERMODEL ps_3_0
5+
#else
6+
#define VS_SHADERMODEL vs_4_0_level_9_1
7+
#define PS_SHADERMODEL ps_4_0_level_9_1
8+
#endif
9+
10+
Texture2D SpriteTexture;
11+
12+
sampler2D SpriteTextureSampler = sampler_state
13+
{
14+
Texture = <SpriteTexture>;
15+
};
16+
17+
struct VertexShaderOutput
18+
{
19+
float4 Position : SV_POSITION;
20+
float4 Color : COLOR0;
21+
float2 TextureCoordinates : TEXCOORD0;
22+
};
23+
24+
float4 MainPS(VertexShaderOutput input) : COLOR
25+
{
26+
return tex2D(SpriteTextureSampler,input.TextureCoordinates) * input.Color;
27+
}
28+
29+
technique SpriteDrawing
30+
{
31+
pass P0
32+
{
33+
PixelShader = compile PS_SHADERMODEL MainPS();
34+
}
35+
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
public override void Draw(GameTime gameTime)
2+
{
3+
// Clear the back buffer.
4+
Core.GraphicsDevice.Clear(Color.CornflowerBlue);
5+
6+
if (_state != GameState.Playing)
7+
{
8+
// We are in a game over state, so apply the saturation parameter.
9+
_grayscaleEffect.Parameters["Saturation"].SetValue(_saturation);
10+
11+
// And begin the sprite batch using the grayscale effect.
12+
Core.SpriteBatch.Begin(samplerState: SamplerState.PointClamp, effect: _grayscaleEffect);
13+
}
14+
else
15+
{
16+
// Otherwise, just begin the sprite batch as normal.
17+
Core.SpriteBatch.Begin(samplerState: SamplerState.PointClamp);
18+
}
19+
20+
// Draw the tilemap
21+
_tilemap.Draw(Core.SpriteBatch);
22+
23+
// Draw the slime.
24+
_slime.Draw();
25+
26+
// Draw the bat.
27+
_bat.Draw();
28+
29+
// Always end the sprite batch when finished.
30+
Core.SpriteBatch.End();
31+
32+
// Draw the UI
33+
_ui.Draw();
34+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// The grayscale shader effect.
2+
private Effect _grayscaleEffect;
3+
4+
// The amount of saturation to provide the grayscale shader effect
5+
private float _saturation = 1.0f;
6+
7+
// The speed of the fade to grayscale effect.
8+
private const float FADE_SPEED = 0.02f;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
private void GameOver()
2+
{
3+
// Show the game over panel
4+
_ui.ShowGameOverPanel();
5+
6+
// Set the game state to game over
7+
_state = GameState.GameOver;
8+
9+
// Set the grayscale effect saturation to 1.0f;
10+
_saturation = 1.0f;
11+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
public override void LoadContent()
2+
{
3+
// Create the texture atlas from the XML configuration file
4+
TextureAtlas atlas = TextureAtlas.FromFile(Core.Content, "images/atlas-definition.xml");
5+
6+
// Create the tilemap from the XML configuration file.
7+
_tilemap = Tilemap.FromFile(Content, "images/tilemap-definition.xml");
8+
_tilemap.Scale = new Vector2(4.0f, 4.0f);
9+
10+
// Create the animated sprite for the slime from the atlas.
11+
AnimatedSprite slimeAnimation = atlas.CreateAnimatedSprite("slime-animation");
12+
slimeAnimation.Scale = new Vector2(4.0f, 4.0f);
13+
14+
// Create the slime
15+
_slime = new Slime(slimeAnimation);
16+
17+
// Create the animated sprite for the bat from the atlas.
18+
AnimatedSprite batAnimation = atlas.CreateAnimatedSprite("bat-animation");
19+
batAnimation.Scale = new Vector2(4.0f, 4.0f);
20+
21+
// Load the bounce sound effect for the bat
22+
SoundEffect bounceSoundEffect = Content.Load<SoundEffect>("audio/bounce");
23+
24+
// Create the bat
25+
_bat = new Bat(batAnimation, bounceSoundEffect);
26+
27+
// Load the collect sound effect
28+
_collectSoundEffect = Content.Load<SoundEffect>("audio/collect");
29+
30+
// Load the grayscale effect
31+
_grayscaleEffect = Content.Load<Effect>("effects/grayscaleEffect");
32+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
private void TogglePause()
2+
{
3+
if (_state == GameState.Paused)
4+
{
5+
// We're now unpausing the game, so hide the pause panel
6+
_ui.HidePausePanel();
7+
8+
// And set the state back to playing
9+
_state = GameState.Playing;
10+
}
11+
else
12+
{
13+
// We're now pausing the game, so show the pause panel
14+
_ui.ShowPausePanel();
15+
16+
// And set the state to paused
17+
_state = GameState.Paused;
18+
19+
// Set the grayscale effect saturation to 1.0f;
20+
_saturation = 1.0f;
21+
}
22+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
public override void Update(GameTime gameTime)
2+
{
3+
// Ensure the UI is always updated
4+
_ui.Update(gameTime);
5+
6+
if (_state != GameState.Playing)
7+
{
8+
// The game is in either a paused or game over state, so
9+
// gradually decrease the saturation to create the fading grayscale.
10+
_saturation = Math.Max(0.0f, _saturation - FADE_SPEED);
11+
12+
// If its just a game over state, return back
13+
if (_state == GameState.GameOver)
14+
{
15+
return;
16+
}
17+
}
18+
19+
// If the pause button is pressed, toggle the pause state
20+
if (GameController.Pause())
21+
{
22+
TogglePause();
23+
}
24+
25+
// At this point, if the game is paused, just return back early
26+
if (_state == GameState.Paused)
27+
{
28+
return;
29+
}
30+
31+
// Update the slime;
32+
_slime.Update(gameTime);
33+
34+
// Update the bat;
35+
_bat.Update(gameTime);
36+
37+
// Perform collision checks
38+
CollisionChecks();
39+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#if OPENGL
2+
#define SV_POSITION POSITION
3+
#define VS_SHADERMODEL vs_3_0
4+
#define PS_SHADERMODEL ps_3_0
5+
#else
6+
#define VS_SHADERMODEL vs_4_0_level_9_1
7+
#define PS_SHADERMODEL ps_4_0_level_9_1
8+
#endif
9+
10+
Texture2D SpriteTexture;
11+
12+
// A value between 0 and 1 that controls the intensity of the grayscale effect.
13+
// 0 = full color, 1 = full grayscale.
14+
float Saturation = 1.0;
15+
16+
sampler2D SpriteTextureSampler = sampler_state
17+
{
18+
Texture = <SpriteTexture>;
19+
};
20+
21+
struct VertexShaderOutput
22+
{
23+
float4 Position : SV_POSITION;
24+
float4 Color : COLOR0;
25+
float2 TextureCoordinates : TEXCOORD0;
26+
};
27+
28+
float4 MainPS(VertexShaderOutput input) : COLOR
29+
{
30+
// Sample the texture
31+
float4 color = tex2D(SpriteTextureSampler, input.TextureCoordinates) * input.Color;
32+
33+
// Calculate the grayscale value based on human perception of colors
34+
float grayscale = dot(color.rgb, float3(0.3, 0.59, 0.11));
35+
36+
// create a grayscale color vector (same value for R, G, and B)
37+
float3 grayscaleColor = float3(grayscale, grayscale, grayscale);
38+
39+
// Linear interpolation between he grayscale color and the original color's
40+
// rgb values based on the saturation parameter.
41+
float3 finalColor = lerp(grayscale, color.rgb, Saturation);
42+
43+
// Return the final color with the original alpha value
44+
return float4(finalColor, color.a);
45+
}
46+
47+
technique SpriteDrawing
48+
{
49+
pass P0
50+
{
51+
PixelShader = compile PS_SHADERMODEL MainPS();
52+
}
53+
};
Binary file not shown.

articles/tutorials/building_2d_games/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ This documentation will introduce game development concepts using the MonoGame f
4444
| [Chapter 21: Customizing Gum UI](21_customizing_gum_ui/index.md) | Learn how to create custom UI components with animations and visual styling in Gum. | [21-Customizing-Gum-UI](https://github.com/shyfox-studio/learn-monogame-2d/tree/main/src/21-Customizing-Gum-UI/) |
4545
| [Chapter 22: Snake Game Mechanics](22_snake_game_mechanics/index.md) | Learn how to implement classic snake-like game mechanics and organize game objects into reusable components. | [22-Snake-Game-Mechanics](https://github.com/shyfox-studio/learn-monogame-2d/tree/main/src/22-Snake-Game-Mechanics/) |
4646
| [Chapter 23: Completing the Game](23_completing_the_game/index.md) | Finalize game mechanics by updating our current demo into a snake-like inspired game. | [23-Completing-The-Game](https://github.com/shyfox-studio/learn-monogame-2d/tree/main/src/23-Completing-The-Game/) |
47+
| [Chapter 24: Shaders](24_shaders/index.md) | Learn how to create custom visual effects using shaders in MonoGame. | [24-Completing-The-Game](https://github.com/shyfox-studio/learn-monogame-2d/tree/main/src/24-Shaders/) |
4748

4849
## Conventions Used in This Documentation
4950

0 commit comments

Comments
 (0)