Part 2: Getting Classy, Utilizing Objects to structure our game.
Hey hey, welcome to Part 2 of our creating a Rogue like game with swift-TCOD.
In Part 0 we configured Xcode to interface with libTCOD
and in Part 1 we set uo our console and moved our "@" symbol
around the screen. If you havent completed those sections, please go back and do so
before beginning this section
With the basic ground work laid, and everything setup and working, we're going to tweak what
we have to better manage different parts of our game as they are added. Swift being an
Object Oriented Programming language (OOP from here on out) it gives us the perfect tool
for this job in the shape of "classes". We've already had interaction with one class so far
If you recall one of the first things we did in part 1 was add this line:
Thats the basic syntax for initializing a class in Swift
What we are going to do now is navigate to Xcodes menu and go to File -> New-> File
And add a new swift file to our project:
Name the new file Entity.swift
In Entity.swift we are going to construct a class called Entity which can be used
to represent our character, monsters, NPC's, even Items. It will help tremendously
as we start building and populating our map. So go ahead and add the following to
Whoa thats alot! thankfully its all pretty self explanitory, but ill sum it up anyway.
We defined an Object "Entity", and given it variables for its coordinates on the map (px, py)
The symbol by which it will be identified on the map, and the color the symbol will appear on the map. (symbol, color)
If your thinking that TCOD_color_t looks awfully like a C typedef, its because it is one :-P
So now that we have the entity class defined, lets go back to main.swift and use it to represent our
"@" character. As It stands our main.swift looks like this:
As it stands, our character is represented by the playerx and playery variables, and were just passing a string
and those coordinates to the putChar function. We COULD keep our game this way, but we would be wasting
the power of OOP and competent data structures we have at our finger tips, not to mention becoming overwhelmed
QUITE quickly ass more items/characters are added to the map. With that in mind, lets change our main.swift
by initializing an instance of the Entity class that we will use to represent our Character "@", and change the old
values that were associated with our player:
Thats a bit of a difference, so im going to put the two versions
of the code next to eachother so you have a clearer idea of whats going on
with the changes we've made so far, our old part 1 main.swift is on the left
and the changes we've made thus far in part 2 are on the left:
main.swift from Part 1
changes made to main.swift in Part 2
Wow! a bit of a difference there, not dramatic, but subtle, and POWERFUL
as you can see, values being altered are very clearly associated
with the player instance of the entity class. Not only does that make our code
a bit more "readable", but it also gives us a very structured way of representing
anything we place on the games map we've also made two other significant changes
the way that our characters coordinates are manipulated via player.move()
and the function we use to display the character, tcod.putColorChar()
This function allows us to color what we are outputing:
Ok, so now that you have a better idea of how we are going to use the Entity class, lets initialize another Entity Called
npc. Now, instead of adding another putColorChar statment, another move statement, etc for each new Entity
lets create an array of Entitys, called ents, and add player and npc to that array:
Because we'll be changing the way we are handling input and output, go ahead and add a new .swift
to your project and call it inputAndRender.swift
We're going to move our keypress handling from the main game loop to a function we will create
called keyReader() add the following code to your inputAndReader.swift:
Instead of just incrementing a value when a key is pressed, were going call a function that returns
a Dictionary composed of an instruction (String), and values for the instruction(Int32,Int32)
so when keyReader returns its value, we annalyze that value and call the associated action
Since we've moved key handling to outside of our game loop, we know have to edit our main loop accordingly:
Whats happening here is we've declared retVal as a Dictionary to be populated by the return value of keyReader
We've initialized two Int32's, chgx and chgy(change x and change y), as a Tuple to be populated by the Tuple
portion of the retVal Dictionary. Next, we call keyReader(), and loop through a list of associated actions
to determine what action should be taken from keyReader()'s return.
If this isnt the clearest explaination i appologize. I'm programmer, not a grammer teacher :-P
Next up, were going to add some more functions to inputAndRender.swift
These functions make positiong our Entites a trivial process instead of having to continuosly
add lines to display or clear an Ent as needed.
*NOTE*: I included the clearEnt and clearAll functions for the sake of continuity
between this tutorial and the python tutorial.
they are in fact unnecessary as using tcod.consoleClear() will do the same thing!
Lets make a few minor tweaks to our main game loop to utilize this new way of displaying Entites:
And with that out of the way, lets start putting together the pieces a map for our game!
The first thing we're going to do is add a file to our project and name it "MapEtc.swift"
because it will contain information about the map... etcetra....
In MapEtc.swift we are going to create a struct called Tile, which will hold 2 Boolean variables:
blocked, and blockSight, and an initializer to set the value of each boolean
when Tile.blocked = true, the character cannot traverse the tile, when blockSight = true
our character cant see what is beyond that tile.
your copy of MapEtc.swift should look like this:
Now, you might be wondering why we're using a struct to creat the tile type and not a class
(like you would in python). In Swift, structs represent value types, while classes are reference types.
This effects us in such as if we were to create an array of Tile (like we're about to do) than every time
we went to change a property of one tile, every tile in the array would change accordingly. No Bueno. so struct it is.
Next, we creat a class for the game map, you can place it right below the Tile struct in MapEtc.swift
This class will have 2 variables representing the width and height of the map (smaller than the values we set
for the width and height of the console, for obvious reasons.) and a 2d dimensional array of Tile's. Also in this class
we will create a method to initialize the tile array with base values so they can be changed/accessed in the future.
We will also creat a method, is_blocking() so we can find out if a tile is blocking our characters
sight or movement. Our GameMap class should look like this:
Since we will be drawing our tiles from the map on the screen, we need to rewrite our drawAll function:
and since there may now be barriers to our characters movement, we make the following change
to our game loop, to check if our character CAN move before moving them: