Showing posts with label GML. Show all posts
Showing posts with label GML. Show all posts

Wednesday, 6 June 2012

Arrays in GML : 5 things you probably don’t know


What is GML?

You have most probably heard of Gamemaker, the popular game design software.

Along with Drag-and-Drop (D&D) feature, it also features an extensive coding language, which is formally called “The Game maker Language (GML)”.

According to Mark Overmars, the original creator of Game Maker (which has been recently re-named as Gamemaker), “Game Maker contains a built-in programming language. This programming language gives you much more flexibility and control than the standard actions. This language we will refer to as GML (the Game Maker Language).”

Why this article?

The only official documentation of Game Maker is the help file included with the software. This help file, though complete, documents only what happens when something is used and the correct syntax to use it. But, it leaves out necessary details in some cases.

Among the many features of GML, I find the “Array” portion of the help file least detailed, which is (probably) supposed to be known by the user. Though this is acceptable, it often causes a lot of confusion when using arrays extensively for the first time in a new project. A lot of things have to be guessed. Now the problem lies with this guessing: Everyone with prior programming knowledge tries to think in terms of their previous concepts and experiences. Unfortunately, this often differs considerably due to the different approach of different programming languages.

This problem is concentrated further by the fact that compiled languages like C/C++ (which are most popular among programmers) support only fixed length arrays (without using dynamic memory allocation, of course) compared to GML which supports dynamic arrays (so, practically their lengths are not fixed and can be changed whenever required). Thus, for many programmers, previous concepts have to be tested in GML. This article tries to solve this problem, testing and publishing the result of every exceptional situation that may arise with arrays in GML. I have tried to answer every weird question about arrays that popped up in my head and thus, exposing some of the lesser-known facts about it. But on other hand, you are expected to know what is written in the help file.

Just a word of caution: You probably won’t find anything worth experimenting with arrays after you complete reading this.

So, let’s start…

1.     What does arr refer to when arr is an array? 

A: In GML, nothing is practically defined as a variable of some specific data type. The data type is instead implied based on the value assigned to it at any time. A variable is implied to be an array only when it is assigned a value in this format:
  • a)      arr[ind]=value;   /* in case of 1-D arrays or */  variable_local_array_set(name,ind,value);
  • b)      arr[ind1,ind2]=value; /*in case of 2-D arrays*/variable_local_array2_set(name,ind1,ind2,value);
Now that it is implied as an array, arr actually refers to the arr[0,0] ( which is the same as arr[0] ) position. 

2.     How are the 1-D and 2-D arrays related when a 1-D array is converted into 2-D array and vice-versa? 

 A: After a lot of experimenting, this is the final decision I came to: arr[ind1] is the same as arr[0,ind1] for all practical purposes. The value of arr[ind1] changes to the new value whenever the value of arr[0,ind1] is changed to a new value and vice versa.

3.     Is there any relation between numbers, strings and arrays? 

A: Two-dimensional arrays can be considered as the general data type for both numbers and strings as well as 1-D arrays (Hence, these are the special cases of an 2-D array).

      They are related in the following way:

  • Any number or string variable (let’s say,the variable  named numb_or_string , usually used in code like this:  numb_or_string=something;) is actually the [0,0] position of the 2-D array of the same name(i.e. numb_or_string[0,0] ). Thus, numb_or_string can be alternatively called as numb_or_string[0,0] and vice versa . 
  • Any 1-D array (for eg. arr[ind], used in code like this:  arr[ind]=something;) essentially refers to the [0,ind] position of the 2-D array with the same name(i.e.  arr[0,ind] ).
This answer generalizes the answers given in the first and second question.

As a side note, this is the reason why the same variable name can’t be used for two variables even when they are of different data types.

4.     Which elements of an array are filled with the default value?

 A: This idea is quite simple: I’ll explain it in terms of a 2-D array, though it can be easily applied with 1-D arrays (following the previous rules). The first and second index of a 2-D array is referred to as row and column respectively, for visualization purpose.



   The rules for filling up the elements of an array with the default value (zero) are:

  •   If it’s a global 2-D array, then the [0,0] element is filled with zero.
  •   In both local and global arrays, for any row, all the undefined elements between any two defined element is filled with the default value, zero.
5.     Is there always an error when a negative index is passed to an array?

 A: In terms of 2-d array, an error is always thrown when you use this type of syntax: “arr[ind1,ind2]=value; “ (where atleast one of the values among ind1 and ind2 is negative), to set or get a value. But only in one exceptional case, when you use variable_local_array2_set(name,ind1,ind2,value)  to set a value, such that ind1 is positive but ind2 is negative, no error is thrown. 

     I found out this last exception just out of curiosity. Though practically it is not of much use as the memory is ultimately leaked and so, the value can’t be accessed. IMO, it is some sort of a unimportant bug, so you should probably check if ind2 is negative, before using it in that function.

Tuesday, 15 May 2012

Generating smooth roads for top-down racing games on-the-fly

Prologue:

I am making a fake 3D racing game (like a lot of flash games you have seen). It looks like a first-person racing game, but doesn't use any 3D functions. Why not real 3D, you may ask and the answer is quite simple:
a. Not every game development tool has 3D support
b. It will be lot faster if designed correctly.

When I was creating the tracks, I was a lot bored and it was a tiring task to lay long tracks by hand just for testing. So, I decided to code for dynamic random road generation, so that I will never run out of road :D

The beginning:

At first, I thought it would be quite easy, you know like:

 Generate random points within a small distance and join them to make a road.

But the major flaw that surfaced quickly was that the road was not at all smooth, it was like throwing away some chunk of concrete at places.
My thought was like:
This is not how roads really look like :(
So, I decided to come up with a new approach to tackle this problem and
the next day, I came up with this solution.

Main concept


 The idea is pretty simple. You'll need to have a knowledge of how sine curves are drawn on graphs.
We won't need any transformation matrices for this.

Note: 
1. The co-ordinate system is same as traditional, but the origin is at the bottom-center of the page.
   So, Y is always positive and X can be both be positive and negative upto a certain extent.
2. Co_eff is a constant value which constrains the maximum X co-ordinate of the road in order to
    fit it within the view. It is used as the amplitude of the sine curve.

First of all, I decided that that only full sine curves (one total period) will be used to avoid complexity.

 This also gave me one added advantage of smoothness of the curves even when one sine curve ends and a new one is drawn.

This are the steps for generating the first curve … The rest will follow similarly...

Steps:

1. Generate a random value  (within a  suitable range) and store it as y1
    This y1 value is the (relative) height (distance in the y direction) at which one full sine curve
    terminates.

2. Now, as we know, sine curves have a period of 2⊼ radians.
   But, in our case, the sine curve should start exactly at the current point and terminate exactly at the next
  point (0,y1) [relative to the current point].
  So, we need to find a variable named "value" such that y1=2⊼*value
  We will use a factor of (1/value) with the independent variable [here y-coordinate]
  (as the curves are drawn along y-axis, so the x-coordinate of the initial and final
   point doesn’t change. So, we don’t care about the x-coordinate)

3. Now, draw the curve “ x=co_eff*sin(y/value) ” starting from the initial point.

It will look like this:

Last words...

When I was first thought of this whole dynamic road generation thing, I asked one my friend on Facebook for his view on this matter. From what I could make out, he had a better but not-so-simple approach in mind. So, we decided to make a shared  Google Doc about this and I wrote about this concept there.
As of now, he's working on his version of this solution and hopefully, he will soon be done with it, and we can have a better version in this blog...