Thursday, June 26, 2014

Creating A Simple RPG Part 1: Player Control And NPC

    It seems like it is not easy for me to post during school time... Anyway...

    During last few weeks I've been thinking about making an RPG-like game with Game Maker. I've started working on it and decided to put my progress here as I move forward. Here in this article I will tell you about how I made my character and NPC characters move around without overlapping walls. By the way, I know I can use tileset feature of Game Maker, but I was actually trying to make a random dungeon generator which requires tiles exist as individual objects, therefore no, I won't use that feature.

    First of all I would like to say that the tileset I'm using is pretty awesome and it should get its credit here. The set is created by DragonDePlatino from opengameart.org and is called DAWNLIKE 16x16 Universal Rogue-like Tileset V1.8. And as DragonDePlatino wished, I also credit DawnBringer for awesome color palette.

    Now I'm relieved... Let's start!

Floors (Things you can walk on) And Walls (Thou shall not pass! things)

    You might have seen it many times before if you have played indie RPG's like Ahriman's Prophecy before: sometimes there are some buggy-like tiles that player should not be able to pass over but somehow it does. For example there is a high cliff but player can go up like there is an invisible ladder. To avoid this first thing that comes on mind is putting an object that player cannot pass through. But this time player will not be able to walk on little things like carpets on the floor or tall grasses in the field etc. The main thing about making tiles passable and not making it look weird is creating some kind of layer structure. By layer structure I mean sorting everything by their vertical position and volume. There should be floor in the lowest layer, and a carpet above it, and the player that can freely move above it. There also should be a wall in the same layer as player so that player should not able to pass through it, and all above them there should be light effects and HUD's so that they won't get overlapped by tilesets as we move our character. To summarize:

0: Floor.
1: Thin things on the floor.
2: Player, walls, player-size objects, NPC's etc.
3: Lights and other effects.
4: HUD's (like lifebars, score, inventory etc.)
5: Message windows, menus...

    We have this kind of a layer feature in GM. It is called "Depth" and things get "upper" as depth "decreases". To begin with, we will create a character, give it a sprite and make it solid. Then as we said, give it a depth of "-2". This will make it 2 level higher than any other object in depth 0. Then create another object for floor, do not make it solid and give it a depth of 0. And another object for walls, make it solid and give a depth of -2. Then create a small room with your newly created objects, like this:

Animated Sprite?
    Yes! We can make an animated sprite. From the DAWNLIKE set, I chose a sprite, which has only 2 frames. To animate it, I simply used an alarm function.

    Inside the Create Event of character I put in a code:
image_speed = 0;
kicker = 0;
facing = 0;

    After I add an Alarm 1, and put this if command inside:
if (step=0) {step=1} else {step=0}
alarm[1] = 30;

    And inside Step Event of character:
image_index = step;

    This is just a simple clock system that in every 30 frames It changes step value, and changes image index as step value changes.

Let's Get Moving!
    There are several ways to make a character move, I will show you one of the shortest ways. But what I actually trying to do is making player stay in grid all the time. Like if I pressed UP and released, player should move upwards until it comes to another grid cell instead of stopping immediately. This way we can get rid of un-wanted situations, like "DAMN IT I CAN'T GET INTO THAT DAMN DOOR!". And also I want the character actually "move", not just jump to the desited position like in most rogue-like games.

    To begin with, we will need two local variables for our character. I named first one as facing, it will be used for testing which way the player is facing. And the second one as kicker, which will keep player moving until we release the button. Inside the Create event, put these variables with zero value:
facing = 0; kicker = 0;

Now add an event from Keyboard, and choose "<Any key>" from the list. Inside that, we will add a code with if command:

if (kicker = 0)
{

}

Inside the brackets, we will put the following code:

