Jump to content


Photo
* * * * * 2 votes

GML Basics Explained


  • Please log in to reply
9 replies to this topic

#1 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 16824 posts
  • Version:GM:Studio

Posted 21 June 2011 - 03:48 PM

GML BASICS EXPLAINED



The topics in this post have been selected based on many of the common questions asked in the Novice Q&A forum and it contains a list of tutorials designed to explain certain programming concepts and ideas that appear within the GM manual, but that are either not explained at all or very poorly explained. They are meant for beginners in GML to use as a learning tool and as reference material, but that's not to say that some of the more experienced users won't get any benefits from reading these!

Below is a list of the topics covered, just click on the one you want and you will be taken directly to the post...

Hopefully these guides will help you to get the most out of GM and make bigger and better games!

Nocturne

PS: more will be added as they are made, so come back every so often to see what's been added!
  • 3

#2 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 16824 posts
  • Version:GM:Studio

Posted 21 June 2011 - 03:49 PM

ARRAYS EXPLAINED





Introduction

Arrays. They sound boring and look odd, but they can be extremely useful, and are an essential part of programming. Why? Well, here are just a few things that would be impossible without arrays -

  • Menus. An array or two can make it much easier to create a good menu system.
  • RPGs. Arrays are essential for making RPGs, because instead of having a jumble of variables, you just have a few lines, which you can refer back to at any time.
  • Card Games. Good for keeping track of cards and hands and can even be shuffled!
  • High scores and other statistics. Much easier to keep track of one array than multiple variables.
That's just the tip of the iceberg as arrays are one of the most fundamental and useful programming tools you can use, and you'd be surprised at the applications they can have! Let's find out a bit more about them then...



1D Arrays

Okay, we can use an array for those things mentioned above, but what is an array? What does it look like? Well, something like this...

myarray[0] = 1;
This is a 1D (one dimensional) array. Not very impressive, or scary looking is it? So let's break down the parts of this array to see what it means.

myarray
This is the array's name. Just like any other variable, it can be anything you want from simply "aaa" to "mymumscow".

[0]
This is the position within the array that we are using. You see, an array is basically a list, with each position on that list having a specific number, which is what we put in the []. It's worth noting that an array ALWAYS starts at 0 and can never be negative! Now let's expand our array to include different positions...

myarray[0] = 0;
myarray[1] = 0;
myarray[2] = 0;
Our array now contains three positions, 0,1 and 2, and we have initialized our array to 0. Eh? What does that mean? Well, an array has to be initialized before we can use it or GM will give us an error. Initializing an array just means that we give each position of the array an initial value in preparation for it to be used elsewhere in the object. This is important to remember as it means that you have to do a certain amount of planning before using one...
An easy way to initialize an array is to use a repeat loop like this...

var i;
i=0;
repeat(10)
{
myarray[i]=0;
i+=1;
}
This simple code will initialize a ten position array (0-9) to 0, in that each position in the array contains the value 0. but what if we want to initialize the array with different values for each position? Well for that we have to manually type each and every position ourselves, but there is a nice trick to help us keep track of things there too...

count = 0;
myarray[count] = "Hello"
count += 1;
myarray[count] = "How"
count += 1;
myarray[count] = "are"
count += 1;
myarray[count] = "you?"
count += 1;
As you can see, we haven't used any numbers in the actual array, rather a variable to count up through the values. This has two benefits... One, we don't have to worry about typos or errors when writing out the array positions, and Two, we have in the variable "count" the number of positions that the array contains, which can then be used elsewhere in the object. Very useful!

With that done how do we use an array for practical things? Exactly the same as we would use a normal variable! Look...

total = myarray[0] + myarray[5]; //Add to array values together
if myarray[9] = 10 {do something}; //Check an array value
draw_text(32, 32, myarray[3]); //draw an array value
BUT (and this is an important 'but') since arrays are numbered consecutively, this means you can loop through them to perform extra actions too (like we did to initialize it)...

var i, total;
i=0;
repeat(10)
{
total += myarray[i];
draw_text(32, 32 + (i * 32), myarray[i]);
i+=1;
}
draw_text(32, 32 + (i *32), total);
The above code will add up all the values in our array, draw each of them and draw the total value at the end. Handy eh?



2D Arrays

Now that we know what a normal array looks like, let's look at a 2D (two dimensional) array.

 myotherarray[0,0] = 7;
Hmmm... this array now has TWO values! What do they mean? Well, as before, each number points to a position, only this time each position has a position! Think of it as a list within the list, where the first value is the list number and the second value is the position. Here is an extended example :

myarray[0,0] = 1;
myarray[0,1] = "hello";
myarray[0,2] = 55.5;
myarray[1,0] = 0;
myarray[1,1] = "world";
myarray[1,2] = -67.89;
Here is that same array in two different diagrams to help you visualise exactly what is going on...

Arrays as a table...
Spoiler

Arrays as a tree...
Spoiler



