In the "Games" section on CodeGym, you'll find exciting projects that involve writing popular computer games. Want to create your own version of the popular games 2048, Minesweeper, Snake, and other games? It's simple. We've turned game writing into a step-by-step process.To test your abilities as a game developer, you don't have to be an advanced programmer, but a specific set of Java knowledge is necessary. Here you'll find information that will be useful in game writing.

1. Inheritance

Working with the CodeGym game engine involves using inheritance. But what if you don't know what that is? On the one hand, you need to understand this topic: it is studied in Level 11. On the other hand, the engine was specially designed to be very simple, so you can get away with superficial knowledge of inheritance. So what is inheritance? Putting very simply, inheritance is a relationship between two classes. One of them becomes the parent, and the other becomes a child (descendant). Moreover, the parent class may not even know that it has descendants. In other words, it doesn't gain any particular advantage by having descendants. But inheritance gives a descendant many advantages. And the most important one is that all of the parent class's variables and methods appear in the descendant as if the code of the parent class was copied to the descendant class. This is not an entirely accurate description, but it will suffice for a simplified understanding of inheritance. Here are some examples to better understand inheritance. Example 1: The simplest inheritance.
public class Parent {

}
The Child class inherits the Parent class using the extends keyword.
public class Child extends Parent {

}
Example 2: Using the parent class's variables.
public class Parent {

   public int age;
   public String name;
}
The Child class can use the Parent class's age and name variables as if they were declared in the Parent class.
public class Child extends Parent {

   public void printInfo() {

     System.out.println(name+" "+age);
   }
}
Example 3: Using the parent class's methods.
public class Parent {

   public int age;
   public String name;

   public getName() {
      return name;
  }
}
The Child class can use the Parent class's variables and methods as if they were declared in the Child class. In this example, we use the getName() method.
public class Child extends Parent {

   public void printInfo() {

     System.out.println(getName()+" "+age);
   }
}
This is what the Child class looks like to the compiler:
public class Child extends Parent{

   public int age;  // Inherited variable
   public String name;  // Inherited variable

   public getName() {  // Inherited method.
      return name;
  }
   public void printInfo() {

     System.out.println(getName()+" "+age);
   }
}

2. Overriding methods

Sometimes there are situations where we make our Child class inherit some very useful Parent class, along with all its variables and methods, but some of the methods don't work quite how we want them to. Or not at all how we want them to. What can we do in this situation? We can override the method we don't like. This is very easy to do: in our Child class, we simply declare a method with the same signature as the method in the Parent class, and then we write our own code in it. Example 1: Overriding a method.
public class Parent {

   public String name;

   public void setName(String nameNew) {
       name = nameNew;
  }

   public getName() {
      return name;
  }
}
The printInfo() method will display "Luke, No!!!"
public class Child extends Parent{

   public void setName(String nameNew) {
       name = nameNew + ", No!!!";
  }

   public void printInfo() {
      setName("Luke");
      System.out.println(getName());
   }
}
This is what the Child class looks like to the compiler:
public Child extends Parent {

   public String name;  // Inherited variable

   public void setName(String nameNew)  // Overridden method instead of the inherited method {

       name = nameNew + ", No!!!";
   }
   public getName() {  // Inherited method.

      return name;
   }
   public void printInfo() {

     setName("Luke");
     System.out.println( getName());
   }
}
Example 2: Some inheritance magic (and method overriding).
public class Parent {

   public getName() {
      return "Luke";
  }
   public void printInfo() {

     System.out.println(getName());
   }
}
public class Child extends Parent {

   public getName() {
      return "Luke, I am your father";
  }
}
In this example, if the printInfo method (from the Parent class) is not overridden in the Child class, when this method is called on a Child object, its getName() method will be called instead of the Parent class's getName() method.
Parent parent = new Parent ();
parent.printnInfo();
This code displays "Luke" on the screen.
Child child = new Child ();
child.printnInfo();
This code displays "Luke, I am your father" on the screen.
This is what the Child class looks like to the compiler:
public class Child extends Parent {

