From 7119de123850ccb124cf1216100a438ad74bfb1d Mon Sep 17 00:00:00 2001
From: Gurpreet Singh Matharoo This function is called when you want to begin the saving out of multiple buffers to multiple files (or loading multiple buffers). The groupname is a string and will be used as the directory name for where the files are saved, and should be used as part of the file path when loading the files back from outside an async group (using any of the buffer_load functions). This function is only for use with the buffer_save_async and buffer_load_async functions and you must also end the async group by calling buffer_async_group_end function otherwise the files will not be saved/loaded. For the console platforms (like PS4 for example), the groupname will be used as the save slot description, and using this function can help you avoid having the UI show for every file that is being saved out. For some console platforms (e.g. PlayStation), the groupname will be used as the save slot description, and using this function can help you avoid having the UI show for every file that is being saved out. buffer_async_group_begin(groupname) With this function you can remove the given emitter from memory. This should always be done whenever the emitter is not going to be used further in the room or the game, ie: in the Destroy Event of the instance or in the Room End Event, otherwise you may end up with a memory leak that will slow down and eventually crash your game. With this function you can remove the given emitter from memory. This should always be done whenever the emitter is not going to be used further in the room or the game, i.e.: in the Clean Up Event of the instance or in the Room End Event, otherwise you may end up with a memory leak that will slow down and eventually crash your game. Sound instances currently being played on the emitter are force-stopped. audio_emitter_free(emitter) N/A if (lives == 0) if (lives == 0) The above code checks the value of the global variable "lives" and if it returns 0, it will destroy the emitter indexed in the variable "s_emit" and then go to the room indexed in the variable "rm_Menu". The above code checks the value of the global variable "lives" and if it returns 0, it will destroy the emitter indexed in the variable "s_emit" and then go to the room indexed in the variable "rm_menu". This function returns the cache directory for your game. Use this directory to store cached data that is not permanently needed for your game. This variable holds the path to the cache directory for your game. Use this directory to store cached data that is not permanently needed for your game. On some consoles, certain options may need to be enabled for this to hold a valid path. This function returns the directory where the game's runner (executable) is stored. However, this may not always be useful, particularly as some devices run the executable from a *.zip file, so this would return that location no matter where the extracted executable is actually running from. This variable holds the path to the directory where the game's runner (executable) is stored. However, this may not always be useful, particularly as some devices run the executable from a *.zip file, so this would return that location no matter where the extracted executable is actually running from. This is different from working_directory, which stores where the game's files are stored, however by default they are in the same location. This function returns the temporary directory created for your game each time it is run. This variable holds the path to the temporary directory created for your game each time it is run. This directory will hold files and can be accessed while the game is running, but it will be removed (along with all files that it contains) when the game is closed. This returns a path that points to where the game's files are stored. In most cases, this is the same as the program_directory, which is the path to the game's runner (executable). However if the game's files happen to be in a different directory than the runner (say you use game_change to use a different working directory or use command line to run a runner in a different location), then this will point to where the game files are, not the runner. This variable holds the path that points to where the game's files are stored. In most cases, this is the same as the program_directory, which is the path to the game's runner (executable). However, if the game's files happen to be in a different directory than the runner (say you use game_change to use a different working directory or use command line to run a runner in a different location), then this will point to where the game files are, not the runner. It may also be a different directory when testing your project through the IDE, as then the game files and the runner are in different locations as well. When using this directory to write out a file, GameMaker will redirect it to the game_save_id location if the file system sandbox does not allow writing to the working directory (this is the default behaviour, which can be disabled in the Game Options for Desktop targets only). Welcome to the GameMaker user manual! This document is divided into three parts with the aim of getting you introduced to the interface and basic workings of GameMaker and general programming, before going on to more advanced usage and the functions available through our proprietary programming language GML (GameMaker Language). To ease you into things we have created a handy Quick Start Guide, and even if you are familiar with other game creation tools we recommend that you start there to get an overview of the way that GameMaker works. You'll find GameMaker to be easy and intuitive to use, and whatever your skill level, you will soon be making games you've always dreamt of. Due to the modular nature of GameMaker there are certain things that are not included in this user manual, in particular those aspects of setting up and connecting the different devices that can be supported. For up-to-date information and troubleshooting hints and tips related to the different target platforms, please see the GameMaker Wiki and GameMaker Help Center (for legacy information). Due to the modular nature of GameMaker there are certain things that are not included in this user manual, in particular those aspects of setting up and connecting the different devices that can be supported. For up-to-date information and troubleshooting hints and tips related to the different target platforms, please see the GameMaker Wiki and GameMaker Help Center (for legacy information and help articles). Returning to the manual? Here are some handy shortcuts: Functionality for Mobile Push Notifications has been separated into extensions. Please read the following articles for implementing notifications: This page lists functions for use with the Live Wallpaper functionality. For information on how to set these up, see the helpdesk article on GX Live Wallpapers. For information on how to set these up, see the helpdesk article on GX Live Wallpapers. The following functions are given for Live Wallpapers: This function subscribes to the given metric(s) from the Companion app. This is used to get real-time system information, and enable mouse input, which is disabled for Live Wallpapers by default. See this guide for making a basic Live Wallpaper and (optionally) setting up the Companion app on Windows. See this guide for making a basic Live Wallpaper and (optionally) setting up the Companion app on Windows. Graphics drivers must be up-to-date on the target computer for GPU metrics to work correctly. Each call to this function cancels any previously active subscriptions, so only those included in the last call remain active. To import a previous GameMaker project into GameMaker it must have been created using the 1.4 version, and even then it may not work directly on import. A great many things are different between GameMaker and GameMaker: Studio 1.4, and so your older projects may need some tweaking for them to work. Please see the article Porting A GM:S 1.4 Game To GameMaker on the GameMaker Knowledge Base and the section of the manual that covers Obsolete Functions and Compatibility Scripts. To import a previous GameMaker project into GameMaker it must have been created using the 1.4 version, and even then it may not work directly on import. A great many things are different between GameMaker and GameMaker: Studio 1.4, and so your older projects may need some tweaking for them to work. Please see the article Porting A GM:S 1.4 Game To GameMaker on the GameMaker Knowledge Base and the section of the manual that covers Obsolete Functions and Compatibility Scripts. Importing a *.yyz project that contains font resources may require you to "regenerate" the fonts by removing/re-adding them, or by changing the font in The Font Editor and then setting it back again. This is because the existing font information is retained by the *.yyz when it is exported, and, on import later or on another machine, the project may not have the required fonts installed already (or may have a different font of the same name). This should only be done if you are seeing issues with how the font renders after import. Each target option saves to a platform-specific format, listed below: This variable holds the path that points to where the game's files are stored. This variable holds the path to the directory where the game's files are stored. In most cases, this is the same as the program_directory, which is the path to the game's runner (executable). However, if the game's files happen to be in a different directory than the runner (say you use game_change to use a different working directory or use command line to run a runner in a different location), then this will point to where the game files are, not the runner. It may also be a different directory when testing your project through the IDE, as then the game files and the runner are in different locations as well. When using this directory to write out a file, GameMaker will redirect it to the game_save_id location if the file system sandbox does not allow writing to the working directory (this is the default behaviour, which can be disabled in the Game Options for Desktop targets only). You supply the instance ID to use (an instance that is active in the room, and not an object index) or a struct reference, as well as the function ID (or method reference) that you want to bind. The function will return a new method which can be called from the variable it is assigned to (see the code example below). The returned method will be "bound" to the given instance or struct, meaning it will always execute in the scope of that instance/struct. You can bind built-in functions as well as user-defined functions/methods, and you can also supply undefined as the instance/struct argument meaning that the current self scope will be used for the binding. The method function is implicitly called when defining new Method Variables (to assign the new function to self) and when defining new struct and array literals. Due to this, you may see extra calls to the method function in The Debugger in addition to any explicit calls, which are made implicitly to define the aforementioned resources. method(struct_ref_or_instance_id, func) Shaders are often used to create beautiful graphical effects in games. They are also among the most advanced features offered by GameMaker, so it is necessary that you have a basic understanding of programming and how GameMaker works before getting started with them. So, what is a shader? Initially they were created to provide shading for lighting (hence the name), but they are now used to produce a huge variety of effects. Shader code is similar to regular code, but it is (almost always) executed by the GPU, not the CPU. This difference comes with its own set of rules and limitations, but we’ll cover those later. Each shader is made up of two separate components: a vertex shader and a fragment shader (also referred to as pixel shader). Let’s start with the vertex shader. Each sprite is formed by a rectangle, but computers like to draw triangles, so those rectangles are split into two triangles (sometimes called a quad). This leaves us with six vertices (corners) per sprite, but two of those are the same one, so we should only worry about four. Now, imagine we have a for loop that goes over every vertex and executes the code inside the vertex shader for each. This allows us to change the vertex position and color before passing it over to the fragment shader since the vertex shader is executed earlier. Here’s how that would look: So, what is a shader? Initially they were created to provide shading for lighting (hence the name), but they are now used to produce a huge variety of effects. Shader code is similar to regular code, but it is (almost always) executed by the GPU, not the CPU. This difference comes with its own set of rules and limitations, but we'll cover those later. Each shader is made up of two separate components: a vertex shader and a fragment shader (also referred to as pixel shader). Let's start with the vertex shader. Each sprite is formed by a rectangle, but computers like to draw triangles, so those rectangles are split into two triangles (sometimes called a quad). This leaves us with six vertices (corners) per sprite, but two of those are the same one, so we should only worry about four. Now, imagine we have a for loop that goes over every vertex and executes the code inside the vertex shader for each. This allows us to change the vertex position and color before passing it over to the fragment shader since the vertex shader is executed earlier. Here's how that would look: It would look something like this: GameMaker allows users to write shaders in GLSL (OpenGL Shader Language), HLSL (High-level Shader Language, used when working with DirectX), and GLSL ES (a subset of GLSL which is common in mobile devices). Here we are using GLSL ES as the shader language since it’s the one that provides the best compatibility across target platforms. Generally this is the one you always want to use unless you have very specific needs and understand the limitation of the other shader languages. The math and techniques should be similar between all three languages however, save for a few syntax differences here and there. The vertex shader is executed first, and as we explained above, it deals with vertices. It is used to calculate positions, normals, and texture coordinates. These shaders are not particularly useful in 2D, since every sprite is usually a square, but it can be used to do some skewing, scaling, etc... It becomes much more useful in 3D for lighting calculations and mesh deformations. Fragment shaders are much more interesting and are what will be covered mostly here, since the fragment shader is where we get information about our textures and can tweak the final color of each pixel in our image. GameMaker allows users to write shaders in GLSL (OpenGL Shader Language), HLSL (High-level Shader Language, used when working with DirectX), and GLSL ES (a subset of GLSL which is common in mobile devices). Here we are using GLSL ES as the shader language since it's the one that provides the best compatibility across target platforms. Generally, this is the one you always want to use unless you have very specific needs and understand the limitation of the other shader languages. The math and techniques should be similar between all three languages however, save for a few syntax differences here and there. The vertex shader is executed first, and as we explained above, it deals with vertices. It is used to calculate positions, normals, and texture coordinates. These shaders are not particularly useful in 2D, since every sprite is usually a square, but it can be used to do some skewing, scaling, etc. It becomes much more useful in 3D for lighting calculations and mesh deformations. Fragment shaders are much more interesting and are what will be covered mostly here, since the fragment shader is where we get information about our textures and can tweak the final color of each pixel in our image. If you have created a shader in GameMaker, you might have noticed the following keywords in the default pass-through shader. These keywords help the shader understand the purpose and scope of each variable: If you have created a shader in GameMaker, you might have noticed the following keywords in the default passthrough shader. These keywords help the shader understand the purpose and scope of each variable: You'll also see the use of vec as a keyword. This is used to identify a vector variable in the shader and you'll soon see that vectors are very important when working with shaders. That is why they are implemented as a base type in GLSL. If you are unfamiliar with them, they are a mathematical term represented as a matrix with only one column. In programming, we usually represent them as an array where the number of components corresponds to the dimension. Two and three-dimensional vectors are often used for positions, texture coordinates, or colors without an alpha channel, while four-dimensional ones are used for colors with an alpha channel. We can also specify if they hold booleans, integers, or floating point values. The syntax to declare a vector is this: You'll also see the use of vec as a keyword. This is used to identify a vector variable in the shader and you'll soon see that vectors are very important when working with shaders. That is why they are implemented as a base type in GLSL. If you are unfamiliar with them, they are a mathematical term represented as a matrix with only one column. In programming, we usually represent them as an array where the number of components corresponds to the dimension. Two and three-dimensional vectors are often used for positions, texture coordinates, or colors without an alpha channel, while four-dimensional ones are used for colors with an alpha channel. We can also specify if they hold booleans, integers, or floating point values. The syntax to declare a vector is this: vec2 firstVec; // Two-dimensional vector of floats vec4 myVec; This uses the component names inside the vector to access them. You can use x, y, z, or w, to get the first, second, third, or fourth components, respectively. We refer to this method as swizzling because the following syntax is also valid: This uses the component names inside the vector to access them. You can use x, y, z, or w, to get the first, second, third, or fourth components, respectively. We refer to this method as swizzling because the following syntax is also valid: vec4 firstVec; As you can see, we can use any combination of up to four letters to create a vector of that length. We cannot attempt to access a component that would be out of bounds (for example, trying to access w in secondVec or thirdVec, since they don’t have a fourth component). Also, we can repeat letters and use them in any order, as long as the vector variable it’s being assigned to is the same size as the number of letters used. For obvious reasons, when using swizzle to set component values, you can’t use the same component twice. For example, the below is not valid as you are trying to set the same component to two different values: As you can see, we can use any combination of up to four letters to create a vector of that length. We cannot attempt to access a component that would be out of bounds (for example, trying to access w in secondVec or thirdVec, since they don't have a fourth component). Also, we can repeat letters and use them in any order, as long as the vector variable it's being assigned to is the same size as the number of letters used. For obvious reasons, when using swizzle to set component values, you can't use the same component twice. For example, the below is not valid as you are trying to set the same component to two different values: myVec.xx = vec2(2.0, 3.0); Last, we have been using xyzw as our swizzle mask, which is usually the case when dealing with positions. There are two more sets of masks you can use: rgba (used for colors), or stpq (used for texture coordinates). Internally, there is no difference between these masks, and we only use them to make the code clearer as to what the vector represents in that instance. Also, we can’t combine swizzle masks in the same operation, so this is invalid: Last, we have been using xyzw as our swizzle mask, which is usually the case when dealing with positions. There are two more sets of masks you can use: rgba (used for colors), or stpq (used for texture coordinates). Internally, there is no difference between these masks, and we only use them to make the code clearer as to what the vector represents in that instance. Also, we can't combine swizzle masks in the same operation, so this is invalid: myVec = otherVec.ybp; Those were a lot of definitions and information, but knowing these things is necessary to understand shaders themselves. When you create a shader in GameMaker, it will open two files for you: a vertex shader (.vsh) and a fragment shader (.fsh). This is the most basic shader you can make, which takes a sprite, reads the texture, and colors each pixel with that color. If you specify vertex colors when drawing, those colors will blend with the texture. Let’s go through the code for a newly created shader asset and analyze it, starting with the vertex shader. When you create a shader in GameMaker, it will open two files for you: a vertex shader (.vsh) and a fragment shader (.fsh). This is the most basic shader you can make, which takes a sprite, reads the texture, and colors each pixel with that color. If you specify vertex colors when drawing, those colors will blend with the texture. Let's go through the code for a newly created shader asset and analyze it, starting with the vertex shader. // Passthrough Vertex Shaderbuffer_async_group_begin
Syntax:
Example:
- © Copyright YoYo Games Ltd. 2024 All Rights Reserved
+ © Copyright YoYo Games Ltd. 2026 All Rights Reserved
audio_emitter_free
- Syntax:
Syntax:
@@ -38,12 +40,12 @@ emitter
- Audio Emitter ID
+ Audio Emitter ID
The index of the emitter to free.
Returns:
Example:
-
+
{
audio_emitter_free(s_emit);
- room_goto(rm_Menu);
+ room_goto(rm_menu);
}Example:
© Copyright YoYo Games Ltd. 2022 All Rights Reserved
+ © Copyright YoYo Games Ltd. 2026 All Rights Reserved
cache_directory
- Example:
program_directory
- Example:
© Copyright YoYo Games Ltd. 2024 All Rights Reserved
+ © Copyright YoYo Games Ltd. 2026 All Rights Reserved
temp_directory
- Example:
working_directory
- Example:
diff --git a/Manual/contents/GameMaker_Language/GML_Reference/Asynchronous_Functions/Push_Notifications/Push_Notifications.htm b/Manual/contents/GameMaker_Language/GML_Reference/Asynchronous_Functions/Push_Notifications/Push_Notifications.htm
index 2cc5a2dca..a497e1fe6 100644
--- a/Manual/contents/GameMaker_Language/GML_Reference/Asynchronous_Functions/Push_Notifications/Push_Notifications.htm
+++ b/Manual/contents/GameMaker_Language/GML_Reference/Asynchronous_Functions/Push_Notifications/Push_Notifications.htm
@@ -18,7 +18,7 @@
Push Notifications
Live Wallpapers
Functions
diff --git a/Manual/contents/GameMaker_Language/GML_Reference/Live_Wallpapers/wallpaper_set_subscriptions.htm b/Manual/contents/GameMaker_Language/GML_Reference/Live_Wallpapers/wallpaper_set_subscriptions.htm
index 5b6242322..4a9b66dc0 100644
--- a/Manual/contents/GameMaker_Language/GML_Reference/Live_Wallpapers/wallpaper_set_subscriptions.htm
+++ b/Manual/contents/GameMaker_Language/GML_Reference/Live_Wallpapers/wallpaper_set_subscriptions.htm
@@ -16,7 +16,7 @@
- wallpaper_set_subscriptions
Arguments
diff --git a/Manual/contents/IDE_Navigation/Menus/The_File_Menu.htm b/Manual/contents/IDE_Navigation/Menus/The_File_Menu.htm
index b64197c3d..6a35de3d4 100644
--- a/Manual/contents/IDE_Navigation/Menus/The_File_Menu.htm
+++ b/Manual/contents/IDE_Navigation/Menus/The_File_Menu.htm
@@ -24,7 +24,7 @@ The File Menu
The Help Menu
in the menu bar will also open the document, as will pressing F1. See Help Preferences for configuration of the manual.
diff --git a/Manual/contents/Introduction/Compiling.htm b/Manual/contents/Introduction/Compiling.htm
index e87be9e02..0ff8fbeba 100644
--- a/Manual/contents/Introduction/Compiling.htm
+++ b/Manual/contents/Introduction/Compiling.htm
@@ -80,8 +80,8 @@ You Should Know
@@ -92,7 +92,7 @@
Account Menu menu to log in before creating an executable.
at the top of the IDE). GameMaker will cache many of your game files to keep compilation speed to a minimum and these can sometimes get corrupted, so it is safer to clear that cache before doing a release build.How Different Targets Build
-
See tutorials for: Game / Live Wallpaper / Game Strip
+
See tutorials for: Game / Live Wallpaper / Game Strip
Tick the "Remember Packaging Option?" checkbox here to use the same setting and not show this window again on subsequent builds.
diff --git a/Manual/contents/Introduction/Our_Knowledge_Base.htm b/Manual/contents/Introduction/Our_Knowledge_Base.htm
index f2a8ad352..2732c375a 100644
--- a/Manual/contents/Introduction/Our_Knowledge_Base.htm
+++ b/Manual/contents/Introduction/Our_Knowledge_Base.htm
@@ -22,10 +22,10 @@ Our Knowledge Base
Our Knowledge Base
Next: Our Social Links© Copyright YoYo Games Ltd. 2025 All Rights Reserved
+ © Copyright YoYo Games Ltd. 2026 All Rights Reserved
working_directory
- method
Syntax:
Example:
© Copyright YoYo Games Ltd. 2024 All Rights Reserved
+ © Copyright YoYo Games Ltd. 2026 All Rights Reserved
Guide To Using Shaders
For the fragment shader, you can imagine the same loop as before, but this time it goes over every single pixel in your sprite, giving you information such as location and color of that pixel. In your fragment shader code, you perform operations and calculations to determine the color of that pixel to get the effect you want. For example, if you want a shader to make your sprite be black and white, then you’d calculate which shade of grey each pixel needs to be to create the effect.
For the fragment shader, you can imagine the same loop as before, but this time it goes over every single pixel in your sprite, giving you information such as location and color of that pixel. In your fragment shader code, you perform operations and calculations to determine the color of that pixel to get the effect you want. For example, if you want a shader to make your sprite be black and white, then you'd calculate which shade of grey each pixel needs to be to create the effect.
The reason shader code is usually executed by the GPU is that it is more efficient at it. Modern CPUs typically have between two to eight cores. Each core can perform one task at a time, so by taking advantage of multiple cores, we can perform that many tasks simultaneously. In contrast, modern GPUs can perform thousands, and even tens of thousands, of tasks running at the same time. This is helpful for shaders because we can execute the shader code of thousands of pixels concurrently. The limitation is that we only have access to the initial state of the sprite, so we don’t know about any modifications done to other pixels since we can’t know for sure the code has run on them yet.
The reason shader code is usually executed by the GPU is that it is more efficient at it. Modern CPUs typically have between two to eight cores. Each core can perform one task at a time, so by taking advantage of multiple cores, we can perform that many tasks simultaneously. In contrast, modern GPUs can perform thousands, and even tens of thousands, of tasks running at the same time. This is helpful for shaders because we can execute the shader code of thousands of pixels concurrently. The limitation is that we only have access to the initial state of the sprite, so we don't know about any modifications done to other pixels since we can't know for sure the code has run on them yet.Shader Variables
-
-
vec3 secondVec; // Three-dimensional vector of floats
vec4 thirdVec; // Four-dimensional vector of floats
@@ -62,21 +62,21 @@ Shader Variables
myVec.x = 0.0;
myVec.y = 1.0;
vec3 secondVec = firstVec.xyz;
vec2 thirdVec = secondVec.zy;
vec4 fourthVec = thirdVec.yxxy;Creating A Shader
-
attribute vec3 in_Position; // (x,y,z)
//attribute vec3 in_Normal; // (x,y,z) unused in this shader.
@@ -95,14 +95,14 @@ Creating A Shader
v_vTexcoord = in_TextureCoord;
}
Outside of the main function, we see some variable declarations and their qualifiers. The attributes are given to us by GameMaker. The varying ones are created by the user to pass that information over to the fragment shader. Inside the main function, we have the calculations to find the screen position of the vertex:
+Outside of the main function, we see some variable declarations and their qualifiers. The attributes are given to us by GameMaker. The varying ones are created by the user to pass that information over to the fragment shader. Inside the main function, we have the calculations to find the screen position of the vertex:
This shader should be left alone if you are not planning to play with vertex positions and it will not be used in any of the examples given below because all the effects shown will be created using the fragment shader.
-Let’s take a quick look at the fragment shader now:
+Let's take a quick look at the fragment shader now:
// Passthrough Fragment Shader
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
@@ -112,28 +112,28 @@
As explained before, the idea behind a fragment shader is to return the color of the current pixel. This is done by assigning the variable gl_FragColor the final color value. The texture2D function takes a texture and a vec2 with the UV coordinates you want to check in that texture, which returns a vec4 with the color. In the pass through shader, all we are doing is grabbing the color of the texture in the coordinate of this pixel and multiplying it by the color of the vertex associated with this pixel.
+As explained before, the idea behind a fragment shader is to return the color of the current pixel. This is done by assigning the variable gl_FragColor the final color value. The texture2D function takes a texture and a vec2 with the UV coordinates you want to check in that texture, which returns a vec4 with the color. In the passthrough shader, all we are doing is grabbing the color of the texture at the coordinate of this pixel and multiplying it by the color of the vertex associated with this pixel.
Now that we have our first shader, all we have to do to test it is create an object and assign it a sprite, then in the Draw Event of the object you set the shader like this:
// Draw Event
shader_set(shdrColorOverlay);
draw_self();
shader_reset();
Every draw call we make between shader_set() and shader_reset() will have the shader applied to it. Here, we are drawing the object sprite with our passthrough shader:
-
As you might have guessed, this does not visually changing anything, as this is a simple pass-through shader. However the sections below outline some simple steps you can take to modify this and change the way the sprite will be drawn. Each of the section shows a different shader that you can create and use in your projects, explaining the steps required to create them and why we are doing things the way we are.
Every draw call we make between shader_set and shader_reset will have the shader applied to it. Here, we are drawing the object sprite with our passthrough shader:
+
As you might have guessed, this does not visually changing anything, as this is a simple passthrough shader. However, the sections below outline some simple steps you can take to modify this and change the way the sprite will be drawn. Each of the sections shows a different shader that you can create and use in your projects, explaining the steps required to create them and why we are doing things the way we are.
We can edit the base shader now to do something different. We'll not be touching the vertex shader part, and only editing the fragment shader, and to start with we'll do a very simple operation, which is to make the shader draw the sprite using the colour red. We'll do this by simply changing the gl_FragColor to be red., like this:
+We can edit the base shader now to do something different. We'll not be touching the vertex shader part, and only editing the fragment shader, and to start with we'll do a very simple operation, which is to make the shader draw the sprite using the colour red. We'll do this by simply changing the gl_FragColor to be red, like this:
// Color Overlay Fragment Shader
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
This will give us the following result:
-
Not exactly what we expected! What we need to remember is that every sprite is ultimately a rectangle, so unless we consider transparency - which we haven't - this is the result we’ll get.
In the image above, the rectangle changes size because the base sprite has had the "empty" space around it cropped automatically when it was placed on the texture page by GameMaker, so each animation frame the triangles that make it up are different sizes to fit the cropped size of the frame. If you disable this option, then you'd simply have a motionless red square on the screen.
-Above we mentioned the texture2D function, and we'll use that to grab the color at the pixel we are working on and get the transparency from it. The return value of is texture2D is a vec4, where the components are the red, green, blue, and alpha, in that order. We can access the alpha channel either by putting a period followed by an a or a w after the variable name. This corresponds to RGBA and XYZW, respectively.
-Here’s the updated code:
+
Not exactly what we expected! What we need to remember is that every sprite is ultimately a rectangle, so unless we consider transparency - which we haven't - this is the result we'll get.
In the image above, the rectangle changes size because the base sprite has had the "empty" space around it cropped automatically when it was placed on the texture page by GameMaker, so each animation frame the triangles that make it up are different sizes to fit the cropped size of the frame. If you disable this option, then you'd simply have a motionless red square on the screen.
+Above we mentioned the texture2D function, and we'll use that to grab the color at the pixel we are working on and get the transparency from it. The return value of texture2D is a vec4, where the components are the red, green, blue, and alpha, in that order. We can access the alpha channel either by putting a period followed by an a or a w after the variable name. This corresponds to RGBA and XYZW, respectively.
+Here's the updated code:
// Color Overlay Fragment Shader
varying vec2 v_vTexcoord;
@@ -143,20 +143,20 @@
We are now assigning a new vec4 to gl_FragColor, where the red channel is maxed, the green, and blue channels are zero, and the alpha channel is the same as the original texture. The output looks like this:
-
Now that’s what we were after! We have replaced the color of every pixel with red, but have kept the alpha channel intact.
Having to change the shader each time we want to use a different color isn’t a good idea, especially since we’d need to have a separate shader for each color we want. Instead, we will pass the color information to the shader using a uniform. To do this, we first need to get a pointer to the uniform. We will do this in the Create Event of our object that has the sprite by adding:
+We are now assigning a new vec4 to gl_FragColor, where the red channel is maxed, the green and blue channels are zero, and the alpha channel is the same as the original texture. The output looks like this:
+
Now that's what we were after! We have replaced the color of every pixel with red, but have kept the alpha channel intact.
Having to change the shader each time we want to use a different color isn't a good idea, especially since we'd need to have a separate shader for each color we want. Instead, we will pass the color information to the shader using a uniform. To do this, we first need to get a pointer to the uniform. We will do this in the Create Event of our object that has the sprite by adding:
// Create Event
_uniColor = shader_get_uniform(shdrColorOverlay, "u_colour");
_color = [1.0, 1.0, 0.0, 1.0];
All we need to do is call shader_get_uniform() to get a pointer to the uniform. The parameters we need to pass are the shader asset name (without quotation because we want to pass the ID that GameMaker generates for us) and the name of the uniform variable inside of the shader, this time as a string. This name needs to match exactly the one inside the shader code for it to work. We have also added a colour variable so we can change it at runtime and have it remember our changes.
-Now the code in our draw event will change slightly to pass the uniform variable.
+All we need to do is call shader_get_uniform to get a pointer to the uniform. The parameters we need to pass are the shader asset name (without quotation because we want to pass the ID that GameMaker generates for us) and the name of the uniform variable inside of the shader, this time as a string. This name needs to match exactly the one inside the shader code for it to work. We have also added a colour variable so we can change it at runtime and have it remember our changes.
+Now the code in our Draw event will change slightly to pass the uniform variable.
// Draw Event
shader_set(shdrColorOverlay);
shader_set_uniform_f_array(_uniColor, _color);
draw_self();
shader_reset();
It’s the same code as before, but before we draw anything, we need to pass all the uniform values to the shader. In this case, we are passing the color as an array of floats. As for the shader, we will change it to include the uniform and use it, so it becomes:
+It's the same code as before, but before we draw anything, we need to pass all the uniform values to the shader. In this case, we are passing the color as an array of floats. As for the shader, we will change it to include the uniform and use it, so it becomes:
// Color Overlay Fragment Shader
varying vec2 v_vTexcoord;
uniform vec4 u_colour;
@@ -165,14 +165,14 @@
We declare a variable with the same name as in the create shader (u_colour) and we pass it as the first three components of the gl_FragColor vector, taking advantage of swizzling. If we compile again, we should see this:
-
Now the shader is much more useful and reusable. It’s up to you to add more functionality if you need it to set the color (using the variable _color) during runtime.
We declare a variable with the same name as in the create shader (u_colour) and we pass it as the first three components of the gl_FragColor vector, taking advantage of swizzling. If we compile again, we should see this:
+
Now the shader is much more useful and reusable. It's up to you to add more functionality if you need it to set the color (using the variable _color) during runtime.
Making a black and white shader is a great way to learn more about how shaders work, and a lot of beginners start by trying to do this, since conceptually it's quite simple: get every pixel and assign it a shade of gray. But is it simple? Not quite...
-When using RGB colour, if all three components are the same value, then we get a gray tone. The naïve approach to creating a shader to use this idea would be to add all three color channels (red, green, and blue) and then divide it by three. After that you'd assigned the value to all three channels, thus creating a gray tone. Here’s what that fragment shader looks like:
+When using RGB colour, if all three components are the same value, then we get a gray tone. The naïve approach to creating a shader to use this idea would be to add all three color channels (red, green, and blue) and then divide it by three. After that you'd assigned the value to all three channels, thus creating a gray tone. Here's what that fragment shader looks like:
// Black and white fragment shader
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
@@ -184,14 +184,14 @@
One thing you might have noticed is that in the gl_FragColor code, we're multiplying the vec4 with something called v_vColour. This is a variable passed by the vertex shader which tells us the color of the vertex associated with this pixel. It’s always a good idea to multiply your final calculated color with the vertex color. In most cases, it won’t do anything, but if you changed the vertex color in GML, this will reflect that (by using functions such as draw_sprite_ext() or draw_sprite_general() to change the image_blend).
-As for the draw event, it’s quite simple since we don’t have a uniform to pass in:
+One thing you might have noticed is that in the gl_FragColor code, we're multiplying the vec4 with something called v_vColour. This is a variable passed by the vertex shader which tells us the color of the vertex associated with this pixel. It's always a good idea to multiply your final calculated color with the vertex color. In most cases, it won't do anything, but if you changed the vertex color in GML, this will reflect that (by using functions such as draw_sprite_ext or draw_sprite_general to change the image_blend).
+As for the Draw event, it's quite simple since we don't have a uniform to pass in:
// Draw Event
shader_set(shdrBlackAndWhite);
draw_self();
shader_reset();
Let’s compile and see what we got.
-
This looks great already, right? Well, yes and no... there is a solution that is more “correct”, since instead of adding the components and dividing by three, we multiply each component by the standard NTSC values for black and white. Here’s the modified fragment shader code:
Let's compile and see what we got.
+
This looks great already, right? Well, yes and no... there is a solution that is more "correct", since instead of adding the components and dividing by three, we multiply each component by the standard NTSC values for black and white. Here's the modified fragment shader code:
// Black and white fragment shader
varying vec2 v_vTexcoord;
@@ -202,17 +202,17 @@
We use the dot product as a shorthand for multiplying each component of texColor with the correct weights and then add them together. If you are unfamiliar with the dot product, this is essentially what’s happening:
+We use the dot product as a shorthand for multiplying each component of texColor with the correct weights and then add them together. If you are unfamiliar with the dot product, this is essentially what's happening:
float gray = (texColor.r * 0.299) + (texColor.g * 0.587) + (texColor.b * 0.114);
-In the end, it looks very similar, but it’s technically more correct.
+In the end, it looks very similar, but it's technically more correct.