So what practical use is this? Well, Here is one small example of what you can do... Say you have a game and you want to spawn four different enemies at four different points depending on a random value. Well, we can use a 2D array to do this and save writing out a load of code.

 //CREATE EVENT
 //First, initialize the array with the values we want
 enemy[0,0] = obj_Ogre; //Object
 enemy[0,1] = 32; //x position
 enemy[0,2] = 32; //y position
 enemy[1,0] = obj_Knight;
 enemy[1,1] = 608;
 enemy[1,2] = 32;
 enemy[2,0] = obj_Skeleton;
 enemy[2,1] = 608;
 enemy[2,2] = 448;
 enemy[3,0] = obj_Slime;
 enemy[3,1] = 32;
 enemy[3,2] = 448;


 //EVENT TO CREATE THE OBJECT LIKE AN ALARM
 var i;
 i=irandom(3); //get a random number from 0 to 4
 instance_create(enemy[i,1], enemy[i,2], enemy[i,0]); //Use the array to create the object
See how much easier that is? It uses far less code than an "if / then / else" structure or even a "switch", and as the array is initialzed all together in the create event it is MUCH easier to edit and change any of those values as they are not hard-coded into the rest of the object codes.



Summary

Hopefully you now have a grasp of what an array is, how it can be used and the difference between a 1D array and a 2D array. These concepts are essential if you wish to become a good programmer, not just with GM but with any other language as they all use arrays in one form or another.

For further reading Chronic also has a tutorial on arrays HERE.

Thanks for reading!

Nocturne


  • 5

#3 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 16824 posts
  • Version:GM:Studio

Posted 21 June 2011 - 03:50 PM

GML MATHS FUNCTIONS EXPLAINED




Introduction

The manual in GM has a large list of mathematical functions, but it is rather short on explanations and examples of what they do or how they are used... this tutorial aims to clear up any confusion and remedy this by giving a short explanation of all the functions along with a small example of them being used. In this tutorial all functions are listed using the same format :

Function
What the manual says

  • Short explanation plus example of use


Hopefully this will make it easy to read through and keep the information well defined for future reference should you need it.



Part I - General Functions

random(x)
Returns a random real number between 0 and x. The number is always smaller than x.

  • This is good for probabilities where returning an integer (whole number) is not necessary. For example, random(100) will return a value from 0 to 99, but that value can be 22.56473! You can also use real numbers and not integers in this function like this - random(0.5), which will return a value between 0 and 0.4999999.

random_range(x1,x2)
Returns a random real number between x1 (inclusive) and x2 (exclusive).
  • As above, but this time it returns a random number between the specified range, and (again) this return value does not need to be an integer. For example, random_range(20,50) will return a random number from 20 to 49, but the value may be a real number like 38,65265. Real numbers can also be used.
irandom(x)
Returns a random integer number between 0 and x (inclusive when x is an integer).
  • This is a very useful function that only returns integers (whole numbers). So irandom (10) will return a number from 0 to 10... real numbers can also be used but the upper value will be excluded, so irandom(9.5) will return a value from 0 to 9 only.
irandom_range(x1,x2)
Returns a random real number between x1 (inclusive) and x2 (inclusive). Both x1 and x2 must be integer values (otherwise they are rounded down).
  • this is the same as random_range() only with integer values. So irandom_range(10,35) will return an integer between 10 and 35. As with the irandom() function, real numbers can be used, in which case they will be rounded down to the nearest integer EG: irandom_range(6.2,9.9) will give a value between 6 and 9.
choose(val1,val2,val3,...)
Returns one of the arguments choosen randomly. The function can have up to 16 arguments.
  • Sometimes you want to specify something other than numbers for a random selection, or the numbers you want are not in any real order or within any set range. In these cases you would use choose() to generate a random result. For example, say you want to create an object with a random sprite at the start, then you would have sprite_index = choose(spr_Cactus, spr_Flower, spr_Tree), which will set the sprite index to one of those three sprites.
abs(x) Returns the absolute value of x.
  • An absolute value is a value that ignores the sign of the value. So abs(5) will return 5 but abs(-3) will return 3. The value checked can be real or integer, EG: abs(-5.56) will return 5.56.
sign(x)
Returns the sign of x (-1,0 or 1).
  • This function returns whether a number is positive, negative or neither (0). For example : sign(458) will return 1, sign(-5) will return -1 and sign(0) will return 0.
round(x)
Returns x rounded to the nearest integer.
  • Just as it says, round() takes a number and rounds it up or down to the nearest integer value. If the decimal value is less than 5 it gets rounded down, but if it is greater than 5 it gets rounded up, so round(5.4999) will become 5 while round(5.5) will become 6.
floor(x)
Returns the floor of x, that is, x rounded down to an integer.
  • This is similar to the round() function, but it only rounds down, no matter what the decimal value, so floor(5.99999) will return 5, as will floor(5.2), floor(5.6457) etc...
ceil(x)
Returns the ceiling of x, that is, x rounded up to an integer.
  • Similar to floor(), but this time always rounding up to the nearest integer no matter what the decimal value is. So, ceil(3.0001) will become 4, as will ceil(3.9) or ceil(3.564).
frac(x)
Returns the fractional part of x, that is, the part behind the decimal dot.
  • This function will return only the decimals behind the dot of a value. So frac(3.125) will return 0.125, frac(6.921) will return 0.921, etc...
