Blog Post

Intro To Game Development

Written by

True Life: Game Development

 

I believe at some point in every young man’s life, he has the desire to create his own video game. However, having the desire and actually learning to do so are two completely different things. Actually programming and seeing endless lines of code come together to form something playable is an extremely daunting task. When video games were first coming out, most games were programmed in C language. At the time C++ was around but not utilized. The problem with coding in C is that it becomes problematic with bigger games. I’m sure most every PC user during the 2000’s was constantly upgrading their video cards. With the rapid advances in technology it seemed as if once you purchased the best, top of the line video card, it was obsolete within a month. Nowadays that is less of a problem. Before we jump into technical mumbo jumbo, lets go over a brief history of the most common language used to code games, known as C# (C sharp)

 

A Brief History of C#

 

In January 1999, Anders Hejlsberg formed a team to build a new language at the time called Cool, which stood for "C-like Object Oriented Language".Microsoft had considered keeping the name "Cool" as the final name of the language, but chose not to do so for trademark reasons. By the time the .NET project was publicly announced at the July 2000 Professional Developers Conference, the language had been renamed C#, and the class libraries and ASP.NET runtime had been ported to C#. At one point C# had a mascot named Andy. Microsoft retired him in 2004. Currently the most recent version of C# is 5.0.

 

Common Language Runtime

 

  • The Common Language Runtime (CLR) is the virtual machine component of Microsoft's .NET framework and is responsible for managing the execution of .NET programs.
  • Just-in-time compilation - the compiled code is converted into machine instructions that, in turn, are executed by the computer's CPU.
  • The CLR provides additional services including memory managementtype safety and exception handling.
  • All programs written for the .NET framework, regardless of programming language, are executed by the CLR.
  • Provides exception handling, garbage collection and thread management.
  • CLR is common to all versions of the .NET framework.

 

 

 

 

 

 

Reasons to use C#

  • Manage Code - Managed code supplies the metadata necessary for the CLR to provide services such as memory management, cross-language integration, code access security, and automatic lifetime control of objects. All code based on IL executes as managed code. It’s executed by the CLR, and prevents crashing. C++ can also run manage code.
  • Typecast - Casting is usually a matter of telling the compiler that although it only knows that a value is of some general type, you know it's actually of a more specific type.

 

Example:

object x = "hello"

 

// I know that x really refers to a string

string y = (string) x;

 

Variables

  • Variables represent storage locations. Every variable has a type that determines what values can be stored in the variable. C# is a type-safe language, and the C# compiler guarantees that values stored in variables are always of the appropriate type. The value of a variable can be changed through assignment or through use of the ++ and – operators.

 

Example: John and Doe are the variables

using System;

 

namespace ConsoleApplication1

{

    class Program

    {

        static void Main(string[] args)

        {

            string firstName = "John";

            string lastName = "Doe";

 

 

            firstName = Console.ReadLine();

 

 

        }

    }

}