if (keyboard_check(vk_down)) and (place_free(x,y+16)) {vspeed = 1; alarm[0] = 16; facing=0;kicker=1;}
if (keyboard_check(vk_right)) and (place_free(x+16,y)) {hspeed = 1; alarm[0] = 16;facing=1;kicker=1;}
if (keyboard_check(vk_up)) and (place_free(x,y-16)) {vspeed = -1; alarm[0] = 16;  facing=2;kicker=1;}
if (keyboard_check(vk_left)) and (place_free(x-16,y)) {hspeed = -1; alarm[0] = 16;facing=3;kicker=1;}
if (keyboard_check(vk_down)) {alarm[0] = 16;facing=0;kicker=1;}
if (keyboard_check(vk_right))  {alarm[0] = 16;facing=1;kicker=1;}
if (keyboard_check(vk_up)) {alarm[0] = 16;facing=2;kicker=1;}
if (keyboard_check(vk_left))  {alarm[0] = 16;facing=3;kicker=1;}

    It looks a little complex but I will explain. As you see there are 2 different If structures within the code above. The first line directly checks if the pressed button was DOWN arrow. And not only that, It also checks if the place that is 16 pixel down the player is free. If these two conditions met, then it gives player a vertical speed of 1 for 16 frames, which will move player down for 16 pixels. Then sets an alarm for 16 frames, just when the player would be moved 16 pixels. After that it defines direction by giving it zero value. As you can see if player moves right, facing becomes 1, moving up makes 2 and left makes 3. And lastly there is a setting for kicker that makes it 1. When kicker is not zero, then none of the movement functions work, this way the player always moves 16 pixels each time.

    In the second type of if command, it again checks for the button pressed, but not for the empty places. This is just for making player change its facing if it cannot move. Turn back to the picture of my room and take a look at the dead-end at the top right corner. If we won't add another if command like this, then it would be impossible for the player to turn left or right in that corridor, because left and right side are not empty. This command will not give any speed to the player, but change it's facing direction.

   And lastly add an Alarm 0 event, and put these little code inside:
speed=0;
kicker = 0;

    This way each time we call the Alarm 0, player will stop moving and immediately be able to move again.

    Doing this, we also made another good trick too. The trick is that player will continuously move until we release the button, and it will always stop at the right place of the grid. Go ahead and try it!

What About Non-Player Character's?
    For an NPC, we will do the exact same thing as we did for character, except, we will make them move in every 160 frames instead of pressing buttons. Don't forget to make your NPC sprite a two-step one just like the player sprite! Now copy the player object and name the copy as NPC, then delete the Keyboard event for <Any key>. Inside the Create Event, put another alarm: Alarm[2] = 160;. Create an Alarm 2 event, and put the following code:

if (kicker = 0)
{
 to = choose(0,1,2,3);
 switch (to)
 {
  case 0: if (place_free(x,y+16))
  {vspeed = 1; alarm[0] = 16; facing=0;kicker=1;}
  else
  {alarm[0] = 16;facing=0;kicker=1;}
   break;
 case 1: if (place_free(x+16,y))
  {hspeed = 1; alarm[0] = 16;facing=1;kicker=1;}
  else
  {alarm[0] = 16;facing=1;kicker=1;}
  break;
 case 2: if (place_free(x,y-16))
  {vspeed = -1; alarm[0] = 16;  facing=2;kicker=1;}
  else
  {alarm[0] = 16;facing=2;kicker=1;}
  break;
 case 3: if (place_free(x-16,y))
  {hspeed = -1; alarm[0] = 16;facing=3;kicker=1;}
  else
  {alarm[0] = 16;facing=3;kicker=1;}
 break;
 }
}
alarm[2] = 160;

    This one again works with the same kicker stuff. To make it choose a direction randomly, I just put a choose function and assigned it to a variable called "to". Then added a switch command for to, and defined what to do for each to values with case statements. Each if statement inside the cases checks for if the desired to direction is empty, if empty it moves the NPC and changes its direction, if not it does not move the NPC but still changes the direction. And in the end it recalls Alarm 2 after 160 frames to choose another direction and move NPC again.

This way your NPC should be moving itself. And this is the end of this tutorial.



    I hope someone can make use of these series I am going to write during summer. Next time I will show you how to make simple message windows that can change it's place depending on players position.

Thursday, August 29, 2013

Random Terrain Generation (RTG) With Matrices And Calculation Cells


In my previous tutorial I wrote about how we can make use of Perlin Noise for terrain generation. Perlin Noise is used because it gives totally random results, however the RTG motor I wrote was really slow since it requires to take information directly from the monitor. In this tutorial, I will show you how to simulate the same method without calling information from the screen, but using matrices instead. This way we will get much more fast results with just a little matrice knowledge.

How To Generate Terrain With Matrices And Calculation Cells?
First of all if we try to define what a matrice is, we can say that it is a two-dimensional number table. For example:
[5] is a one-dimensional number with one number,
[5   2] is a two-dimensional number table with a size of 1x2. Same way;
|5   2|
|4   7|  is also a two-dimensional number table with a size of 2x2.