   public getName() {
      return "Luke, I am your father";
   }
   public void printInfo() {

     System.out.println(getName());
   }
}

3. Lists

If you haven't yet met lists (List), here's a brief overview. You can find complete information in Levels 6-7 of the CodeGym course. Lists have a lot in common with arrays:
  • you can store a lot of data of a specific type;
  • they let you get items by their index;
  • element indices start from 0.
Benefits of lists: Unlike arrays, lists can change size dynamically. When a list is created, its size is 0. As you add items to a list, its size increases. Here's an example of creating a list:
ArrayList<String> myList = new ArrayList<String>(); // Create a new ArrayList
The value in the angle brackets indicates the data type that the list can store. Here are some methods for working with the list:
Code Short description of what the code does
ArrayList<String> list = new ArrayList<String>(); Create new list of strings
list.add("name"); Add an element to the end of the list
list.add(0, "name"); Add an element to the beginning of the list
String name = list.get(5); Get an element by its index
list.set(5, "new name"); Change an element by its index
int count = list.size(); Get the number of elements in the list
list.remove(4); Delete an element from the list
You can learn more about lists from the following articles:
  1. ArrayList class
  2. ArrayList in pictures
  3. Deleting an element from an ArrayList

4. Arrays

What is a matrix? A matrix is nothing more than a rectangular table that can be filled with data. In other words, it's a two-dimensional array. As you probably know, arrays in Java are objects. A standard one-dimensional int array looks like this:
int [] array = {12, 32, 43, 54, 15, 36, 67, 28};
We can visualize it like this:
0 1 2 3 4 5 6 7
12 32 43 54 15 36 67 28
The top row indicates the addresses of cells. In other words, to get the number 67, you need to access the array element with index 6:
int number = array[6];
It's all very simple. A two-dimensional array is an array of one-dimensional arrays. If you're hearing about this for the first time, stop and imagine it in your head. A two-dimensional array looks like this:
0 One – dimensional array One-dimensional array
1 One-dimensional array
2 One-dimensional array
3 One-dimensional array
4 One-dimensional array
5 One-dimensional array
6 One-dimensional array
7 One-dimensional array
In code:
int [][] matrix = {
{65, 99, 87, 90, 156, 75, 98, 78},
{76, 15, 76, 91, 66, 90, 15, 77},
{65, 96, 17, 25, 36, 75, 54, 78},
{59, 45, 68, 14, 57, 1, 9, 63},
{81, 74, 47, 52, 42, 785, 56, 96},
{66, 74, 58, 16, 98, 140, 55, 77},
{120, 99, 13, 90, 78, 98, 14, 78},
{20, 18, 74, 91, 96, 104, 105, 77}
}
0 0 1 2 3 4 5 6 7
65 99 87 90 156 75 98 78
1 0 1 2 3 4 5 6 7
76 15 76 91 66 90 15 77
2 0 1 2 3 4 5 6 7
65 96 17 25 36 75 54 78
3 0 1 2 3 4 5 6 7
59 45 68 14 57 1 9 63
4 0 1 2 3 4 5 6 7
81 74 47 52 42 785 56 96
5 0 1 2 3 4 5 6 7
66 74 58 16 98 140 55 77
6 0 1 2 3 4 5 6 7
120 99 13 90 78 98 14 78
7 0 1 2 3 4 5 6 7
20 18 74 91 96 104 105 77
To get the value 47, you need to refer to the matrix element at [4][2].
int number = matrix[4][2];
You may have noticed that the matrix coordinates are different from the classical rectangular coordinate system (Cartesian coordinate system). When you access the matrix, you first specify the y coordinate and then the x coordinate. In mathematics, it is customary to specify the x coordinate first, i.e. (x, y). You may be wondering: "Well, why not rotate your representation of the matrix and then access the elements in the usual way using (x, y)? Doing this wouldn't change the contents of the matrix". Yes, nothing would change. But in the programming world, the accepted practice is to access matrices "first by y, then by x". You should accept this as the proper way. Now let's talk about projecting the matrix to our engine (Game class). As you know, the engine has many methods that change the cells of the playing field at specific coordinates. For example, the setCellValue(int x, int y, String value) method. It sets a specific cell with coordinates (x, y) equal to the value parameter. You may have noticed that this method takes x first, just like in the classical coordinate system. The engine's other methods work in a similar way. When developing games, it will often be necessary to reproduce the state of a matrix on the screen. How do we do that? First, you need to iterate through all the matrix elements in a loop. Second, call the display method for each of them, using REVERSED coordinates. For example:
private void drawScene() {
    for (int i = 0; i < matrix.length; i++) {
        for (int j = 0; j < matrix[i].length; j++) {
            setCellValue(j, i, String.valueOf(matrix[i][j]));
        }
    }
}
Naturally, the reversal works in both directions. You can pass (i, j) to the setCellValue method and simultaneously take element [j][i] from the matrix. Reversing the coordinates may seem a little difficult, but you need to remember it. And always, if you encounter any problems, you should grab a piece of paper and a pen, draw the matrix, and reproduce the processes involving the matrix.