sqrt(x)
Returns the square root of x. x cannot be a negative value.
  • If you multiply a number with itself, you get the square of that number. So to find what number has been multiplied with itself to get any given positive value we use this. So sqrt(9) will return 3 since 3*3=9.
sqr(x)
Returns x*x.

  • Multiplies a number by itself and so returns the square of that number. EG: sqr(5) would return 25 since 5*5=25.
power(x,n)
Returns x to the power n.
  • This will return the value of a number multiplied by itself "n" number of times. For example, power(5,3) will multiply 5 by itself 3 times and return 125, which is the same as saying 5*5*5=125.
exp(x)
Returns e to the power x.
  • This is the function power(e,x), where e is approximately 2.718281828, and x is the number of times it should be multiplied by itself. This basicaly says how much growth do I get after after x units of time (and 100% continuous growth). So exp(3) would return 20.08, and this means that after 3 time units we have 20.08 times the amount we started with . Further reading HERE.
ln(x)
Returns the natural logarithm of x.
  • The natural logarithm In(x) is the amount of time needed to reach a certain level of continuous growth, where x is the level reached. So if we want to find out how many time units we need to get 20 growth we would use ln(20) which returns 2.99 units of time to get that amount of growth. Further reading HERE.
log2(x)
Returns the log base 2 of x.
  • This function is also know as a binary logarithm. It basically asks "how many 2's do you need to multiply to get x?". A common example of use in programming would be to calculate the number of bits that are needed to represent a number. To do this we calculate the log2(x) of the number, round it down and add 1 - for example log2(100) returns 6.643856, which rounded down is 6, to which we add one and it gives us 7. So we need 7 bits to represent 100. It can also be used for describing exponential growth or decay. Further reading HERE.
log10(x)
Returns the log base 10 of x.
  • Similar to log2(x), log10(x) gets the number of 10's we need to multiply together to get x. So log10(100) returns 2, as multiplying 10 by itself gives 100, log10(1000) returns 3 as 10x10x10=1000 etc...
logn(n,x)
Returns the log base n of x.
  • As the above functions, only you stiplulate the values. EG: logn(5,25) is how many 5's we need to multiply to get 25 which is 2.
min(val1,val2,val3,...)
Returns the minimum of the values. The function can have up to 16 arguments. They must either be all real or all strings.
  • With this function you can get the minimum of a set of values that you input into it. So if you have min(43, 76, 98) it will return 43 as that is the lowest of all the input values.
max(val1,val2,val3,...)
Returns the maximum of the values. The function can have up to 16 arguments. They must either be all real or all strings.
  • This function will return the maximum value of those that it contains, so max(12, 96, 32, 75) will return 96 as that is the highest of all the input values.
mean(val1,val2,val3,...)
Returns the average of the values. The function can have up to 16 arguments. They must all be real values.
  • This function works by adding up all the input values and then dividing them by their own number. So, mean(2, 6, 9, 32) returns 12.25 as 2+6+9+32=49 and 49/4=12.25.
median(val1,val2,val3,...)
Returns the median of the values, that is, the middle value. (When the number of arguments is even, the smaller of the two middle values is returned.) The function can have up to 16 arguments. They must all be real values.
  • Using median returns the value that falls in the middle between the highest and lowest of the input values. This means that median(43,12,25,19,6) would return 19 as it is the middle value between all the rest.

point_distance(x1,y1,x2,y2)
Returns the distance between point (x1,y1) and point (x2,y2).
  • This will give you the distance between two sets of coordinates, namely coordinates x1,y1 and x2,y2.
point_direction(x1,y1,x2,y2)
Returns the direction from point (x1,y1) toward point (x2,y2) in degrees.
  • This will give you the direction in degrees if we go from point x1,y1 to point x2,y2 in a straight line. Remember, direction in GM goes from 0 to 360 with 0 being right, 90 is up, 180 is left and 270 is down, so point_direction(x,y,x-200,y) would return 180 as (x-200,y) is to the left of (x,y).
is_real(x)
Returns whether x is a real value (as opposed to a string).
  • Returns whether a given variable is a real or not. In some cases you want to check and see if a variable in GM holds a real number, and that's when you would use this. It DOES NOT return the real number but rather true/false. So if nnn="fish", is_real(nnn) will return false, but if nnn=200, is_real(nnn) will return true.
is_string(x)
Returns whether x is a string (as opposed to a real value).
  • Returns whether a given variable is a string or not. In some cases you want to check and see if a variable in GM holds a string, and that's when you would use this. It DOES NOT return the string but rather true/false. So if nnn="fish", is_string(nnn) will return true, but if nnn=200, is_string(nnn) will return false.




Part II - Trigonomic Functions

The following functions are all based on trigonometry and as such it is a LOT easier to explain when you have a basic and fundamental understanding of this branch of mathematics. To that end I suggest very strongly that you read this before continuing if you are uncertain about this subject, and if you require further reading then try this.


sin(x)
Returns the sine of x (x in radians).

  • In a right angled triangle sin(x) = Opposite / Hypotenuse where x is one of the three angles. Further reading HERE.