While creating terrains, first of all we will create a matrice but way more larger than the ones in the examples, maybe some 256x256 sized-ones. But to make it easier to understand I will explain everything with a 8x8 matrice. So think about a 8x8 matrice of which all numbers are zero.

For the next step, we will assign random numbers from a limited interval for each component of this matrice. I will use [0,32] interval. I want to create an island, therefore I will assign numbers only to the red area I've shown above, and leave the ones on the outside as zero. After assigning numbers, I will be something like this:

The next step is using canculation cells. Canculation cell is a function that applies a specific operation over a specific area of any matrice. For this example I will use a 3x3 sized calculation cell, which will add up all the numbers in a 3x3 area and assign the total number to the component in the middle of the calculation cell. This calculation cell will be applied all over our matrice to generate a new matrice of higher numbers.

Above on the left, the green areas with red midpoint are our calculation cells. As you see for the cells on the corners, most of the numbers left outside. For the ones on the sides, most of the numbers are inside the matrice. And for the middle ones all of the numbers are in the cell. And above on the right is our second matrice that is generated after the calculation cell operations are finished. You must note that the one on the right and the first matrice we created are TOTALLY DIFFERENT. That means you must create a second matrice for the results of calculation cells. If you record the results of the calculation cells on the source matrice, that will give a problematic terrain generation.

But How Did It Work?
Let us take a look at the calculation cell on the top-left corner. What our calculation cell does is adding up all the numbers inside itself, and then assigning the total number at the midpoint of the result matrice. So, the top-left cell added up 0+0+0+18 = 18, and assigned it to the red component of the result matrice, which can be seen as an 18 in a yellow box on the right matrice.

For the one at the left side:  0+20+0+7+0+28 = 55' is total number and 55 is added to the midpoint.

And fot the middle cell: 24+30+14+15+1+17+8+14+27=150, which can also be seen on the right as assigned to the midpoint.

This operation will be done for each component in the matrice, which means for a 8x8 matrice, calculation will be done 64 times..

How Do We Generate Terrain From This Matrice?
We will use the same logic as the one in Perlin method. We will define a sea level, for example 90, and assign every component below this as sea, above this as land. For our 8x8 matrice, I applied a color scale as follows and achieved the result:

I know it doesn't look beautiful. This is because a 8x8 matrice gives a really low resolution. As out matrice gets larger (for example a 225x255 sized matrice), the resolution gets larger and we get better terrains. I generated a contour map for our matrice and this way enhanced the resolution 16 times:

Applying This Method To Game Maker
In Game Maker, we use GRID's instead of matrices. For the calculation cell operations, we will use ds_grid_get_mean command and define a "cell range" variable.

For the first step we generate a sprite and an object, which we will use as "empty space". The color of the sprite doesn't matter, however it is better to make it square. I used a 16x16 white sprite and named my object as empty.

Now create a new script and name it as terraingen. Now we will assign some variables in the beginning to make it easier to change later. These are my variables:

nrange = 32;    //upper boundary of the random numbers.
range = 5;       //range of the calculation cell.
srange = 9;     //range of the second level calculation cell*
border = 3;    //the thickness of the area that will be left as zero (for island-like generations)
tilesize = 16;   //size of our tiles, which is same as sprite size.

*You don't have to create a secondary calculation cell here, however the more you use calculation cells, the better your terrain becomes.

Now create three grids (the actual number is n+1, where n is your calculation cell number, I have 2 cells, therefore I created 3 grids). The first one is our randomly generated source matrice, the second one is our result matrice for first calculation cell operations, and the third one is our result matrice for secondary calcualtion operations.

global.grid1 = ds_grid_create(room_width/tilesize,room_height/tilesize);
global.grid2 = ds_grid_create(room_width/tilesize,room_height/tilesize);
global.grid3 = ds_grid_create(room_width/tilesize,room_height/tilesize);

This way we created three different grids of which sizes' depend on our empty object's sprite size.
After we filled our room with our empty object (see: Useful Code Groups) now we will assign random numbers to our matrice. With a "double for loop" we can do this operation:
for (i=border;i<room_width/tilesize-border;i+=1) //horizontal working for loop
{
  for (j=border;j<room_height/tilesize-border;j+=1) //vertical working for loop
  {

    ds_grid_set(global.grid1,i,j,random(nrange));  //function that assigns random numbers
  }
}


The code above: increases i and j variables one-by-one from (border, grid size - border) interval and does ds_grid_set operation for each (i,j) coordinate inside the grid. Here, ds_grid_set operation assigns a random number from (0,32) interval for (i,j) coordinates.