Our final shader example is a fun one and can be used to add life to text and buttons and other things. We'll start simple and add functionality gradually since this shader is highly customizable. There's quite a lot to cover for this one, so if you feel a bit lost or confused, please go back and re-read some of the sections above.
-The first thing we want to do is color pixels with every hue, depending on the pixel’s horizontal position. The way to do this is to set the x position to be the hue and then convert from HSV (hue, saturation, brightness) format to RGB (red, green, and blue) format. For this, we will need to write a helper function in our fragment shader that takes HSV values and returns an RGB vector. We will use a single function which does this without the need for any if statements, as using conditionals in shader code makes shaders very slow, and should be avoided.
-Here’s what the shader looks like at this stage:
+The first thing we want to do is color pixels with every hue, depending on the pixel's horizontal position. The way to do this is to set the x position to be the hue and then convert from HSV (hue, saturation, brightness) format to RGB (red, green, and blue) format. For this, we will need to write a helper function in our fragment shader that takes HSV values and returns an RGB vector. We will use a single function which does this without the need for any if statements, as using conditionals in shader code makes shaders very slow, and should be avoided.
+Here's what the shader looks like at this stage:
// Fragment Shader
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
@@ -231,25 +231,25 @@
There's a bit more going on here than in the previous examples, but most of it should be fairly obvious to you now. First, there’s our hsv2rgb function, which takes a vec3 with our HSV colour and returns another vec3 with our RGB conversion. In the main function, we start by creating our HSV colour, where the hue is our x position, and we’ll leave the saturation and brightness as 1.0 for now. Then, we get the alpha from the texture so it only colors our sprite character and not the entire sprite rectangle (as we did in the colour overlay example, above). Lastly, we set our Fragment color to be our HSV color converted to RGB with the alpha, multiplied by the vertex color (good practice to do this always).
+There's a bit more going on here than in the previous examples, but most of it should be fairly obvious to you now. First, there's our hsv2rgb function, which takes a vec3 with our HSV colour and returns another vec3 with our RGB conversion. In the main function, we start by creating our HSV colour, where the hue is our x position, and we'll leave the saturation and brightness as 1.0 for now. Then, we get the alpha from the texture so it only colors our sprite character and not the entire sprite rectangle (as we did in the colour overlay example, above). Lastly, we set our Fragment color to be our HSV color converted to RGB with the alpha, multiplied by the vertex color (good practice to do this always).
As for our draw code, it is trivial at the moment:
// Draw Event
shader_set(shdrRainbow);
draw_self();
shader_reset();
Let’s check out what we got:
-
We are close to what we want, but there’s an issue: we are not seeing all the colors at once in every frame of the animation, and the colors seem to change randomly. The reason is that we assumed that v_vTexcoord gave us the coordinates of the sprite, starting at the top-left corner (0,0) and ending in the bottom right corner (1,1), which is standard in shaders. However, for optimization, GameMaker stuffs as many textures together as it can fit in what is called a texture page, and because of that, this is how our texture actually looks:
As explained above, v_vTexcoord gives us the absolute coordinates of the sprite within this entire texture page, but what we want is a value from 0.0 to 1.0 that only covers our current sprite. This process is called normalizing (getting a value and translating it to a 0 to 1 range). To normalize our horizontal values, we need to know the values of x0 and x1 in the picture above. Luckily, GameMaker has a function that gives us the location of every corner in our sprite within the texture page. First, we need to go to the Create Event and create a uniform to pass this data over to the shader:
Let's check out what we got:
+
We are close to what we want, but there's an issue: we are not seeing all the colors at once in every frame of the animation, and the colors seem to change randomly. The reason is that we assumed that v_vTexcoord gave us the coordinates of the sprite, starting at the top-left corner (0, 0) and ending in the bottom-right corner (1, 1), which is standard in shaders. However, for optimization, GameMaker stuffs as many textures together as it can fit in what is called a texture page, and because of that, this is how our texture actually looks:
As explained above, v_vTexcoord gives us the absolute coordinates of the sprite within this entire texture page, but what we want is a value from 0.0 to 1.0 that only covers our current sprite. This process is called normalizing (getting a value and translating it to a 0 to 1 range). To normalize our horizontal values, we need to know the values of x0 and x1 in the picture above. Luckily, GameMaker has a function that gives us the location of every corner in our sprite within the texture page. First, we need to go to the Create Event and create a uniform to pass this data over to the shader:
// Create Event
_uniUV = shader_get_uniform(shdrRainbow, "u_uv");
And we modify the draw event to get the values and then pass them to the shader:
+And we modify the Draw event to get the values and then pass them to the shader:
// Draw Event
shader_set(shdrRainbow);
var uv = sprite_get_uvs(sprite_index, image_index);
shader_set_uniform_f(_uniUV, uv[0], uv[2]);
draw_self();
shader_reset();
The function sprite_get_uvs() takes a sprite and an index, and it returns an array with tons of information, such as the coordinates for each corner, how many pixels were cropped to optimize it, etc. We are interested in two of those values: the left and right coordinates of the sprite, which are stored in uv[0] and uv[2] respectively. In the fragment shader, we will use those values now to calculate the normalized horizontal position like this:
+The function sprite_get_uvs takes a sprite and an index, and it returns an array with tons of information, such as the coordinates for each corner, how many pixels were cropped to optimize it, etc. We are interested in two of those values: the left and right coordinates of the sprite, which are stored in uv[0] and uv[2] respectively. In the fragment shader, we will use those values now to calculate the normalized horizontal position like this:
// Fragment Shader
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
@@ -271,7 +271,7 @@
Here we add the uniform variable at the top of the file with the same name we used in the Create Event. Next, we calculate the normalized horizontal position by translating our current x coordinate to the origin ( v_vTexcoord.x - u_uv[0]) and then we divide it by the width of the sprite to make the range from 0 to 1 (u_uv[1] - u_uv[0]).
+Here we add the uniform variable at the top of the file with the same name we used in the Create Event. Next, we calculate the normalized horizontal position by translating our current x coordinate to the origin ( v_vTexcoord.x - u_uv[0]) and then we divide it by the width of the sprite to make the range from 0 to 1 (u_uv[1] - u_uv[0]).
The result is:
There we go! This is exactly what we wanted. We can see every color of the spectrum inside our sprite.
You might be happy with that, but we can have some more fun with this shader. What if we added an offset to the colors based around time to produce movement? To do this, we will need two extra variables for speed and time. We will also need two more uniforms, one for each of the new variables, so the Create Event becomes:
@@ -284,7 +284,7 @@We also need to increase the time every frame, so in the Step Event we add:
// Step Event
_time += 1 / game_get_speed(gamespeed_fps);
Let’s go to the draw event now to send these uniforms to the shader:
+Let's go to the Draw event now to send these uniforms to the shader:
// Draw Event
shader_set(shdrRainbow);
var uv = sprite_get_uvs(sprite_index, image_index);
@@ -318,7 +318,7 @@
If you did everything correctly, you should be seeing something like this:
-
To finish this shader, we will add a few more uniforms to customize it even further. The first two are to control the saturation and brightness. The next one we'll call "section" and its function is to allow the user to pass a number between zero and one to determine what percentage of the entire spectrum we see at a time. Last, we will add a variable called "mix", which will specify how much we want to mix our shader color with the original texture color (1.0 is all rainbow, 0.0 is all texture). As always, let’s start by adding the variables to the Create Event:
To finish this shader, we will add a few more uniforms to customize it even further. The first two are to control the saturation and brightness. The next one we'll call "section" and its function is to allow the user to pass a number between zero and one to determine what percentage of the entire spectrum we see at a time. Last, we will add a variable called _mix, which will specify how much we want to mix our shader color with the original texture color (1.0 is all rainbow, 0.0 is all texture). As always, let's start by adding the variables to the Create Event:
// Create Event
_uniUV = shader_get_uniform(shdrRainbow, "u_uv");
_uniTime = shader_get_uniform(shdrRainbow, "u_time");
@@ -335,7 +335,7 @@
Our draw event changes to include these uniforms like this:
+Our Draw event changes to include these uniforms like this:
// Draw Event
shader_set(shdrRainbow);
var uv = sprite_get_uvs(sprite_index, image_index);
@@ -384,14 +384,14 @@
-
That's the end of this short guide and you should now have a better understanding of how shaders work and some of the uses they can be put to. You should take your time to play with the shaders you've created following this guide, and try to experiment with them do other things - how about creating a blur shader, or a shader that makes a gameboy-style monochrome screen? - since shaders are an incredibly powerful tool for adding visual complexity and style to your games.
+That's the end of this short guide. You should now have a better understanding of how shaders work and some of the uses they can be put to. You should take your time to play with the shaders you've created following this guide, and try to experiment with them to do other things - how about creating a blur shader, or a shader that makes a Game Boy-style monochrome screen? - since shaders are an incredibly powerful tool for adding visual complexity and style to your games.
We would like to thank Alejandro Hitti and Amazon for permitting us to reproduce this guide. You can find the original version on the Amazon Developer Blog.
-
When programming your game, whether using GML Code or GML Visual, it can be very easy to make mistakes - using the wrong variables, passing the wrong arguments, or using the wrong functions are just some of the most common errors we all make - and these mistakes are not always detected by the syntax checker that is included with the script/action editor. That means that these mistakes will only become apparent when you actually run or compile your game, and even then it can sometimes be difficult to know exactly what is going wrong. It can therefore be of vital importance to know how your game is performing on the chosen device, as well as see what instances are in the room, what global variables have been created and a whole host of other details. Checking these things is called "debugging your code", and any errors or issues you may find are called "bugs".
Now, you can check a lot of these things yourself by adding in so-called "debug code" to your games to display on the screen the information you require, or you can have it that it shows messages when there is an error, but this is often a lot of work and if you aren't sure where the problem is in the first place then it can be a time consuming case of trial and error to track down your bug. For that, GameMaker has a special test mode called Debug Mode which will start the Debugger, and there is also a comprehensive error reporting system which displays messages on Compiling to help you track down any problems with your game.
The sections below cover the different ways that you can debug your game:
@@ -61,7 +61,7 @@This contains preferences for the Package Manager:
@@ -42,7 +40,7 @@
This function can be used to add all the values of all the cells found within the source area of a grid to the values within the destination grid, as illustrated below:
-
NOTE You can also use this function on the same grid to add values from one region of the grid to those stored in another (see code example below).
--
ds_grid_add_grid_region(index, source, x1, y1, x2, y2, xpos, ypos)
-| Argument | -Type | -Description | -
|---|---|---|
| index | -- | The handle of the destination grid. | -
| source | -- | The handle of the source grid. | -
| x1 | -- | The left position of the region of cells to copy from the source grid. | -
| y1 | -- | The top position of the region of cells to copy from the source grid. | -
| x2 | -- | The right position of the region of cells to copy from the source grid. | -
| y2 | -- | The bottom position of the region of cells to copy from the source grid. | -
| xpos | -- | The x position on the destination grid to add the source region to. | -
| ypos | -- | The y position on the destination grid to add the source region to. | -
-
-
-
ds_grid_add_grid_region(grid, grid, 0, 0, 1, 5, 2, 0)
-The above code would copy the region of cells from (0,0) to (1,5) of the DS grid indexed in the variable "grid" and add them to the cells from position (2,0) of the same DS grid .
--
-
-