cos(x)
Returns the cosine of x (x in radians).
  • In a right angled triangle cos(x) = Adjacent / Hypotenuse where x is one of the three angles.
tan(x)
Returns the tangent of x (x in radians).
  • In a right angled triangle tan(x) = Opposite / Adjacent where x is one of the three angles.
arcsin(x)
Returns the inverse sine of x.
  • This function simply returns the inverse of sin(x), in that if sin(x)=n, arcsin(n)=x.
arccos(x)
Returns the inverse cosine of x.
  • This function simply returns the inverse of cos(x), in that if cos(x)=n, arccos(n)=x.
arctan(x)
Returns the inverse tangent of x.
  • This function simply returns the inverse of tan(x), in that if tan(x)=n, arctan(n)=x.
arctan2(y,x)
Calculates arctan(Y/X), and returns an angle in the correct quadrant.
  • This function returns the inverse tangent of an angle y/x, where y = Opposite side of triangle and x = Adjacent side of triangle. Unlike arctan(x) the function arctan2(y,x) is valid for all angles and so may be used to convert a vector to an angle without risking division by zero, and it also returns a result in the correct quadrant.
degtorad(x)
Converts degrees to radians.
  • In GM all the trigonomic functions work in radians, but most people work in degrees. This means that to convert your degrees into radians you need to use this function - for example degtorad(180) returns 3.14159265 radians. This function translates degrees into radians using the formula :
angle_radians = angle_degrees * pi / 180

radtodeg(x)
Converts radians to degrees.
  • Once you have done your calculations using sin, or cos etc... the result is in radians. This may not always be what you want and so to turn the radians into degrees we use this function like this - radtodeg(sin(180)) which returns -45 degrees. This function translates radians into degrees using the formula :
angle_degrees = angle_radians * 180 / pi;

lengthdir_x(len,dir)
Returns the horizontal x-component of the vector determined by the indicated length and direction.
  • This function seems confusing at first, but it's not really. It is used to get the x component of a position "len" pixels from the starting point and in direction "dir". Imagine a circle around your object, then imagine a point anywhere on that circle. To move to that point we need to move the object so many pixels in that direction... so this function used with the next one (lengthdir_y) gets the position of that point on the circle to be used in code by the object. Further reading HERE.
lengthdir_y(len,dir)
Returns the vertical y-component of the vector determined by the indicated length and direction.
  • As above only now the function is used to get the y component of a position "len" pixels from the starting point and in direction "dir".




Summary

That's it! I Hope this has helped you come to grips with some of these functions. Obviously, in one post I cannot cover ALL the bases, but hopefully I've explained enough for you to fire up Gamemaker and use some of these in your next game. But, if you are still unsure about a function then start game maker, add a room and an object then start to experiment and see what they do for yourself... that's the best possible way to learn!

Nocturne
  • 3

#4 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 16824 posts
  • Version:GM:Studio

Posted 21 June 2011 - 04:02 PM

PARTICLES EXPLAINED


Introduction

What is a particle?
A particle is a graphic resource that has certain properties which are defined by a particle system. These properties cannot be manipulated directly
for individual particles, but are changed through the code that is used to define the sytem that it belongs to. They are very useful for creating beautiful and flashy effects (or subtle and discreet ones!) in a game without the cpu overhead that using objects has.


What is a particle system?
Think of a particle system like a container that we will use to hold our particles ready for use. We use code to define a series of visial aspects for our particle, and then we place it in the "container" so that we can take it out and use it whenever and wherever we need later.


How do I set one up?
Well, before setting up a system itīs important to know a few things... First off is that most of a particle systems code is only ever called ONCE in the game, usually in some type of controller object in the first room or level (this is not always the case, but for the sake of simplicity, weīll keep it like this!). This is because a particle system, once created, stays in memory and is ready to be used at any time, so if you create it more than once it can quickly up the memory usage and cause serious lag, before eventually crashing the game... In this example we will make a global particle system that can be used by any object at any time...



Part I - Creating A Particle System

Okay, to start with we need to define the particle system and give it a name so that we can use it... As this is going to be a global sytem that any object can use we will do it like this...

global.P_System=part_system_create();

Easy, huh? So thatīs the system created, but what about particles? We have to define them too or the sytem is useless and does nothing! To create a particle you have to define itīs general properties. These are like object properties, but they only apply in a general way to individual particles... What this means is that if you give the particles a movement speed of 1,2 any particle created by the system will have a random speed between 1 and 2 pixels per step, and that overall they will have an average speed of 1.5... Letīs name and add our first particle to the sytem, then...

global.Particle1=part_type_create();