Now the next step is creating our calculation cell and making it work. We will create another double-for-loop, however this time our ds_grid_set function will write over our "second grid". And our function that calculation cells operate is ds_grid_get_mean.

for (i=0;i<room_width/tilesize;i+=1)
{
   for (j=0;j<room_height/tilesize;j+=1)
     {

       ds_grid_set(global.grid2,i,j,ds_grid_get_mean(global.grid1,i-range,j-range,i+range,j+range));
     }
}


The ds_grid_get_mean function does not work as same as the one in our 8x8 matrice example. This grid function adds up all the number in the area it works on, and then divides the total to the total component number inside the area, which actually means it calculates mean value. For example when our range is 2, that means we will move 2 cells further from the middle point in four direction. If (i,j) = (8,8), than the function will work as:
ds_grid_set(global.grid2,8,8,ds_grid_get_mean(global.grid1,6,6,10,10));
This function uses the following coordinates for the operation:
(6,6)    (7,6)   (8,6)   (9,6)   (10,6)
(6,7)    (7,7)   (8,7)   (9,7)   (10,7)
(6,8)    (7,8)   (8,8)   (9,8)   (10,8)
(6,9)    (7,9)   (8,9)   (9,9)   (10,9)
(6,10) (7,10) (8,10) (9,10) (10,10)

which actually is a 5x5 matrice. Since a 5x5 matrice conist of 25 components, the function divides the total number to 25 after adding all the given components up, and assign the result to the midpoint at grid2 which is (i,j) = (8,8)

Now we will do the exact same considering grid2 as our source and grid3 destination, while using srange as our new range.

for (i=0;i<room_width/tilesize;i+=1)
{
   for (j=0;j<room_height/tilesize;j+=1)
     {

       ds_grid_set(global.grid3,i,j,10*ds_grid_get_mean(global.grid1,i-srange,j-srange,i+srange,j+srange));
     }
}

As you see we multiplied the value by 10. We did this do decrease decimal values and make better calculations, so it is not essential.

After all these, we now creates our random matrice global.grid3 using calculation cells. All these calculations take only one or two seconds, which is really fast. The speed here depends on the number of multiple calculation cell operations and range values for each.

Now it comes to create a terrain from this grid. We will now open our empty object, add a create event, add Execute Code inside and write this inside the code:
alarm[0]=2;
We have to do this because we don't want the code we will write into the empty object to be executed before the grid operations end. If the code started immediately it would try to get data from the uncalculated cells of our grid, which would cause glitches. To avoid this, we make only 2 frame delay with alarm function.

Now we will add an Alarm event with Alam0 and add an Execute Code operation again. The code we will write here will do assignments depending on elevation which is actually our calculated grid3's values. The codes I used and explanations are as follows:
kolo = ds_grid_get(global.grid1,x/16,y/16); //reads data from grid3, assigns to a temporary variable
w=159;  //sea upper limit
sa=160.5;  //sand upper limit
gr=164;  //grass upper limit
mo=167;  //moutain upper limit
bmo=169; //high mountain upper limit

(kolo < w)
{instance_change(water1,true);}  //if below sea limit, transform into water

if (kolo > w) and (kolo < sa)  
{instance_change(sand,true);}  //if between sea and sand limits, transform into sand

if (kolo > sa) and (kolo < gr)
{instance_change(grass,true);}  //if between sand and grass limits, transform into grass

if (kolo > gr) and (kolo < mo)
{instance_change(mount,true);}  //if between grass and mountain limits, transform into mountain

if (kolo > mo)
{instance_change(bigmount,true);}  //if above mountain limits, transform into high mountain


Now let us create an empty room, for example a 3600x3600 sized one! And then make it run your terraingen script. You can create a new controller object and put into the room or just add into room's creation code. The room size should be proportional to the your tilesize variable to get better results. You can try different range and srange values to see how it differs. My results are as follows for three different variable couples.

    range=5;srange=9;
    range=9;srange=9;
    range=6;srange=15;

Thursday, August 1, 2013

Random Terrain Generation Using Perlin Noise


Noise... I know It doesn't sound good, but the noise I will talk about is something a little different, actually an "useful" noise.

What Is Perlin Noise?
Noise is not only something that is auditory, and Perlin Noise is not an auditory noise, but a visual one. On empty channels of our oldy televisions, we used to see repeatedly moving black and white points on the screen, that are called "static" or "noise". Perlin Noise takes one of those pointy pictures, stacks them on top of another a few times this way it generates a cloud-like grayscale image out of the noise. It sounds a little complex huh?