Basic Data Types

  • Boolean - variables are stored as 16-bit (2-byte) numbers, but they can only be True or False. Use the keywords True and False to assign one of the two states to Boolean variables.
  • Byte - variables are stored as unsigned 8-bit (1-byte) numbers ranging in value from 0 through 255. The Byte data type is used for containing binary data.
  • Char - variables are stored as unsigned 16-bit (2-byte) numbers ranging in value from 0 through 65535. Each number represents a single Unicode character. Direct conversions between the Char data type and the numeric types are not possible, but you can use the AscW and ChrW functions for this purpose.
  • Date - variables are stored as IEEE 64-bit (8-byte) integers that represent dates ranging from January 1 of the year 1 through December 31 of the year 9999, and times from 0:00:00 (midnight) through 11:59:59 PM. Date values must be enclosed within number signs (#) and be in the format M/D/YYYY, If you convert a Date value to the String type, the date is rendered according to the short date format recognized by your computer, and the time is rendered according to the time format (either 12-hour or 24-hour) in effect on your computer. The equivalent .NET data type is System.DateTime.
  • Decimal variables are stored as signed 128-bit (16-byte) integers scaled by a variable power of 10. The scaling factor specifies the number of digits to the right of the decimal point; it ranges from 0 through 28. With a scale of 0 (no decimal places), the largest possible value is
  • Double variables are stored as signed IEEE 64-bit (8-byte) double-precision floating-point numbers ranging in value from -1.79769313486231570E+308 through -4.94065645841246544E-324
  • Integer variables are stored as signed 32-bit (4-byte) integers ranging in value from -2,147,483,648 through 2,147,483,647. The Integer data type provides optimal performance on a 32-bit processor, as the smaller integral types are slower to load and store from and to memory.
  • Long variables are stored as signed 64-bit (8-byte) integers ranging in value from -9,223,372,036,854,775,808 through 9,223,372,036,854,775,807. You can convert the Long data type to Single, Double, or Decimal without encountering a System.OverflowException error.
  • Object variables are stored as 32-bit (4-byte) addresses that refer to objects. You can assign any reference type (string, array, class, or interface) to a variable declared as an Object. An Object variable can also refer to data of any value type (numeric, Boolean, Char, Date, structure, or enumeration).
  • Short variables are stored as signed 16-bit (2-byte) integers ranging in value from -32,768 through 32,767.
  • Single variables are stored as signed IEEE 32-bit (4-byte) single-precision floating-point numbers ranging in value from -3.4028235E+38 through -1.401298E-45 for negative values and from 1.401298E-45 through 3.4028235E+38 for positive values. Single-precision numbers store an approximation of a real number.
  • String variables are stored as sequences of unsigned 16-bit (2-byte) numbers ranging in value from 0 through 65535. Each number represents a single Unicode character. A string can contain up to approximately 2 billion (2 ^ 31) Unicode characters.
  • The user-defined type (UDT) supported by previous versions of Visual Basic is generalized to a structure in Visual Basic .NET. A structure is a concatenation of one or more members of various data types. The structure is treated as a single unit, although its members can also be accessed individually.
  • A structure declaration starts with the Structure statement and ends with the End Structure statement. The Structure statement supplies the name of the structure, which is also the identifier of the data type being defined by the structure. Other parts of the code can use this identifier to declare the data type of variables, arguments, and function return values.

Operators

  • The operator keyword is used to declare an operator in a class or struct declaration.
  • Operators can only take value parameters, not ref or out parameters.
  • Based on the number of operands used with the operator, operators are classified as unary (single operand), binary (two operands) and ternary (three operands).
  • For example, the operator ‘==’ can be used to compare two objects of immutable value type for which the operator is overloaded in the user-defined type of the object for comparing the value equality instead of reference equality.

The various types of C# operators that are used for specific functionalities include:

  • Assignment (=) : used to assign the result of an expression to a variable
  • Short-hand assignment(+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=): for shortening the common assignment operations
  • Arithmetic (+,-,*,/,%) : for constructing mathematical expressions
  • Increment and decrement operators (++ and --): shortcut for incrementing or decrementing the value by 1
  • Comparison (==,>,<,>=,<=,!=): for performing comparison that control the program flow
  • Boolean logical operator (!, &&, ||, ^): for performing Boolean logical operations
  • Bitwise manipulation (&,|,^,>>,<<): for manipulating each bit of integer values
  • Type testing(is, as): to check or convert the type of an object
  • Pointer manipulation(*,&,->,[]): for operations performed directly on pointers in unsafe context
  • Overflow exception (checked and unchecked): option to check or avoid checking overflow on values
  • Ternary operator (?:):used for making decisions

 

Constants

  • Constants are values which are known at compile time and do not change. (To create a constant value that is initialized at runtime, use the readonly keyword.) Constants are declared as a field, using the const keyword before the type of the field. Constants must be initialized as they are declared.

 

Example:

class Calendar1

{

    public const int months = 12;

}

 

 

Converting C

 

  • ?
  • There are some things that cannot be converted

Loops

  • In computer programming, a loop is a sequence of instruction s that is continually repeated until a certain condition is reached. Typically, a certain process is done, such as getting an item of data and changing it, and then some condition is checked such as whether a counter has reached a prescribed number. If it hasn't, the next instruction in the sequence is an instruction to return to the first instruction in the sequence and repeat the sequence. If the condition has been reached, the next instruction "falls through" to the next sequential instruction or branches outside the loop. A loop is a fundamental programming idea that is commonly used in writing programs.
  • The break statement terminates the closest enclosing loop or switch statement in which it appears. Control is passed to the statement that follows the terminated statement, if any.
  • The continue statement passes control to the next iteration of the enclosing iteration statement in which it appears.

 

Scoping

 

  • Scope refers to identifiers; that is types, functions, classes and variables and is that part of the source code where the particular identifier is visible.
  • Basically that means everything inside of the curly brackets { }

 

Example:

 

using System;

 

namespace _______

{

    class _______

    {

        static void Main(string[] args)

        {

int X;

int Y;

x=7

y=x + 3;

         }

     }

}

 

Value Types vs Reference Types

Value Type - holds the data within its own memory allocation

Examples of Value Types

  • All numeric data types
  • Boolean, Char, and Date
  • All structures, even if their members are reference types
  • Enumerations, since their underlying type is always SByte, Short, Integer, Long, Byte, UShort, UInteger, or ULong

 

Reference Type - contains a pointer to another memory location that holds the data

Examples of Reference Types

  • String
  • All arrays, even if their elements are value types
  • Class types, such as Form
  • Delegates

Garbage Collection

  • Manages the allocation and release of memory for your application.
  • Each time you create a new object, the common language runtime allocates memory for the object from the managed heap.
  • As long as address space is available in the managed heap, the runtime continues to allocate space for new objects.
  • However, memory is not infinite, eventually the garbage collector must perform a collection in order to free some memory
  • The garbage collector's optimizing engine determines the best time to perform a collection, based upon the allocations being made.
  • When the garbage collector performs a collection, it checks for objects in the managed heap that are no longer being used by the application and performs the necessary operations to reclaim their memory.

Structure

  • A struct type is a value type that can contain constructors, constants, fields, methods, properties, indexers, operators, events, and nested types.
  • Takes less memory than class
  • Used performance wise
  • Also good for creating own variables
  • Cannot have default constructor

Example

[attributes] [modifiers] struct identifier [:interfaces] body [;]

Constructor

  • A constructor is a class member function that has the same name as the class itself
  • The purpose of the constructor is to initialize all member variables when an object of this class is created

 

In the following example, a class called Taxi is defined with a simple constructor. This class is then instantiated with the new operator. The Taxi constructor is invoked by the new operator immediately after memory is allocated for the new object.

public class Taxi

{

    public bool isInitialized;

    public Taxi()

    {

        isInitialized = true;

    }

}

 

class TestTaxi

{

    static void Main()

    {

        Taxi t = new Taxi();

    }

}

 

Structure vs Class

  • Visual Basic unifies the syntax for structures and classes, with the result that both entities support most of the same features. However, there are also important differences between structures and classes.
  • Classes have the advantage of being reference types — passing a reference is more efficient than passing a structure variable with all its data. On the other hand, structures do not require allocation of memory on the global heap.
  • Because you cannot inherit from a structure, structures should be used only for objects that do not need to be extended. Use structures when the object you wish to create has a small instance size, and take into account the performance characteristics of classes versus structures.

Similarities of Structures & Classes

  • Both are container types, meaning that they contain other types as members.
  • Both have members, which can include constructors, methods, properties, fields, constants, enumerations, events, and event handlers. However, do not confuse these members with the declared elements of a structure.
  • Members of both can have individualized access levels. For example, one member can be declared Public and another Private.
  • Both can implement interfaces.
  • Both can have shared constructors, with or without parameters.
  • Both can expose a default property, provided that property takes at least one parameter.
  • Both can declare and raise events, and both can declare delegates.

 

 

Differences of Structures & Classes

  • Structures are value types; classes are reference types. A variable of a structure type contains the structure's data, rather than containing a reference to the data as a class type does.
  • Structures use stack allocation; classes use heap allocation.
  • All structure elements are Public by default; class variables and constants are Private by default, while other class members are Public by default. This behavior for class members provides compatibility with the Visual Basic 6.0 system of defaults.
  • A structure must have at least one nonshared variable or nonshared, noncustom event element; a class can be completely empty.
  • Structure elements cannot be declared as Protected; class members can.
  • A structure procedure can handle events only if it is a Shared (Visual Basic) Sub procedure, and only by means of the AddHandler Statement; any class procedure can handle events, using either the Handles keyword or the AddHandler statement. For more information, see Events and Event Handlers.
  • Structure variable declarations cannot specify initializers or initial sizes for arrays; class variable declarations can.
  • Structures implicitly inherit from the System.ValueType class and cannot inherit from any other type; classes can inherit from any class or classes other than System.ValueType.
  • Structures are not inheritable; classes are.
  • Structures are never terminated, so the common language runtime (CLR) never calls the Finalize method on any structure; classes are terminated by the garbage collector (GC), which calls Finalize on a class when it detects there are no active references remaining.
  • A structure does not require a constructor; a class does.
  • Structures can have nonshared constructors only if they take parameters; classes can have them with or without parameters.
  • Class created on the heap.

Heap vs Stack

  • In a multi-threaded application, each thread will have its own stack. But, all the different threads will share the heap. Because the different threads share the heap in a multi-threaded application, this also means that there has to be some coordination between the threads so that they don’t try to access and manipulate the same piece(s) of memory in the heap at the same time.
  • Objects can be stored on the stack rather than the heap. If you create an object inside a function without using the “new” operator then this will create and store the object on the stack, and not on the heap. Suppose we have a C++ class called Member, for which we want to create an object. We also have a function called somefunction( ).

 

 

 

 

 

 

 

Example:

 

 

void somefunction( )

{

/* create an object "m" of class Member

    this will be put on the stack since the

    "new" keyword is not used, and we are

   creating the object inside a function

*/

 

  Member m;

 

} //the object "m" is destroyed once the function ends

So, the object “m” is destroyed once the function has run to completion – or, in other words, when it “goes out of scope”. The memory being used for the object “m” on the stack will be removed once the function is done running.

If we want to create an object on the heap inside a function, then this is what the code would look like:

void somefunction( )

{

/* create an object "m" of class Member

    this will be put on the heap since the

    "new" keyword is used, and we are

   creating the object inside a function

*/

 

  Member* m = new Member( ) ;

 

  /* the object "m" must be deleted

      otherwise a memory leak occurs

  */

 

  delete m;

}

In the code above, you can see that the “m” object is created inside a function using the “new” keyword. This means that “m” will be created on the heap. But, since “m” is created using the “new” keyword, that also means that we must delete the “m” object on our own as well – otherwise we will end up with a memory leak.

How long does memory on the stack last versus memory on the heap?

Once a function call runs to completion, any data on the stack created specifically for that function call will automatically be deleted. Any data on the heap will remain there until it’s manually deleted by the programmer.

Can the stack grow in size? Can the heap grow in size?

The stack is set to a fixed size, and can not grow past it’s fixed size (although some languages have extensions that do allow this). So, if there is not enough room on the stack to handle the memory being assigned to it, a stack overflow occurs. This often happens when a lot of nested functions are being called, or if there is an infinite recursive call.

If the current size of the heap is too small to accommodate new memory, then more memory can be added to the heap by the operating system. This is one of the big differences between the heap and the stack.

How are the stack and heap implemented?

The implementation really depends on the language, compiler, and run-time – thesmall details of the implementation for a stack and a heap will always be different depending on what language and compiler are being used. But, in the big picture, the stacks and heaps in one language are used to accomplish the same things as stacks and heaps in another language.

Which is faster – the stack or the heap? And why?

The stack is much faster than the heap. This is because of the way that memory is allocated on the stack. Allocating memory on the stack is as simple as moving the stack pointer up.

How is memory deallocated on the stack and heap?

Data on the stack is automatically deallocated when variables go out of scope. However, in languages like C and C++, data stored on the heap has to be deletedmanually by the programmer using one of the built in keywords like free, delete, or delete[ ]. Other languages like Java and .NET use garbage collection to automatically delete memory from the heap, without the programmer having to do anything..

What can go wrong with the stack and the heap?

If the stack runs out of memory, then this is called a stack overflow – and could cause the program to crash. The heap could have the problem of fragmentation, which occurs when the available memory on the heap is being stored as noncontiguous (or disconnected) blocks – because used blocks of memory are in between the unusedmemory blocks. When excessive fragmentation occurs, allocating new memory may be impossible because of the fact that even though there is enough memory for the desired allocation, there may not be enough memory in one big block for the desired amount of memory.

Which one should I use – the stack or the heap?

For people new to programming, it’s probably a good idea to use the stack since it’s easier. Because the stack is small, you would want to use it when you know exactly how much memory you will need for your data, or if you know the size of your data is very small. It’s better to use the heap when you know that you will need a lot of memory for your data, or you just are not sure how much memory you will need (like with a dynamic array).

 

 

Value vs Reference Parameters

  • In Visual Basic, you can pass an argument to a procedure by value or by reference. This is known as the passing mechanism, and it determines whether the procedure can modify the programming element underlying the argument in the calling code. The procedure declaration determines the passing mechanism for each parameter by specifying theByVal (Visual Basic) or ByRef (Visual Basic) keyword.
  • When passing an argument to a procedure, be aware of several different distinctions that interact with each other:
  • Whether the underlying programming element is modifiable or nonmodifiable
  • Whether the argument itself is modifiable or nonmodifiable
  • Whether the argument is being passed by value or by reference
  • Whether the argument data type is a value type or a reference type
  • You should choose the passing mechanism carefully for each argument.
  • Protection. In choosing between the two passing mechanisms, the most important criterion is the exposure of calling variables to change. The advantage of passing an argument ByRef is that the procedure can return a value to the calling code through that argument. The advantage of passing an argument ByVal is that it protects a variable from being changed by the procedure.
  • Performance. Although the passing mechanism can affect the performance of your code, the difference is usually insignificant. One exception to this is a value type passed ByVal. In this case, Visual Basic copies the entire data contents of the argument. Therefore, for a large value type such as a structure, it can be more efficient to pass it ByRef.

For reference types, only the pointer to the data is copied (four bytes on 32-bit platforms, eight bytes on 64-bit platforms). Therefore, you can pass arguments of type String or Object by value without harming performance.

 

Object Oriented Programming (OOP)

  • All managed languages in the .NET Framework, such as Visual Basic and C#, provide full support for object-oriented programming including encapsulation, inheritance, and polymorphism.
  • Encapsulation means that a group of related properties, methods, and other members are treated as a single unit or object.
  • Inheritance describes the ability to create new classes based on an existing class.
  • Polymorphism means that you can have multiple classes that can be used interchangeably, even though each class implements the same properties or methods in different ways.

 

Virtual Methods

  • When an instance method declaration includes a virtual modifier, that method is said to be a virtual method. When no virtual modifier is present, the method is said to be a non-virtual method.

Example:

class B: A

{

   new public void F() { Console.WriteLine("B.F"); }

   public override void G() { Console.WriteLine("B.G"); }

}

 

Abstraction

 

  • An abstract class in C# means that the class *has* to be sub-classed. It can not be instantiated itself. Likewise an abstract method needs to have code put into it in the sub-class. 
  • A good use for an abstract class is if you want to implement the majority of the functionality that a class will need, but there are reasons that the class shouldn't be used directly.
  • Understanding what abstracting your code means, and even writing abstract code yourself is one the major hurdles to "wrapping your head" around Object Oriented Programming.  The essence of abstraction is to reduce the dependencies between classes.  This is known as making your classes "loosely coupled".  So that changes in one class do not ripple through to other classes, which forces you to go through the time-consuming process of tracking down all references, or usage, to the class to effect the changes.  Good luck hunting them all down because all to often the code will compile no problem.

Objects

  • An object is basically a block of memory that has been allocated and configured according to the blueprint.
  • A program may create many objects of the same class.
  • Objects are also called instances, and they can be stored in either a named variable or in an array or collection
  • In an object-oriented language such as C#, a typical program consists of multiple objects interacting dynamically.

 

 

 

Example: (person is the object)

public class Person{    public string Name { get; set; }    public int Age { get; set; }    public Person(string name, int age)    {        Name = name;        Age = age;    }    //Other properties, methods, events...}

 

Arrays

  • An array can be Single-DimensionalMultidimensional or Jagged.
  • The number of dimensions and the length of each dimension are established when the array instance is created. These values can't be changed during the lifetime of the instance.
  • The default values of numeric array elements are set to zero, and reference elements are set to null.
  • A jagged array is an array of arrays, and therefore its elements are reference types and are initialized to null.
  • Arrays are zero indexed: an array with n elements is indexed from 0 to n-1.
  • Array elements can be of any type, including an array type.
  • Array types are reference types derived from the abstract base type Array. Since this type implements IEnumerable and IEnumerable<T>, you can use foreachiteration on all arrays in C#.

Reference vs Value Arrays

  • In C#, arrays are actually objects. System.Array is the abstract base type of all array types
  • all arrays are always reference typeswhich are allocated on the managed heap, and your app's variable contains a reference to the array and not the array itself.

Multidimensional Arrays

  • Arrays can have more than one dimension; these arrays-of-arrays are called multidimensional arrays. They are very similar to standard arrays with the exception that they have multiple sets of square brackets after the array identifier.
  • The most common kind of multidimensional array is the two-dimensional array. A two dimensional array can be thought of as a grid of rows and columns.