Great, but weīre not ready yet to create our outstanding effects... We have still to define the general properties of our particle (ie: how it looks, itīs speed, rotation, alpha etc...). There are a lot of details that can be put into a particle, so to show them Iīll post what the manual says and include a snippet of code that has them all too...


  • part_type_shape(ind, shape) Sets the shape of the particle type to any of the constants above (default is pt_shape_pixel).
  • part_type_size(ind, size_min, size_max, size_incr, size_wiggle) Sets the size parameters for the particle type. You specify the minimum starting size, the maximum starting size, the size increase in each step (use a negative number for a decrease in size).
  • part_type_scale(ind, xscale, yscale) Sets the horizontal and vertical scale. This factor is multiplied with the size. It is in particular useful when you need to scale differently in x- and y-direction.
  • part_type_color1(ind, color1) Indicates a single color to be used for the particle.
  • part_type_alpha1(ind, alpha1) Sets a single alpha transparency parameter (0-1) for the particle type.
  • part_type_speed(ind, speed_min, speed_max, speed_incr, speed_wiggle) Sets the speed properties for the particle type. You specify a minimal and maximal speed. A random value between the given bounds is chosen when the particle is created. You can indicate a speed increase in each step Use a negative number to slow the particle down (the speed will never become smaller than 0).
  • part_type_direction(ind, dir_min, dir_max, dir_incr, dir_wiggle) Sets the direction properties for the particle type. Again you specify a range of directions (in counterclockwise degrees; 0 indicated a motion to the right). For example, to let the particle move in a random direction choose 0 and 360 as values. You can specify an increase in direction for each step.
  • part_type_orientation(ind, ang_min, ang_max, ang_incr, ang_wiggle, ang_relative) Sets the orientation angle properties for the particle type. You specify the minimum angle, the maximum angle, the increase in each step and the amount of wiggling in angle. You can also indicate whether the given angle should be relative (1) to the current direction of motion or absolute (0). E.g. by setting all values to 0 but ang_relative to 1, the particle orientation will precisely follow the path of the particle.
  • part_type_blend(ind, additive) Sets whether to use additive blending (1) or normal blending (0) for the particle type.
  • part_type_life(ind, life_min, life_max) Sets the lifetime bounds for the particle type.


Before you look at the code, Iīll just mention a couple of things...

  • When you see "wiggle", that means that if you place a number between 1 and 20 the particle will "wiggle" or fluctuate between the min and max values for the code (with 1 being a slow wiggle and 20 being very fast). So a speed min of 2 and max of 5 and wiggle of 20 will occilate very quickly between the min/max speeds for the lifetime of each particle...
  • Lifetime? Thatīs the length of time in steps that a particle will exist for. So, a lifetime of 30,30 will have the particle existsing for exactly 30 steps, but a liftime of 20,60 will have each particle exists for a random number of steps between 20 and 60...
  • There are actually 6 different ways to define colour for a particle (you use only one, not all!), but as this is for beginners I havenīt included them. Check the manual as they are easy to understand and offer more flexibility...
  • There are also 3 different codes for setting alpha (yes, use only the one thatīs needed, not all!)... Again, check the manual as they are very useful...
  • Finally, the blend option. This means that the particle can have additive blending or normal. Whatīs that? Well additive means that itīs brightness will be added to whatever is behind it on the screen, and so gives that saturated glowing look!! Useful for fire and magic effects (for example), but best left off for something like smoke... Experiment to see the differences...

Now to define our global particle using the codes detailed above...

part_type_shape(global.Particle1,pt_shape_pixel) //This defines the particles shape...
part_type_size(global.Particle1,1,1,0,2) //This is for the size...
part_type_scale(global.Particle1,1,1) //This is for scaling...
part_type_color1(global.Particle1,c_white) //This sets itīs colour. There are three different codes for this...
part_type_alpha1(global.Particle1,1) //This is itīs alpha. There are three different codes for this...
part_type_speed(global.Particle1,0.50,2,-0.10,0) //The particles speed...
part_type_direction(global.Particle1,0,359,0,20) //The direction...
part_type_orientation(global.Particle1,0,0,0,0,1) //This changes the rotation of the particle...
part_type_blend(global.Particle1,1) //This is the blend mode, either additive or normal...
part_type_life(global.Particle1,1,20) //this is itīs lifespan in steps...

So thatīs it! We have now defined our particles and they are ready to be used? How do we do that? Read on...



Part II(a) - Creating Particles Directly

There are a couple of ways to create particles, and each has itīs pros and cons... You can use emitters to burst or stream particles, or you can creat particles directly at a point. Which one you use really depends on what you are trying to achieve and the effect you are wanting to create. Iīll start with the easiest of the two, which is creating particles directly with part_particles_create...

part_particles_create(global.P_System, x, y, global.Particle1, 50);

Thatīs it? Yup! That short code above will create at the objectīs x/y coords 50 particles of Particle1 from our global system. Easy, huh? The great thing about that line of code is that it can be used anywhere without any fuss. For example if you place it in the global left pressed event for the mouse in an object and change x/y for mouse_x/y, it will create particles at the mouse position every time you press the button. Or if you have a rocket, then you could place this in the step event and have smoke particles coming every step (although 1 or 2 would probably be better than 50!). You can even have it create particles over an area by changing the x/y coords randomly (eg: "x+20-random(40),y+20-random(40)" will create random particles inside a 40px square...).



Part II(B) - Creating Particles With Emitters

