C-Sharp Programming Beginner Tutorial: No-Frills Dungeon Crawler (Part 2)

Hey everybody!!!

I hope you enjoyed my last Tutorial Lesson regarding the No-Frills Dungeon Crawler. Now we're going to dive into the C# fun of it all. We'll see what makes the game tick, what makes it tock, and what in the world is next in stock!

CSharp-ForBeginners_FristImage.JPG

Let's get right down to it, then, and see what the Code looks like. The animated image below shows me playing the game, which isn't much of a game yet. It does show a bit of what the game will look like (yes, it's very simple and I could have done much more) and how to maneuver within the game interface.

2018-01-28-08-26-23.gif

And now for the Code...


The Grand Scale

So we've taken a look at the concept of the game in the previous post as well as the outlook for the future of the game. Now we are going to take an in-depth look at the C# Code for this game. We will get a glimpse of the overall program and then go deeper into the functions and variables and how the logic interacts.

Here you go, my fellow Nerds-in-Waiting and Chic-Geek-Knights, following is the code at a glimpse.






As you can see, quite a bit of switch logic and semi-repetitious checking. There are always a dozen ways to do the same thing, so this is just one way in many that can do the same/similar things. In essence, the switch statement is like saying "I have a bunch of conditions and want to check them each on a case-by-case scenario. Hence, you see the case statement that is part of the switch logic... you cannot use switch without it.

The whole scope may look a bit intimidating, but the logic within each segment can usually be summed up by just a few logical components. Following are the Bits & Pieces of it all.


Bits & Pieces

I'm going to go top-down through the code and explain what it all means without repeating myself over and over. I hope it all makes sense when I'm through with it all. The following sections will explain each of the parts of the code that will become the functional logic and representation to the game as a whole.


The Variables at Play

To start this section, we create an object of type Random that you might recall represents a randomly-generated number. "map" is a char based variable, which is an object that contains singular characters.

"= { ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o' };" says to create the array and fill each with the comma-delimeted values inside the curly braces { }.

An example of the Constants to use: public const int north = 0;

Constants are variables (you remember what variables are, correct? names of things to represent something else) that stay constant and cannot be changed across time. As an example, the above line of code recognizes the variable called "north" as a public (globally-usable) const (constant) with a dataype (type of variable) of int (integer-based, therefore, numeric whole numbers). Setting "north" to a constant variable sets it to a value (this time "0") that cannot be changed.

By using constants, I can now use the word "north" to mean "0". It makes the code far easier to read when it comes to debugging and/or change. I use the directional words to describe each, that way it made the coding of movements (turning left and right) a far simpler formula of addition or subtraction from the current directional number.

"direction" is the variable that actually determines the direction that the game's character will be facing. The "map_x" and "map_y" variables are only initialized and not used more than that. In future versions I may create maps from files that this will represent the map-based coordinates; but for now, it is not used.

"north_door", "east_door", "south_door", & "west_door" are boolean (true/false) variables that I use to represent whether or not there is a doorway in the corresponding wall. As an example, if "east_door" is true it means that if you are facing the east (in the game) there will be a doorway showing, and if you are facing north, that same doorway will show up on the right-hand wall. These are used to draw the correct image.

The "backdrop" is a PictureBox component that will be used for the game-screen itself. A PictureBox is a dotNet component that can hold an image for later use. This object is contained within the structure of Visual Studio itself and, therefore, one can do a drag-and-drop through the Visual Studio interface. In this instance I just created the object within the code itself.

The Images ("left_image", "front_image", "right_image" and so on) are actual Image objects that will be used as the wall-based images. The "left_image" represents the wall image that shows only a doorway on the right-hand wall. An Image object can store the data for an image, whether from a file or some sort of data stream. In these examples (as below) the image itself will be loaded from a file in the next section.


Start & Finish

When the program begins it uses the "Form1_Load" Function to begin loading the variables and components. This is where the variables from the above section will actually become usable. That will occur behind-the-scenes prior to the below code being run.

As you can see in the image above, I use the "Image.FromFile(...)" dotNet Function in order to load the images from files. I could have drawn the images individually or dynamically, but it would have made the code harder to understand. I cannot say one way or another on whether big-name games use my technique or a dynamic technique or something completely different. All I know is that this is the way I am doing it so that it's easier to follow.

Essentially, "left_door = Image.FromFile(...);" tells us to pull the image from the file location marked by the ellipsis and load it into the Image object called "left_door". The actual image is of 3 walls with the left wall as the only one that includes a doorway in it.

The same technique is used for the other images.

"map = room_types[r.Next(0, 15)];" represents logic to randomly create a room with a variable number of walls from 1-4 based on 16 alphabetic characters. "map = " says to set the "map" variable, while "room_types[...];" says to use the char[] object, which is a char array. An array is an object type that holds multiple versions of the same variable with the same name. This one in particular is identified by the char values of the alphabet from "a" - "o" with the first as an empty space. This way "room_type[1]" would represent the 2nd value in the array (these are 0-indexed and, therefore, starts at [0]).

Arrays can be confusing, so don't be alarmed if you still need to learn more about them.

After the "Form1_Load(...)" Function you can see the "Done_Click()" Function that represents the action of clicking the Button that I called "Done" (as in the below image):


(Done Button is circled in Red and labeled with "Quit")

The code itself shows "this.Close();" which is a call to the base "Close()" Function that closes down "this" form. this is a keyword that represents the main Form/object.


Movin' & Groovin'

In order to allow you to move forward through a doorway or backward through a doorway, if there is a doorway in that direction, I have 2 buttons that look like and .

In the above code, "MoveForward_Click()" is the Function linked to the button called "MoveForward". The logic occurs when that button is clicked (hence the "_Click" portion of the Function name.

            switch (direction)
            {
                case north: if (CheckDirection(true)) { map_y++; LastMessage.Text = "You moved forward."; map = room_types[r.Next(0, 15)]; } else { LastMessage.Text = "You cannot go that way. No Door."; }; break;
                case east: if (CheckDirection(true)) { map_x++; LastMessage.Text = "You moved forward."; map = room_types[r.Next(0, 15)]; } else { LastMessage.Text = "You cannot go that way. No Door."; }; break;
                case south: if (CheckDirection(true)) { map_y--; LastMessage.Text = "You moved forward."; map = room_types[r.Next(0, 15)]; } else { LastMessage.Text = "You cannot go that way. No Door."; }; break;
                case west: if (CheckDirection(true)) { map_x--; LastMessage.Text = "You moved forward."; map = room_types[r.Next(0, 15)]; } else { LastMessage.Text = "You cannot go that way. No Door."; }; break;
                default: break;
            }

            GetDoors(map);
            this.Update();

The switch command uses the variable inside the parantheses () to check different scenarios. Each scenario is prefaced by a "case ?: " where the "?" represents the value (in these cases the constants.

So, if "direction" is equal to "north" (0) then it executes a function called "CheckDirection(...)" to see if it returns as true or false (not to be confused by the parameter inside the parentheses). If that, in turn, returns as true then it changes the text value of a label called "LastMessage" to show "You moved Forward.", otherwise if it returns as false it executes the else clause. The else is the alternative of an if statement's _true" clause... "if ... else" represents the question of "if this then do this else do that". If the else clause runs, the label shows "You cannot go that way. No Door." as its text value.

The "MoveBackward_Click(...)" Function does the same of the "MoveBackward" Button object.

GetDoors(map);
this.Update();

The first calls a Function called "GetDoors" and passes in the "map" variable, the one that represents the number of doors in the room. The second line calles "this.Update();" which just refreshes and repaints this form.


Turnaround, every now and then I get a little bit lonely

Ok, I don't get lonely, but it does run the formulas to turn a different direction. The code is fairly short, actually, as can be seen here:


        private void TurnRight_Click(object sender, EventArgs e)
        {
            direction++;

            if (direction > west) { direction = north; }

            GetDoors(map);
            LastMessage.Text = "Turn Right.";
            this.Update();
        }

        private void TurnLeft_Click(object sender, EventArgs e)
        {
            direction--;

            if (direction < north) { direction = west; }

            GetDoors(map);
            LastMessage.Text = "Turn Left.";
            this.Update();
        }

If you recall, the "direction" variable is an integer number that represents the direction that the character is facing in the game. so if you turn to the right, it goes from the current direction to the next direction in line (eg. north->east... which is north (0) to east (1)). To do a right turn, all that needs to happen is the increase the "direction" by 1. "direction++;" means to do just that. 0 becomes 1, 1 becomes 2, and so on. The problem, however, is that there are only 4 directions (0 thru 3), so we need to check and reset if needed. The following line does that:


Directions anyone?

"if (direction > west) { direction = north; }"

if the expression inside the parentheses evaluates to true (eg. if "direction" is now greater than 3 (west)) then it executes the logic in the braces { direction = north; }. Doing this sets "direction" equal to "north" (0).

GetDoors(map);
LastMessage.Text = "Turn Left.";
this.Update();

This set of lines says Execute the GetDoors(map) function, then set the text value of the LastMessage label to "Turn Left." and finally to refresh and repaint this form.

To turn left, it just works in reverse.


What Direction Your Direction is in?

        private bool CheckDirection(bool forward)
        {
            bool result = false;

            if (forward)
            {
                if (direction == north)
                {
                    return north_door;
                }
                else if (direction == east)
                {
                    return east_door;
                }
                else if (direction == south)
                {
                    return south_door;
                }
                else if (direction == west)
                {
                    return west_door;
                }
            }
            else
            {
                if (direction == north)
                {
                    return south_door;
                }
                else if (direction == east)
                {
                    return west_door;
                }
                else if (direction == south)
                {
                    return north_door;
                }
                else if (direction == west)
                {
                    return east_door;
                }
            }

            return result;
        }

The above code basically checks the direction and, if you are moving forward, it checks to see if there's a doorway in that direction. The "forward" variable is the response to "which way are you moving... forward or backward?". Therefore, if "forward" is true, then you're moving forward and, otherwise, you're not moving forward (you're moving backward).

Then, after that check, it checks the appropriate wall to see if there's a doorway in the wall.

            if (forward)
            {
                if (direction == north)
                {
                    return north_door;
                }

This is the first check in the "forward" option. "if (direction == north)" says if "direction" equals "north" then do this. The double-equals (==) is a comparison logical expression. After that, if the "direction" is "north" then return the boolean (true/false) value of "north_door". This returns back to the code in the Movin' & Groovin' section above.



Doorways, Doorways, everywhere

Where have all the Doorways Gone?

This is the logic that determines the doorways and directions for a given room. The code below is a snippet of this Function when the "room_identifier" parameter that is passed in is an 'a'. The letter 'a' represents a door only in the north-facing wall. Therefore, if I check the "direction" value and I'm facing north, the doorway should be right in front of me only... this condition is represented by the "front_image" Image variable. You will see this case scenario below where it says "case north: ...".

        private void GetDoors(char room_identifier)
        {
            switch (room_identifier)
            {
                case 'a':
                    north_door = true; east_door = false; south_door = false; west_door = false;
                    switch (direction)
                    {
                        case north: this.backdrop.Image = front_image; break;
                        case east: this.backdrop.Image = left_image; break;
                        case south: this.backdrop.Image = none_image; break;
                        case west: this.backdrop.Image = right_image; break;
                        default: break;
                    }
                    break;

The other logic is the same type of logic ("Which walls have doors? and what direction am I facing?") to show which doorways to draw.


Lessons Learned

Here are the links to your lessons learned (or not learned, if you need to go back and learn them):

C# Programming Beginner Tutorial: Basic Concepts and Ideas

C# Programming Beginner Tutorial: A First look at actual code using D&D as the Project

C# Programming Beginner Tutorial: Variables & Data Types to Fuel the Gaming Engine!

C# Programming Beginner Tutorial: Designing the Game with Programming Logic in Mind (Part 1)

C# Programming Beginner Tutorial: Designing the Game with Programming Logic in Mind (Part 2)

C# Programming Beginner Tutorial: Designing the Game with Programming Logic in Mind (Part 3)

C-Sharp Programming Beginner Tutorial: Designing the Game with Programming Logic in Mind (Part 4)

C-Sharp Programming Beginner Tutorial: Rock! Paper! Scissors!

C-Sharp Programming Beginner Tutorial: No-Frills Dungeon Crawler (Part 1)


Sort:  

I really enjoy the way you explain coding.
I didn't understand much from other people, but You explain it nice way!
Thanks for amazing tutorial!

That’s a super-nice thing to say and it makes me happy to know it was understandable. I wasn’t totally certain for this lesson so it makes me feel good. Thanks!

Wow. I know a little bit programming also Clanguage and c++ . But this post really helps us to be more exposed on Cprogramming it is understandle using those basic coding. Great!

I know a little C and C++ as well. I didn’t like them because of the overhead coding and the value vs. reference vs. pointer issues. So many more nuances to deal with in the predecessors to C#.

You rock! Thanks for keeping the tutorial updates rolling in ;)

I’m definitely trying to keep it up. I want to average 1-2 per week as is possible.

That's pretty cool to know thanks for the tips by the way :)

You’re quite welcome. Do you have any coding projects that you are considering using this new knowledge to accomplish?

@dbzfan4awhile really your niche of making article on programming is a great thing and unique too and really this will surely help you in long run because you explain really well and really i love reading them as always ........ I have a doubt on java classes and objects please make a blog on that :)

I’m not well-versed in Java but if you explain the issue I might be able to look into it for you.

Upvoted on behalf of the dropahead Curation Team!

Thanks for following the rules.

DISCLAIMER: dropahead Curation Team does not necessarily share opinions expressed in this article, but find author's effort and/or contribution deserves better reward and visibility.

Help us giving you bigger upvotes by:

Upvote this comment!
Upvote the latest dropahead Daily Report!
Join the dropahead Curation Trail
to maximize your curation rewards!
Vote dropahead Witness with SteemConnect
Proxy vote dropahead Witness
with SteemConnect
Donate STEEM POWER to @dropahead
12.5SP, 25SP, 50SP, 100SP, 250SP, 500SP, 1000SP
Do the above and we'll have more STEEM POWER to give YOU bigger rewards next time!

News from dropahead: How to give back to the dropahead Project in 15 seconds or less

well i can share this with my programmers friends they would llove it

Please do! I hope they can find some good information within.

woah, I got disappointed for not being in the platform this series due to the bandwidth error of my account. Wish to see this sooner.
Sir I want to try the project but I can't start it because of not having the images you are calling. Can you please include also the image files that you have use ? if its ok, its just that I don't have the resources to create my own design of this images as of now

Do you mean the images for the walls and doorways? If so, those were just cheesy images I drew in MS Paint. You can draw them yourself and name them the same way. In addition, if you wish to read the previous posts then just click the links in the List at the bottom of this Post.

I am new and follow you please follow me back thanks

I hope it helps!!

@resteem.bot
Resteemed to over 10700 followers and 100% upvoted. Thank you for using my service!

Send 0.200 Steem or 0.200 Steem Dollar and the URL in the memo to use the bot.
Read here how the bot from Berlin works.

We are happy to be part of the APPICS bounty program. APPICS is a new social community based on Steem. The presale was sold in 26 minutes. The ICO will start soon. You can get a account over our invite link: https://ico.appics.com/login?referral=1fRdrJIW

@resteem.bot

Coin Marketplace

STEEM 0.18
TRX 0.14
JST 0.030
BTC 58639.60
ETH 3167.30
USDT 1.00
SBD 2.43