Stack them on top of another?
Well, this doesn't sound good, either, but if you don't know what Perlin Noise is, you will be surprised when you see the results. First of all, I will show you a 240x240 pixel sized black-white noise. Then I will choose a smaller (actually half) sized area inside it. Then choose even smaller one (quarter), and smaller (1/8), and so on.



The figure on the left shows the areas I choose, and on the right is my 240x240 noise. Now let's choose an area of 240x240 pixels from the noise, which will cover the whole noise, and name it as n0. Then choose a smaller one, 120x120 pixels, and name it n1. Following this method, we will pick our n2, n3, n4 ,n5 and n6.




Now we will expand all the smaller squares into the size of the largest one: 240x240, which means we will have 7 images at same size. Then we will put these images on top of another, however we want all the images to be visible a the same time. To accomplish this, we will change the alpha (transparency) values of our images. Most graphic editors use alpha values between 0 and 255, but in Game Maker this interval is 0 and 1. If an image has an alpha value of 0, that means the image is totally invisible, and 1 means it is visible. We have 7 images, therefore if we give each image an alpha value of 0.14, when we stack them up the image will have a total of 0.98 alpha, which is clearly visible. After changing alpha values and stacking the images, the resulting image is like the one on the right, which is actually likable.

How to create terrain from Perlin Noise?
I've explained how does a Perlin Noise created and what it looks like. To create a terrain out of this grayscale image, we will assign different values for different shades of grey. Think about any pixel on the Perlin Noise; we will check how "white" that pixel is and assign a value between 0 and 255 accordingly. Considering 0 is totally black and 255 white, we will decide the sea level; let's make it 140 for now. From now on, we know that any pixel that has a white-ness below 140 will be considered as sea and painted blue. And any pixel above 140 will be ground and painted green. This way, we will be created a terrain-looking image from plain noise. This method can be applied in 3D too, but of course it will be more complex. Minecraft uses Perlin Noise to generate random 3D maps.


Generating Perlin Noise Via Game Maker
Firstly we should create a noise, which is pretty easy.Create a spriteless control object, it will be needed later. Next create a 1x1 white sprite and create an "pixel" object with this sprite. For the object, add "Create" event and insert an "Execude Code". Inside the code write the following:
image_blend = choose(c_white,c_black);
This will make the pixel object automatically paint itself to either white or white after created. Like I told at Useful Code Groups page, fill your room with pixel object using control object you created before. Now create a square room, and put only your control object here. When you start your game, you would see your created noise. By adding a "Restart Game" command into your control object for any key on the keyboard, you can restart game and see that it is totally random.

Next step is dividing our noise into smaller pieces and save each piece as a new sprite. Doing this is a little complex, I hope I can explain clearly. We said that our first noise is n0, we can assign it as a sprite with this code:
global.noise0 = sprite_create_from_screen(0,0,room_width,room_height,false,false,0,0);
This command takes an area from the screen and saves it as a new sprite for the name "global.noise0". Now we have a global sprite whose left-top corner is at (x,y)=(0,0) and size is the same as the room. Making the name "global" is important, this way we will be able to call it from any object.

Repeating the same thing we will create our noise1, but this time left-top point should be random and size of the square should be the half of the noise0's. Now be careful: imagine that we divided the image n0 into four equal pieces. If our smaller n1 square's left-top corner stays inside the left-top piece of n0, then the n1 square will always be inside n0. See the left figure below: there is our n1 red square with a star at left-top corner. Now imagine you hold that star inside the yellowish area and move the red square anywhere with it. If star doesn't leave the yellowish area, red square never gets out of the n0. Same logic works differently for other smaller squares, see image on the right for noise2.

Then when defining the new square, we should assign the left-top corner in a random place between 0 and A/2, and make the size of the square A/2. We can use irandom(x) command to assign random wholenumbers.

global.noise1 = sprite_create_from_screen(irandom(room_width/2),irandom(room_height/2),room_width/2,room_height/2,false,false,0,0);

When creating noise2, we should be careful that side's width will be A/4 and motion area for the left-top corner will be larger since size of the square will be smaller (check figure on the right above). Now the area for the left-top corner will be between 0 and 3*A/4. If you are good at math, here is a general formula for this considering N is noise number:

