HTML and CSS Reference
In-Depth Information
You can probably discern the structure of the map by looking at the array, but it's basically two rooms connected
by a hallway. In your game, you will use "#" to represent walls and " " to represent the floor, where the player can
walk. Now, let's switch gears and create your basic renderer. To get started, create a new file, called renderer.ts ,
in the rogue folder within src. From here, you are going to want to set up your basic module structure:
module rogue.renderer {
}
Next, you define a common API for your renderer to use, taking advantage of an interface, which is part of the
TypeScript language. Interfaces allow you to define all the public methods on a class, and you can use the interface
to type to instead of the class that inherits it. If you have never worked with interfaces before, it should make a little
more sense as you get started building it out. Here is your IMapRenderer interface, which should go inside your
rogue.renderer module:
export interface IMapRenderer {
draw(tiles: any[]):void;
drawTile(column: number, row: number, currentTile: string): void;
clearMap(): void;
}
As you can see, you have three public-facing APIs: draw , drawTile , and clearMap . These will represent the basic
calls that you can make on the map class once you create it. You will also notice that the draw call accepts an array of
tiles, but it has been left generic by using the any[] array type. This allows you to extend your map later if you decide
to use numbers instead of strings to represent the tile values. This is useful if you want to map each tile to a sprite ID,
for example. Now, you are ready to set up the basic code in your game.ts file to render the map. Go back to that file,
and add the following property to the top of the class, just below the invalidate property:
renderer: renderer.IMapRenderer;
You are going to create a renderer, and its type is IMapRenderer , which is the interface you just created. This is
an important part of object-oriented programming called polymorphism (from the Greek polys, “many,” and morphe ,
“form”), meaning “the provision of a single interface to entities of different types.” This is what will enable you to grow
your application and let each of your classes be completely decoupled from the concrete implementation of the class,
instead relying on its interfaces or public methods. As you set up your renderer, the game engine doesn't have to know
anything about the actual class that is in charge of drawing a map; it just requires that whatever you set the renderer
to do is able to call draw , drawTile , and clearMap . To help illustrate this, let's add the following code to your draw
method and replace the “draw called” console.log :
this.renderer.draw(this.tiles);
Now, your game is ready to draw the tiles that you defined. If you try to run this, however, it will fail, because an
interface doesn't include the logic to execute anything. To do that, you will need to create a class that implements your
new interface.
Before moving on, there is one more important thing I should mention regarding interface type. You may have
noticed that you can simply type to it by referring to it as renderer.IMapRenderer instead of by its full module name,
rogue.renderer.IMapRenderer . This is because the renderer module is inside the rogue module. Just because they
are in different files doesn't mean that they have their own individual scope. Therefore, when a class is inside a
module, the class doesn't need to use the fully qualified module path name; you can drop the module name to which
the class belongs and access the class itself. You will see more of this later on, but in some cases, you will have to use
fully qualified module paths. I will do my best to explain these differences.
 
Search WWH ::




Custom Search