5. Random numbers

How do you work with a random number generator? The Game class defines the getRandomNumber(int) method. Under the hood, it uses the Random class from the java.util package, but the way you work with the random number generator doesn't change. getRandomNumber(int) takes an integer as an argument. This number will be the upper limit on what the generator can return. The lower limit is 0. Important! The generator will NEVER return the upper limit number. For example, if you call getRandomNumber(3), it will randomly return 0, 1, or 2. As you can see, it cannot return 3. Using the generator this way is quite simple, but highly effective in many cases. Suppose you need to get a random number in some range: Imagine you need a three-digit number in the range [100..999]. As you already know, the minimum number returned is 0. So you will need to add 100. But in this case, you need to take care not to exceed the upper limit. To get 999 as the maximum random value, call the getRandomNumber(int) method with the argument 1000. But now we remember that we're adding 100 to the result: this means that the upper bound should be reduced by 100. In other words, the code to get our random three-digit number will look like this:
int number = 100 + getRandomNumber(900);
But to simplify this procedure, the engine provides the getRandomNumber(int, int) method whose first parameter is the minimum number to return. Using this method, the previous example can be rewritten as follows:
int number = getRandomNumber(100, 1000);
Random numbers can be used to get a random array element:
String [] names = {"Sarah", "Val", "Sergey"};
String randomName = names[getRandomNumber(names.length)]
Generating certain events with some probability. For humans, mornings begin with a few possible scenarios: Overslept – 50% chance; Woke up on time – 40% chance; Woke up an hour early – 10% chance. Imagine that you're writing a morning outcome generator. You need to generate events with a certain probability. To do this, you again need to use a random number generator. Different implementations are possible, but the simplest should be based on the following algorithm:
  1. set the limits used to generate a number;
  2. generate a random number;
  3. process the obtained number.
In this case, the maximum will be 10. Call the getRandomNumber(10) method and analyze that it we can return. It can return 10 numbers (from 0 to 9), each with the same probability — 10%. Now we need to combine all possible results and map them to our possible events. Your imagination may think up a lot of possible combinations, but here's the most obvious: "If the random number is in the range [0..4], we have the "Overslept" event; if the number is in the range [5..8], we have the "Woke up on time" event; and if the number is 9, then we have the "Woke up an hour early" event. It's all very simple. There are 5 numbers in the range [0..4], each of which may be returned with a probability of 10%, for a total of 50%; there are 4 numbers in the range [5..8], well, and 9 is just one number that appears with a probability of 10%. This whole slick design looks even easier in code:
int randomNumber = getRandomNumber(10);
if (randomNumber < 5) {
    System.out.println("Overslept");
} else if (randomNumber < 9) {
    System.out.println("Woke up on time");
} else {
    System.out.println("Woke up an hour early");
}
In general, there are tons of ways to use random numbers. You're limited only by your imagination. But they are most effectively used if you need to repeatedly get some result. Then the new result will be different from the previous one. With some probability, of course. That's all for now! If you want to learn more about the "Games" section, here is some useful documentation that can help: