📜 ⬆️ ⬇️

Developing an AS3 game (Part 1: introduction, utilities)

Purpose: development of a computer game
Target audience: beginners, interested, onlookers
Tools: ActionScript 3.0 **


Note 0:
I will try to achieve relative autonomy for each part, which will allow you to read them optional and out of order.


Note 1:
The text of the article may contain the personal opinion of the author on certain issues. All responsibility for stirring up hot senseless disputes lies with the reader ( 18+ ).
Cycle content



')

Introduction



Note 2:
In the process of reading, you will often find the word “tool” in relation to certain things. This is done on purpose. I believe that the developer for solving certain tasks is able to choose the most suitable tool for this and use it wisely.


Note 3:
In the process of reading, you also often meet the word “process”. It will be used both in the broad sense of the word and in the narrowed technical sense. Without the process there is no creativity. Without a process there is no development.

You may have noticed that I am writing “computer game development”, clearly not specifying which one. It is not just like that. On the one hand, one can say: “it doesn't matter what you write, the main thing is how” *. On the other hand, as you, probably, again, noted, the article implies several parts, because it is, among other things, the whole story. So let the final product be some intrigue of the whole cycle of articles. In fact, the fact that I am setting forth the material through history emphasizes that there is no development without a process.
For a developer, a computer game ** is not just some program, but also some process. During this process (creative, or creative in places, or non-creative in places) a lot of events occur that affect the final product, other products and the process itself, the developer and the people around him.

If you do not take into account the model "to squeeze the maximum profit", then for a start, some initial impulse is important - an idea that will entice you to one degree or another. You draw, revive the process (in imagination, on paper, in a graphic editor) ... etc.
The whole story began when I once again, in between times, looked at the logo of a well-known company ...

I took up my idea (it fascinated me so much that I didn’t check it for “everything is stolen before us” *) and began to draw something on paper. Created text files with brief notes on game mechanics. These were not only technical aspects, but also simply texts, names of musical compositions and games. He grabbed the first Wednesday ( Flash ?!) That he had come across and began to create graphics for the game. Flash ** made it surprisingly easy to translate my drawings from imagination into specific graphic elements, making me want to continue working. I knew that later I could use them directly in my game, which added a few points to my enthusiasm. I read a lot of articles (including here, on habrahabr.ru **) on game development. About what you need to quit the idea to create a game alone. I watched the video, as someone notch created the game in real time, which reinforced my reluctance to agree with “N reasons to quit everything, take three hundred drops of etheric valerian and forget myself to sleep” *.

Having accumulated a sufficient amount (the criterion of sufficiency is not defined) of graphic materials, having in my imagination everything already working as it should, I began to encode. “At first, the Soviet invasion was successful” *, but soon the process stalled. “And then he still stalled. And still stalled. And further..."*

But I was lucky, the starting impulse was so strong that it did not allow me to completely abandon the project. Hooray!..

So, during the development process, I wanted the player to entertain himself with another game during the pause. Something very simple and warm. I needed a game that could fulfill this role. The process was in full swing, and the option came pretty quickly. I switched to a new game, with the same enthusiasm. The process was repeated in miniature, but because the game was simple, its creation was not stalled. On the contrary, the completion of a small game gave an additional impetus to the development of the main one. In the next part we will develop it together. In the meantime ...
During operation, a lot of things changed in the program code, because it always did not suit the developer (and does not suit). I wished that my changes would not spoil an already working game. Whereupon I turned to TDD **. It was necessary to understand what it is: Kent Beck. Test Driven Development: By Example **.


Note 3:
TDD is “not avada kedavra ** to solve all development problems” *. Everyone needs to be used wisely. In particular, it is a handy tool for making changes and correcting errors. Although I used this methodology for development, I cannot say that I always fully adhered to the red / green / refactoring algorithm indicated in it.

So, I'm with ActionScript **, and I need a simple testing tool. Sounds like a challenge.

There are probably some ready-made tools ( overview , for extras ) ** for these purposes. However, wanting to get soaked up in the spirit of testing, I decided to reinvent the wheel.


Note 4:
Dear reader, in my opinion, the invention of a bicycle is not bad. By doing something of your own, you gain invaluable experience and a basic understanding of how this something works. You encounter the problems faced by those who have already solved this problem. It's like learning the basics of programming (you need to study, try to implement sorting, although in most cases you will simply call the “sort ()” method or the like). However, it is unlikely that your bike, written in a couple of hours, will be able to compete with existing solutions (congratulations, if it can). Therefore, in the future, it is worth paying attention to a specific instrument from “people who have caught more than one bug on this” *.


Utilities


We will document the javadoc style code **.


Note 5:
I believe that the code can and should be written so that the comments are not needed. However, if we write the library “for export”, then the question arises about providing the consumer with decent documentation. For such purposes, javadoc ** comments are a good tool for easy creation of such documentation.


Note 6:
ActionScript ** supports the lack of type checking, but it also provides the ability to keep track of them. I believe that if a language provides a tool for tracking types at the syntax level, they should be used. It is necessary to use type checking everywhere, and the lack of testing should be used wisely where this achieves certain functionality. Thanks to tracking types, the compiler will detect a lot of errors at the compilation stage, ultimately saving your time for something more interesting than debugging.


Testing tool


Git: github.com/v-alx-v/as3-unit-tests **
Task: you need the most simple tool that could be used without torment in the subsequent development of games. Designed as a plug-in library with a minimum threshold of entry.

Inspired by JUnit **, given the limitations of ActionScript **, wanting to create the simplest possible tool, I decided to make it, perhaps, not very convenient, but very transparent set of tools (without the explicit involvement of Hogwarts **).

Total: class Tester , abstract class UnitTest , small manager UnitTests for organizing a transparent test run environment, script for launching tests, “launch file”.
In Figure 2 , a simple UML ** diagram of the developed classes can be studied.


picture 2
Unit Test. Uml Chart of developed classes

In order to test a new class, you need to create for it a new class that uses CUnitTest as the base class, add a new class to the launch configuration, and launch the “launch file”.
class Tester
It can be used separately during debugging as a tool for checking the expected values ​​(or you can not use it).
There is nothing difficult here, however, we will not completely relieve ester of dependence ( UnitTests ), since It is more interesting in aggregate, not separately:


/** * Invokes error in test process. * @param strTitle String * @param strComment String */ public function error( strTitle:String, strComment:String = ''):void { this.m_bError = true; CUnitTests.error( strTitle, strComment); } 


class CUnitTest
“There is a desire to declare an abstract class, but in ActionScript ** there is no such possibility. It is possible to declare an interface, but we have some general implementation, so there is no such desire. So let's drink to that ... "*.

We will consider an ordinary class to be abstract, and thanks to the system of exceptions, we will not allow using our abstraction with impunity:


  /** * Gets list of functions to run. * @return Array of Function */ protected function testList():Array { throw new Error( 'testList must be implemented'); } 

The method described above assumes that it is determined by a descendant class. The essence of the method is to return a list of class functions that need to be run (in JUnit ** you would mark such functions with the @ Test annotation).
class CUnitTests
This is the test execution environment (set of static data and functions). Below you will find out that you don’t actually need to work with this class, although it clearly appears in the test launch configuration script.

Of the interesting features - we can ask the environment to use our CMyTester extends CTester for testing. It will be provided to all objects interested in this:


  /** * Tester fabric. * @param strLabel String * @return {@link alx.common.test.CTester} */ public static function createTester( strLabel:String):CTester { return new CUnitTests.s_testerClass( strLabel); } 

So, when using the environment, the CUnitTest class is of actual interest (by expanding it you can create all user tests) and the launch configuration script:


  import alx.common.test.*; CUnitTests.init( CTester, CUnitTests.SIMPLE_MODE, true); CUnitTests.run(); CUnitTests.printResult( root); 

In order to add a new test, we need to import its class and add it to the list to run.
So for the test, for example, test.alx.common.test.CExampleUnitTest extends CUnitTest you need to change the configuration as follows:


  import alx.common.test.*; import test.alx.common.test.CExampleUtitTest; CUnitTests.init( CTester, CUnitTests.SIMPLE_MODE, true); CUnitTests.run( CExampleUtitTest); CUnitTests.printResult( root); 

After launching the “startup file”, the user will receive a window that is filled with red or green color depending on the overall test result (see Figure 1 ). In the console, you can familiarize yourself with the specific testing progress: the version of the framework and the settings with which it is launched, as well as which specific tests (classes) ( EXTENDED_MODE ) and what specific functions in them ( FULL_MODE ) were launched with the test result for each aspect separately. If a failure has occurred, debugging information and a call stack will be displayed (if you have asked for this with a special setting).
By the way ...
  1. A design pattern was applied ** Factory method ** public static function createTester (strLabel: String): CTester , implemented through a kind of Prototype ** CUnitTests.s_testerClass ;




Random number generator


Git: github.com/v-alx-v/as3-random **
Challenge: A random number generator is needed that supports repeating a pseudo-random sequence.

ActionScript ** is so strange that it does not include the base class of random number generation with the support of the possibility of repeating a pseudo-random sequence.
After a quick look at the solutions to the problem on the Internet, I did not find a generator that completely satisfied me. Some kind of “X-ray shift” magic is created during generation, the problem is shifted to the noise generator in a bitmap, or something else.
Having opened the Random source code for Java **, I decided to port the solution to ActionScript **. Unfortunately, in fifteen minutes nothing happened. As a result, another strange implementation was implemented. But, having set my mind resolutely, I nevertheless redid the solution into a closer solution to Java **.
The random number generator was considered by me also from the standpoint of testing. How to test programs that use random numbers?