Since Iīve explained the easy way, Iīll now explain the slightly more complex way, which is to use emitters. Emitters are another part of the particle system that has to be defined before being used, so weīll make a global emitter the same as the system and the particles. We also have to decide whether to have a
static (non-moving) emitter and whether we are going to burst or stream the particles, as well as over what area and what kind of distribution we are going to do it. What does all that mean? Well, a static emitter is one that you can define once and forget about as it will no be moving anywhere. Think of a log fire... It doesnīt move, it just emits flames! But a fireball is a non-static emitter and will move across the screen... As for bursting or streaming, a burst is a one off explaosion of particles, whereas a stream is just that... a constant stream of particles every step. As for area and distribution, with emitters you can define an area for emitting particles (rectangle, ellipse, diamond or line) as well as the distribution curve (gaussian, invgaussian, or linear)... Oh, and please read the manual on emitters as (as always!) it contains more info and codes that you may need or find useful!

Here is a set of example codes that define two emitters. One will be static and stream particles over the area of the whole room, while the other will follow
the mouse and burst every 30 steps from a small ellipse...

//CREATE EVENT
//Define and name the emitters
global.Particle1_Emitter1=part_emitter_create(global.P_System);
global.Particle1_Emitter2=part_emitter_create(global.P_System);

//Set up the area that will emit particles
part_emitter_region(global.P_System, global.Particle1_Emitter1, 0,  room_width, 0, room_height, ps_shape_rectangle, ps_distr_linear);
part_emitter_region(global.P_System, global.Particle1_Emitter2,  mouse_x-10, mouse_x+10, mouse_y-10, mouse_y+10, ps_shape_ellipse,  ps_distr_gaussian);

//Set the first to stream 10 particles every step
part_emitter_stream(global.P_System, global.Particle1_Emitter1, global.Particle1, 10);
//This can now be forgotten as it will function until told to stop...

//Set the alarm[0] event to burst the emitter2 particles...
alarm[0]=30;


//ALARM[0] EVENT
//The second emitter has to move to the mouse position so...
part_emitter_region(global.P_System, global.Particle1_Emitter2,  mouse_x-10, mouse_x+10, mouse_y-10, mouse_y+10, ps_shape_ellipse,  ps_distr_gaussian);

//Now to burst 30 particles and reset the alarm[0]
part_emitter_burst(global.P_System, global.Particle1_Emitter2, global.Particle1, 30);
alarm[0]=30;

But what if you want several objects to emit particles? A global emitter can only be in one place at a time, so you would need to create local emitters in each object. These emitters will still use the global particle system and any particles that are within it, but they can be different shapes and sizes and move with the object, making them ideal for rockets or bullets or things... The code is exactly the same as above, but without the "global." before the emitter names, and you will have to 'clean up' in the destroy event of the object too (see Part III, below). Check out room 2 in the tutorial file for examples of this...

Thatīs the creation of particles dealt with but there is one more thing thatīs very important... Cleaning up when you are finished with them...



Part III - Cleaning Up

As I mentioned at the start, once created, a particle system (and itīs particles, emitters etc...) are stored in memory for instant use. Great, but what
happens when you restart the game? Or if your player dies and starts the room again? Well, if you donīt manage the game right you get a memory leak. This is when something is eating up memory and causes lag or even blocks the computer, and is a pretty common problem with first time users of particle systems. How do you avoid this? Well, GM has a couple of functions to delete particle systems and their emitters and things from memory when not in use and with a little bit of planning and these codes it will cease to be a problem...

The first thing you have to do is decide where you are going to create the system and how you will use it. You could create it in the game start event of an object that is in your first room (a menu or title screen), but this means that if you use the restart game codes it will be recreated and cause a memory leak... To avoid that you would have something like this...

part_type_destroy(global.Particle1);
part_emitter_destroy(global.P_System, global.Particle1_Emitter);
part_system_destroy(global.P_System);
game_restart();

This will remove the particle, the emitter and then the system from memory before restarting the game again. Or if you have it in a controller object that is placed in every game room, then you could have the create event that defines the particle system and things, then place the destroy codes in the room end event...Just remember that after thinking about where would be the most suitable place to create the system, think about where would be the most suitable place to destroy the system too!!! If you check out the file that goes with this tutorial you can see what I mean by looking at the room end and destroy events of the objects used.



Summary

Right, now you know the basics about particles, particle systems and emitters, so off to create a game!!! Not quite... As I said at the start, particles are less cpu hungry than objects, but they are not the solution to everything as they will cause lag if you have thousands of them at a time. The best thing to do is experiment and use them carefully to "flesh out" visually a game and give it abit more eye-candy without over doing it... Another thing to take into account is that a particle system can be a chore to set up and test, so I canīt recomend enough that you use one of the many particle designing tools that are available on Yoyo. My personal favorite is Particle Designer 2.3 by Alert Games, as it is very powerful and permits you to export the file as a gml script that can then be imported into any game file... I have also prepared a demo file to acompany this tutorial that you can download here :

http://host-a.net/Ma...r_Beginners.gmk

Thatīs it for me!!! I hope that this tutorial has helped you, and donīt forget to download the example file as itīs a lot easier to understand when you see everything working together than it may seem by just reading this... and if you still thirst for more, then RhysMeyers has a far more extensive pdf file with just about everything particle related HERE.

