Home .NET Writing a Racing game on paper, C# WPF

Writing a Racing game on paper, C# WPF

by admin

Prehistory

It was in the early 90’s, the computer was not, but I had a desire to play in the race) has shown me a friend as you can on a notebook sheet of paper into the cell to play the race. And they say there is a board game with these rules. And that almost everyone played this game at university for classes.

Rules of the game

Can be read Wikipedia rules reading this and knowing nothing, I wouldn’t understand ). The main rule of the game is the rules for moving the car. Rule 2 – you can’t make a move by getting in the way, you lose.

Move 1 : The car stands still and can go to points that are located around the point to which the vector of the car’s movement is directed. At the beginning of the game the vector is zero, it is not directed anywhere, so we can go to points around the car. We make a move to the point above the car.

For each generated trace element you need to store :

    Thestarting point (X and Y)

  1. The end point (X and Y)

  2. trace element width (in this implementation, the trace width is the same for all elements, as a saving for the future)

  3. The length of the trace element

  4. Angle of slope of the trace element to the oX axis

  5. User position on the game map

    The user’s position on the game map is displayed as a typewriter. For the game map to be of any size, it is necessary that when the user moves, the map moves relative to the typewriter, not the typewriter relative to the map. This means that the car will always be at the same point on the game map, and when you make a move, you need to remember the deviation of the car from its starting point and redraw the elements of the track given this deviation.

    /// <summary>/// The current map shift in axes/// </summary>int _deltaX, _deltaY = 0;

    The image of the car is made as a car with clearly marked back and front. To make it clear to the user the current direction of movement of the car, it is necessary to turn the car in the direction of the direction of movement.

    Each completed move is stored in the _pathList – a list of the segments of the traversed path.

    /// <summary>/// A list of the sections of the track covered/// </summary>List<PathElement> _pathList = new List<PathElement> ();

    A segment of the traversed path should store the following data :

    1. Point of origin (X and Y)

    2. End point of segment (X and Y)

    3. Displacement of the typewriter relative to the map at the time of the move

    Knowing the start and end points of the segment, you can calculate the angle of the segment to the oX axis.
    AC – change in the X coordinate from the beginning to the end of the segment
    BC – coordinate change Y from the beginning to the end of the segment

    Writing a Racing game on paper, C# WPFWriting a Racing game on paper, C# WPF

    /// <summary>/// Current path angle ////summary> public double Angle {get{if (ToY == FromY ToX > FromX) return 90;if (ToY == FromY ToX < FromX) return -90;if (ToX == FromX ToY > FromY) return 180;if (ToX == FromX ToY < FromY) return 0;if (ToY <= FromY ToX > = FromX) return -Math.Atan((ToX - FromX) / (ToY - FromY)) * 180 / Math.PI;if (ToY <= FromY ToX <= FromX) return - Math.Atan((ToX - FromX) / (ToY - FromY)) * 180 / Math.PI;if (ToY > = FromY ToX <= FromX) return Math.Atan((ToY - FromY) / (ToX - FromX)) * 180 / Math.PI - 90;if (ToY > = FromY ToX > = FromX) return Math.Atan((ToY - FromY) / (ToX - FromX)) * 180 / Math.PI + 90;return 0;}}

    Game card field types

    To perform a move on the game map are nodes – buttons (Buttons) at a distance of 20 pixels from each other, 39 rows of 39 buttons. In this way the functionality of performing a new move is achieved.

    It has been said that when you make a move, the machine stays in place and the map elements change their position. This means that each time you perform a move, you must check all of the map nodes to see where that node currently falls :

    1. field where the machine can make a safe move

    2. a field where the machine can make a move, but it will be out of the track

    3. field belonging to the road

    4. field that does not belong to the road

    5. current field with a machine

    When checking, you need to find the fields into which the machine can make a move. To do this, the current speed of the X-axis and the Y-axis is taken into account.

    Writing a Racing game on paper, C# WPF

    Formula for finding the area of a triangle knowing the coordinates of its vertices :

    Writing a Racing game on paper, C# WPF

    On the other hand, the formula for finding the area of a triangle knowing its height :

    Writing a Racing game on paper, C# WPF

    These two formulas are enough to calculate the height of the triangle (and you could also not bother with the area and calculate more easily using :

    Writing a Racing game on paper, C# WPF

    But I figured that out at the time of writing)

    Formula for finding the length of a segment by its coordinates :

    Writing a Racing game on paper, C# WPFWriting a Racing game on paper, C# WPFWriting a Racing game on paper, C# WPF

    Formula for finding the angles of a triangle knowing the lengths of the sides of a triangle :

    Writing a Racing game on paper, C# WPFWriting a Racing game on paper, C# WPF

    Traversed path segments

    Each time you make a move, record a new segment of the traversed path.
    Again, the segment of the traversed path must store the following data :

    1. Point of origin (X and Y)

    2. End point of segment (X and Y)

    3. Displacement of the typewriter relative to the map at the time of the move

    4. The tilt angle to the oX axis is calculated automatically

    To redraw the traversed path, delete the previously drawn path elements, go through the saved path elements and draw them with the "Line" each one remembering to use the offset of that element.

    Possibility to start a new game again

    To implement this feature let’s make MenuItem type item in main menu of program, let’s make Click event, let’s make clearance of all game map elements, clearance of saved elements of traveled track list, road elements, clearance of variables of map shift and current speed of the car.

    Display of current speed

    The physics of the prototype game is such that we have two speeds : speed on the oX axis, speed on the oY axis.

    By the current speed of the machine we mean the greater value between the two speeds on the axes.

    Ability to change program settings through configuration file

    To change variables in the game it makes sense to put the values of these variables in the configuration file :

    1. Width of road fragment

    2. Number of road slices to generate a new trace

    3. Maximum angle of turn of the road to the left

    4. Maximum right turn angle of the road

    5. Minimum length of the road section

    6. Maximum length of the road section

    7. Position of the car on the game map

    {"RoadWidth": "100", "RoadElementsCount": "20", "MinAngle": "-60", "MaxAngle": "60", "MinRoadLength": "100", "MaxRoadLength": "200", "UserPosition": {"X": "400", "Y": "400"}}

    Depending on these settings, the playing field looks different :

    Landscape generation, GUI improvement

    You should add as many different elements to the game as possible for a more pleasant experience (within reason of course):

    1. Fill the playing field "Earth" – an image that fills the entire field

    2. We check the type of each node in the game map every time we make a move. In this code method we can add the generation of "Christmas trees" in case the field of the given node does not belong to the road. To avoid too many Christmas trees, let’s limit the chance of a Christmas tree to 20%.

      var random = new Random();var elkaChance = random.Next(1, 101);if (elkaChance < 20){// draw a Christmas tree}

    3. To make the roadway look like a roadbed, you can apply a dashed marking running down the middle of the road elements, just connecting the start and end point of each road element. To make this marking more natural, we use the Polyline shape by passing a collection of points from the road elements to the shape.

    var polyLinePointCollection = new PointCollection();foreach (var roadElement in _roadElements){if (polyLinePointCollection.Count == 0) polyLinePointCollection.Add(new Point(roadElement.StartPoint.X + 5 + _deltaX, roadElement.StartPoint.Y + _deltaY));polyLinePointCollection.Add(new Point(roadElement.EndPoint.X + 5 + _deltaX, roadElement.EndPoint.Y + _deltaY));}var polyLine = new Polyline(){Points = polyLinePointCollection, Stroke = Brushes.White, StrokeDashArray = new DoubleCollection() { 6, 4 }, StrokeThickness = 2};

    Dangerous Turn Signs

    Writing a Racing game on paper, C# WPF

    Knowing all the information about the generated road elements, you can compare each road element with the previous element and calculate the difference of the angles of the figures. If the obtained value is > 70°, then we will show the danger sign at the point of the beginning of the road element.

    70° " alt="Angle_text{curr} text{-} Angle_text{prev} > 70° " src="https://habrastorage.org/getpro/habr/upload_files/f07/537/783/f07537783852171db2ae80e9c872cefc.svg"width="182"height="19"/>

    There are cases where one angle is +178° and the other is -178°. The real difference between these angles is only 4°. To solve this problem, we need to add the condition that the angle will be dangerous when the angle difference is less than 290°. The formula will change to this form :

    Writing a Racing game on paper, C# WPF

    Program code

    On my GitHub

    You may also like