It seems that the answer here is he - "Luke, you now have the possibility of repeating a pseudo-random sequence" *. It looks convincing. However, taking into account my experience of developing a random number generator, I realized that in the future, I might want to change the implementation of the generator (to make the distribution of pseudo-random numbers closer to a continuous distribution ** or to provide for the possibility of setting the required distribution ** ***). The new solution will also be able to repeat pseudo-random sequences, but not the same as they were before. This means you need:

  1. Implement a new class CNewRandom extends CRandom . Then the “old” code will use the “old” version of the generator without a simple opportunity to fix it (you can argue that if you write the programs correctly, then in general you just need to change the configuration. Yes, but not all are correct). In addition, CRandom remains as garbage, which can not be put in the trash (let's call it the effect of the grandmother);
  2. Update existing class. Then the “old” code is updated by an elementary replacement. There is no garbage. However, tests that rely on certain random sequences stop working;
  3. Think and redo everything.

Of course, option 3
Internal voting results:
  1. 0% (0);
  2. 0% (0);
  3. 100% (1).


After certain wanderings, I still came to an acceptable option. To begin with, an interface was created for the random number generator, and its general functionality is localized in an abstract class. Now you can create the generator itself:

In addition to the usual random number generator, I created a "random number generator for testing" CFakeRandom extends CRandom :

So, there is a CRandom class (something like Java Random **) that needs to be used via the IRandom interface. When testing, instead of CRandom , you should use FakeRandom . There is nothing more to describe here, except to give a simple UML diagram of the developed classes in Figure 3 .


picture 3
Random. Uml Chart of developed classes
By the way ...
  1. Applied design pattern ** Bridge ** IRandom - CAbsctractRandom .




Collections


Git: github.com/v-alx-v/as3-collections **
Task: convenient collections of objects are necessary.

Again, there are many ready-made solutions on the Internet: github.com/danschultz/as3-collections **, www.as3commons.org/as3-commons-collections **.

I did not use them, but at the same time it seems to me that they would completely suit me. We will be completely stubborn and will realize something of our own. Let it probably be crooked, but we can not miss the opportunity to practice.

In general, there is nothing to describe here, because it's just a reproduction of the finished solution. One can only note the fact that in the process of implementing ActionScript ** it turned out to be quite strange again. For a long time I tried to find an adequate way to calculate the hash code for an arbitrary object, but, having spent more than one hour on this problem, I spat on everything and implemented HashMap somehow. Well, all the strength is that you can then, if necessary, return to this problem and change the implementation without fear of breaking the existing code (for example, if the creators of ActionScript ** come to their senses).

The basis, of course, were taken from the collection of Java **. Here I would like to make a lyrical digression ...

The fact is that this is not the first time when I tried to implement collections in ActionScript **, but this is the time when I came to at least some result, but did not drop everything at the beginning of the path. In the process of implementation, I still do not understand some of the things that I encountered while studying the source code of openjdk **.

Problem:
Suppose there is a Collection ** interface and a List extends Collection ** interface.
Question: Do authors not believe in inheritance and define methods in the List that are already defined in the Collection ?

Problem:
Suppose there is an abstract class AbstractCollection ** and there is an ArrayList extends AbstractList extends AbstractCollection **.
Question: I still understand the redefinition of some methods to delegate a task to another object, which is probably related to the improved performance of these methods. But why override the isEmpty method, I refuse to understand. Replacing a generic public boolean isEmpty () {return size () == 0;} with a private public boolean isEmpty () {return size == 0;} is regrettable. Based on the rest of the code, I do not believe that this is just to “save” on the method call.

However, all this is just some trifles, which may indicate a lack of foresight of the author of this article.


Conclusion


"I will not bore you, most respectable reader, with further details ..." *.

In the next issue:



Note 8:
The text is verified by the author, MS Word ** and the person versed in spelling. For errors, contact the written complaint directly to the author.


Note 9:
This is my first post on habrahabr.ru **. Be extremely cruel.



What is hidden behind the asterisks?
* - Some known quote in their circles has been used (directly or rephrased).
** - Some (we will not name names and titles) could pay extra for advertising.
*** - It seems to me that it is possible to create an even more elegant solution to the described problem by revising the approach of generating random numbers in the direction of the distribution laws of a random variable. But for my case this is not necessary, and I don’t want to bore the reader with additional text. If this topic is interesting, it will be possible to consider this issue separately.

P.S
  1. Why does the acronym tag not accept the title attribute?
  2. How to insert text like [dog] [text] into the article and not get a link to the user?
  3. The author considers his code with the desire to open it to the public with the only restriction: the preservation and indication of authorship. One of the tasks now is to study the available open licenses for which one to choose or based on which one to write your own. Consultations are welcome. Although I explicitly indicate here that I am going to present the code to the public, I want to note that as long as the relevant projects have not received the appropriate license file, they are best not to use.

Source: https://habr.com/ru/post/240285/


All Articles