All the best,

Nocturne

  • 2

#5 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 16824 posts
  • Version:GM:Studio

Posted 07 July 2011 - 10:41 AM

  • Title: VIEWS EXPLAINED
  • Description: Views Explained
  • GM Version: All
  • Registered: no
  • File Type: na
  • File Size: na
  • File Link: na
  • Required Extensions: na
  • Required DLLs: na
Summary


VIEWS EXPLAINED



Introduction


What is a view and why do I need one?
This question is best answered by the GM help file:

...<views> give a mechanism of drawing different parts of your room at different places on the screen. There are many uses for views. First of all, in a number of games you want to show only part of the room at any time. For example, in most platform games, the view follows the main character. In two-player games you often want a split-screen mode in which in one part of the screen you see one player and in another part you see the other player. A third use is in games in which part of the room should scroll with e.g. the main character while another part is fixed (for example some status panel). This can all be easily achieved in Game Maker.

Okay, that gives us an overview of views and how they may be used, but how do we go about setting them up? Well, the main view setup can be done in two distinct (and complementary) ways – by using the views tab in the room editor or by using code form within objects.



Setting Up Views In The Room Editor

Before you can use views in a room, you have to check the Enable the use of Views box on the views tab in the Room Properties window. Now you have a choice of 8 different views to choose between, and each one has a number assigned to it. The first view's number is 0 and the last is 7. There is no difference between each of views, only their number assignment, and they all do the same thing depending on the setup that you give, so when you want to use a view, select it and then check the Visible when room starts box to turn that view on for that room.

Once you have done that, you can start to set up the rest of the parameters, which i will now list and briefly explain :

  • View In Room – this is the the "chunk" of the room that will be shown. You input the initial x/y location of the top left corner, then the width and height of the view in pixels.
  • Port On Screen – this can sometimes confuse people. Basically, it is the size and position of the view (as defined by the previous part) in the game window. Now, you can define the view in the room to be whatever you wish, then use this section to position that view within the game window. It can even be a smaller or larger size (in pixels) than that which you have defined for the view in the room as GM will scale the image shown appropriately. So, for example, if you make the view in the room 320x240 pixels, but the view port is 640x480, the view image will be scaled to twice it's size.
  • Object Following – once defined, a view can be static (non-moving) or can be set to follow a specific object using this section. This means that when the object moves, the view will move too! So here you select the object to follow, then you use the Hbor/Vbor parameters to tell GM how far the player can move within the view BEFORE it starts to follow. So if you set these values to a low number the view won't move until the object is near the edge of the screen, but if you set these values to high numbers, then the view will move much sooner. The Hsp/Vsp values are how fast the view will follow the object. A value of -1 means it will move instantly, and any other value is the amount of pixels per step that the view will move. So, for example, if you move your object with a speed of 3, and place 2 for the Vsp/Hsp values then the object will eventually move outside the view as it is moving faster! This can give some quite nice effects when used right...

Setting Up Views In Code

Views can be set up in code too, and in this way can also be changed while a game is running. This is very useful as it enables things like mini-maps, zooming in/out and other interesting effects. So how is that done? Well, the basic codes are as follows...

  • view_enabled - Whether views are enabled or not. if this is off, NO view will be shown or used.
  • view_visible[0..7] - Whether the particular view is visible on the screen.
  • view_xview[0..7] - X position of the view in the room.
  • view_yview[0..7] - Y position of the view in the room.
  • view_wview[0..7] - Width of the view in the room.
  • view_hview[0..7] - Height of the view in the room.
  • view_xport[0..7] - X-position of the viewport in the drawing region.
  • view_yport[0..7] - Y-position of the viewport in the drawing region.
  • view_wport[0..7] - Width of the viewport in the drawing region.
  • view_hport[0..7] - Height of the viewport in the drawing region.
  • view_angle[0..7] - Rotation angle used for the view in the room (counter-clockwise in degrees).
  • view_hborder[0..7] - Size of horizontal border around the visible object (in pixels).
  • view_vborder[0..7] - Size of vertical border around visible object (in pixels).
  • view_hspeed[0..7] - Maximal horizontal speed of the view.
  • view_vspeed[0..7] - Maximal vertical speed of the view.
  • view_object[0..7] - Object whose instance must remain visible in the view. If there are multiple instances of this object only the first one is followed. You can also assign an instance id to this variable. In that case the particular instance is followed.



view_current* The currently drawn view (0-7). Use this only in the drawing event. You can for example check this variable to draw certain things in only one view. Variable cannot be changed.








Why does the view (or screen) shake? How do I keep the view centered on my player?
The view shakes because one or two of the view's settings are not configured properly. Either the HBor (Horizontal Border) setting or the VBor (Vertical Border) setting is set too high. If you want the view to always be centered on your player, and you don't want the view to shake, do this:

a) Divide the height of your view by two, and then subtract from that the height of your player object's sprite. Set the view's HBor setting to that number.
B) Divide the width of your view by two, and then subtract from that the width of your player object's sprite. Set the view's VBor setting to that number.