global.noise(N)= sprite_create_from_screen(irandom((2^(N) - 1)*room_width/(2^(N)),irandom((2^(N) - 1)*room_height/(2^(N))),room_width/(2^(N)),room_height/(2^(N)),false,false,0,0);

Using this formula, we achieve the following codes below:
global.noise0 = sprite_create_from_screen(0,0,room_width,room_height,false,false,0,0);
global.noise1 = sprite_create_from_screen(irandom(room_width/2),irandom(room_height/2),room_width/2,room_height/2,false,false,0,0);
global.noise2 = sprite_create_from_screen(irandom(3*room_width/4),irandom(3*room_height/4),room_width/4,room_height/4,false,false,0,0);
global.noise3 = sprite_create_from_screen(irandom(7*room_width/8),irandom(7*room_height/8),room_width/8,room_height/8,false,false,0,0);
global.noise4 = sprite_create_from_screen(irandom(15*room_width/16),irandom(15*room_height/16),room_width/16,room_height/16,false,false,0,0);
global.noise5 = sprite_create_from_screen(irandom(31*room_width/32),irandom(31*room_height/32),room_width/32,room_height/32,false,false,0,0);
global.noise6 = sprite_create_from_screen(irandom(63*room_width/64),irandom(63*room_height/64),room_width/64,room_height/64,false,false,0,0);

If you don't want to write too long, you can write the code for noise0 and then use a FOR LOOP for the rest of the noises. Something like: for (N=1;N<7;N+=1){GENERAL FORMULA}

We created sprites from the noise, now we don't need all these pixel objects, create a new room or delete them all. with your control object. Now it's time to stack these sprites with changing their alpha values and sizes; then we need draw_sprite_stretched_ext command. Technically the alpha value for each should be 0.14, but the values I gave below gives the best results:
draw_sprite_stretched_ext(global.noise0,0,0,0,room_width,room_height,c_white,0.2);
draw_sprite_stretched_ext(global.noise1,0,0,0,room_width,room_height,c_white,0.2);
draw_sprite_stretched_ext(global.noise2,0,0,0,room_width,room_height,c_white,0.3);
draw_sprite_stretched_ext(global.noise3,0,0,0,room_width,room_height,c_white,0.3);
draw_sprite_stretched_ext(global.noise4,0,0,0,room_width,room_height,c_white,0.5);
draw_sprite_stretched_ext(global.noise5,0,0,0,room_width,room_height,c_white,0.5);
draw_sprite_stretched_ext(global.noise6,0,0,0,room_width,room_height,c_white,0.4);

Numbers at the end of the each code are alpha values. Giving different numbers will alter your perlin noise, for example making alpha for noise0 will make your noise more ribbed.

Perlin Gürültüsünden Arazi Elde Etmek
Now we will choose a sea level and paint the noise accordingly. This step will be hard for both Game Maker and your computer. I'm sure there are simplier methods to do these, but my capacity is not enough for now -_-'. I use a room with sizes 320x320, which makes 102400 pixel object total. Making 102400 object re-color themselves takes 3 - 5 minutes. It takes long because while controlling the "whiteness" of a pixel, Game Maker directly uses your monitor to work and achieve data about the pixel. Of course, if your computer is faster, the time will be shorter.

There are a lot of alternatives for coloring. I've created another control object to create a height map, too. It runs itself after coloring finished and gives some height visually. This is the code I use:

if (p < room_width)  //If my control variable is smaller then room width;
{
for (i=0;i<room_width;i+=1) //scans the room horizontally
{
for (j=p;j<(p+1);j+=1)  //scans the pixels at line i
{
pointed = color_get_red(draw_getpixel(i,j));   //checks the color of the pixel at coordinates (i,j)
global.tema[i,j] = pointed;  //saves (i,j) pixels color value to the "tema" matrix for height map

if (pointed<140)   //if that value is below 140
{instance_create(i,j,water);}   //creates a water object
else
{instance_create(i,j,ground);}   //if not, creates a ground object instead
}
}
p += 1;  //restarts the process by adding 1 to the control variable
alarm[0] = 2;
}
else
{global.terra = 1;} //if control variable is larger than the room width, starts the height map

Using my "tema" matrix I define the height, and accordingly make water and ground objects lighter or darker. I also put a collision check command inside the ground objects that will transform them into sand objects if they are near water. Here are the results:



I think it looks good, but it is really slow. I'm working on a more comfortable and fast system about this these days, and it goes pretty well. I will write about it in my next entry. You can send email to me if you have questions, requests or recommendations, I appreciate it. :)

You can find the GMK file here:
Perlin_Gurultusu_Rastgele_Arazi.gmk