That should stop the view from shaking, unless your player object uses sprites that are different sizes. If that is the case then you'll need to give your player object a mask. And then do steps a) and B) calculated to the mask instead of the sprite. (See the help file about masks.)


How do I get the view to follow my player? How do I get the view to change what object it follows?
On the views tab in the Room Properties window select the view that you wish to follow your player. Then click the Object to follow box and select the desired object.

To get the view to change which object it follows during the game, you can use the Set the value of a variable action:

variable: view_object[0]
value: obj_player


You would most likely put it in the Create or Step event of the object. You can also do it in code like this:

view_object[0]=obj_player


How do I get text, shapes, or healthbars to follow the view? How do I get something to follow the view along a certain part of the view?
The general principle in getting something to follow a view is to reference the view's view_left and view_top properties in the x and y settings.

Text
For the drag and drop Draw a text action, change the x and y properties to the following settings:

x: view_left[0]
y: view_top[0]


The text will now be drawn in the upper left corner of the view. To get it to follow along another part of the view you need to add a certain amount to it. This will draw the text in the bottom right corner of the screen:

x: view_left[0]+view_width[0]-50
y: view_top[0]+view_height[0]-16


Of course you'll have to change 50 and 16 to get it precisely aligned the way you want.

In code it would be something like this:

draw_text(view_left[0]+10,view_top[ 0]+10,"TEXT")
Shapes
For the drag and drop Draw a rectangle action, change the x and y properties to the following settings:

x1: view_left[0]
y1: view_top[0]
x2: view_left[0]+50
y2: view_top[0]+20


In code:

draw_rectangle(view_left[0],view_top[ 0],view_left[0]+50,view_top[0]+20)
The same applies for drawing circles, lines, and healthbars as well.


Can you use views to see more than one room at a time?
No. It's impossible.


How do I destroy my bullet objects when they go outside the view?
In the bullet object's Step event you would put this code:

if(x<view_left[0] or x>view_left+view_width or y<view_top[0] or y>view_top[0]+view_height[0])instance_destroy()


How do I refer to the different view properties in code?
Each reference to a view's property has a basic structure that is followed. It begins with view_ and then the property you want to reference and then comes whichever view number you're referencing [0] (and then if your changing a property next comes a = followed by the new setting).

Example:

view_hspeed=5
  • 2

#6 urban

urban

    GMC Member

  • GMC Member
  • 3 posts
  • Version:GM:Studio

Posted 19 October 2012 - 05:14 AM

Thank you, I'm just learning the basics now. I got tripped up in the first array section because in the newer versions of GM you need to assign a value to a variable. It doesn't automatically assign to 0 anymore apparently, so I had to make sure to write "total=0;".

Edited by urban, 19 October 2012 - 07:04 AM.

  • 0

#7 Truth_

Truth_

    GMC Member

  • New Member
  • 6 posts
  • Version:Unknown

Posted 19 November 2012 - 07:09 AM

I have no idea what any of this is, but after reading the first section, it seems well explained. Good work.
  • 0

#8 Stinktier86

Stinktier86

    GMC Member

  • GMC Member
  • 51 posts
  • Version:GM:Studio

Posted 07 April 2013 - 05:37 PM

Just a newbie's food for thought regarding fixing memory leaks related to particles (But first of all, a big thank you for writing these wonderful tutorials - i've learned so much already from you!)...

Wouldn't it be good practice to, rather than keeping the particle system in any menu/ingame room with memory leak prohibiting code, let room0 be a global initializing room where

1)one object with just a creation event contains:
2)Most global definitions for the sake of tidyness

3)the particle system

 

and

4)Once through with all its tasks, the object transfers the user to the intro/presentation/menu/game rooms who never go back to the initializing room, ever, unless the game isn't designed around a reset feature (which then should include the system destroying lines)?

Still being new to GML and practical game design in general, this is what my guts tell me to do and as such it is my 2 cent contribution. View this as an addition to the tutorial and if it doesn't make sense, please make a remark or two.

And once again, thanks for the very intuitive and didactive tutorials.

One thing i feel is missing in the trigonomy tutorial is basic applications (ie. swing/move object relative to point, direction, length, etc... maybe it falls out of the basic scope?)

Kind regards,
Stefan


Edited by Stinktier86, 07 April 2013 - 05:39 PM.

  • 0

#9 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 16824 posts
  • Version:GM:Studio

Posted 08 April 2013 - 06:38 AM

The particle tutorial was designed to get people up and running and so doesn't cover the finer points... But you are quite correct in that it would be a good idea to create the system globally from some init object/room and then forget about it. That's what I generally do! however, if certain particles are only used at very specific points in your game, then why have them throughout? It all depends on how you are making the game and what you need to do with them.

 

As for the Trig examples, again, that article is designed as an over-view of the functions, since the manual itself is a bit vague about what they do and how to use them.

 

Thanks for reading and I'm glad that i've been of some help to you!


  • 0

#10 Ruub

Ruub

    GMC Member

  • GMC Member
  • 429 posts
  • Version:GM:Studio

Posted 08 April 2013 - 10:40 AM

Cool Nocture!

 

How about a 3rd section on arrays: DS functions :D


  • 1




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users