Skip to content

Narwhal Simulator 11: Object Oriented Programming and Polymorphism

Hi everyone! This blog post is gonna be a bit lame for people who don’t care about the technicals. I’m still planning how to properly modularise the player, but I feel I’m getting close to finishing it and then I can actually start making progress for you all again. Today I will tell you about what’s taking so long, and along with that, I’ll try my best to explain polymorphism to you. 

First of all, I’ll summarise the last few posts and what I’ve been doing at the moment. Recently, I’ve been spending most of my time finishing up my schoolwork for the year. I’ve also been planning the next section of the game. I need to modularise the player. This means that I need to split the player up. Right now, the player is a single script, but the player needs to be able to upgrade themselves, making themselves better. Most importantly, the player’s different upgraded parts need to be able to do custom things, look and act unique, and interact with both the world and the player’s other parts. The interaction with other parts is the main issue here.

I’ll use the same example as last time to show the issue and the potential solutions. 

C#, the language I’m using, is a statically typed language (also known as strongly typed), which means that each variable is given a type it can store and it can only store that type. This means that the compiler and the programmer will both know exactly what each variable is and which methods and variables are inside it. This makes it more difficult for beginners to learn, but does come with a lot of advantages too. The IDE can give better suggestions and hints, the compiler can give warnings and errors about types before the program is even run. I can only call methods or use variables that the compiler knows a variable has. For example, I can only call the ClosestPoint method on an object of type Rigidbody2D because the compiler knows that it will have that method. I can’t call ClosestPoint on a string variable because the compiler knows that a string won’t have a ClosestPoint function.

The IDE knows that x is a RigidBody2D and can suggest the variables and methods in RigidBody2D.
The compiler knows that x is a RigidBody2D so it won’t let me assign a string to it.

C# lists work in similar ways to this. You have to specify what kind of thing you want to go into the list, then you can only put that type of thing in the list.

I can put ints into the list, but if I try to put a string into the list, it doesn’t work!

This is very useful, but what if I want to be able to store multiple types of objects in a list? I’ll use chess as an example here, but then I’ll apply this to Narwhal Simulator. In a chess game, we would need to store a list of pieces. With a list of pieces, we could loop over each one and update them, draw them, and do everything else we need to do with them. 

using System;
using System.Collections.Generic;
using System.Text;

public class Chess {
	public List<ChessPiece> pieces;

	public void Start() {
		pieces.Add(new ChessPiece(0, 1)); // Pawn
		pieces.Add(new ChessPiece(1, 1)); // Pawn
		pieces.Add(new ChessPiece(2, 1)); // etc...
	}
}

public class ChessPiece {
	public int x, y;
	public ChessPiece(int x, int y) {
		this.x = x;
		this.y = y;
	}

	public bool CanMove(int x, int y) {
		return true;
	}

	public void Move(int x, int y) {
		if (CanMove(x, y)) {
			MovePrivate(x, y);
		}
	}

	void MovePrivate(int x, int y) {
		this.x = x;
		this.y = y;
	}
}

Here’s some basic code. There is a Chess class that stores a list of chess pieces, then pretends to initialise a full board (I didn’t actually make it make the full board because there’s no need to make an actual chess game). This implementation isn’t actually going to be an implementation, nor is it actually going to work. I’m just using it as an example. Chess pieces all exhibit similar properties, like how they can all move, and they all have an x and a y coordinate on the board. They should all have a function which the game can call to check if a piece can move to a certain position as well. This is the CanMove function. Notice the ChessPiece class’ canMove function. This is the only part of our chess piece that actually varies depending on the piece. Rooks can move in different ways than pawns, and bishops can move in different ways than knights. This should be easy, we could just make a function for each one, right? That might work, but it’s a bit silly that the Chess class would need to keep track of what type of piece each is, then call the right function every time it needs to check a move. There’s an (arguably) easier way. It’s definitely cleaner anyway. It’s called Object Oriented Programming (OOP), and it’s the topic of this post. 

OOP is an important part of programming and it is very useful for solving these types of problems. We can use inheritance and abstract classes to solve this problem. Having an object inherit from another one means that the “child” object inherits all the methods and variables from the “parent” object. Inheritance goes hand in hand with polymorphism, another useful part of OOP. Polymorphism means that a child object can pretend to be the parent object. The child object will always have the same methods available as the parent object, since it inherits them. For example, if the parent object has a public DoStuff function, the child object will inherit this function, so the child object will always have a DoStuff function too, so the compiler doesn’t care if the object is actually the parent or if it’s the child. Finally, the child object can override the inherited functions, meaning that the child can declare their own code inside the function. This means that the parent and the child will both have the same functions, but they won’t necessarily work the same way. This is confusing, but bear with me, because I’ll apply this to the chess analogy and hopefully you’ll understand it. If you don’t, don’t worry! It takes time to understand complicated concepts like OOP. Here’s the new chess code, I’ll explain it after. 

using System;
using System.Collections.Generic;
using System.Text;

public class Chess {
	public List<ChessPiece> pieces;

	public void Start() {   // comment 1
		pieces.Add(new Rook(0, 1)); // Rook
		pieces.Add(new Bishop(1, 1)); // Bishop
		pieces.Add(new Rook(2, 1)); // etc...
	}
}

public abstract class ChessPiece { // comment 2
	public int x, y;
	protected ChessPiece(int x, int y) {
		this.x = x;
		this.y = y;
	}

	public virtual bool CanMove(int x, int y) { // comment 3
		return true;
	}

	public void Move(int x, int y) {
		if (CanMove(x, y)) {
			MovePrivate(x, y);
		}
	}

	void MovePrivate(int x, int y) {
		this.x = x;
		this.y = y;
	}
}

public class Rook : ChessPiece { // comment 4
	public Rook(int x, int y) : base(x, y) { } // comment 5

	public override bool CanMove(int x, int y) { // comment 6
		if (this.x == x || this.y == y) {
			return true;
		}
		return false;
	}
}

public class Bishop : ChessPiece {
	public Bishop(int x, int y) : base(x, y) { }

	public override bool CanMove(int x, int y) {
		if (Math.Abs(this.x - x) == Math.Abs(this.y - y)) {
			return true;
		}
		return false;
	}
}
// etc...

There’s a lot of new stuff there! I’ll discuss the parts I’ve commented on in order.

  1. Here, even though the List can only contain objects of type ChessPiece, the compiler lets me add a Rook and a Bishop! This is the OOP at work.
  2. This line isn’t too different, but notice the ‘abstract’ keyword. This means you can’t make an object of this type directly. This is good because we don’t want to be able to make a generic chess piece. Every chess piece should have its own way of moving.
  3. This line has had the ‘virtual’ keyword added. This means that child objects can override this function. In C#, only certain functions can be overridden. The other option would have been to add the ‘abstract’ keyword to the function. Abstract functions must be overridden by the child, while virtual functions can be overridden if the child wants to, but don’t have to be. This function could have been marked as either, but I decided to mark it as virtual.
  4. The colon here indicates that the Rook class is the child of the ChessPiece class.
  5. The “: base(x, y) { }” part of the constructor indicates that Rook doesn’t need a special constructor and it can just do whatever the ChessPiece class does in its constructor. I could have chosen to put something in the curly brackets, and in that case, it would have executed that code before the ChessPiece part. I decided not to because I didn’t think there was anything special that the Rook needed.
  6. Finally, the ‘override’ keyword here means that this function overrides the ChessPiece’s CanMove function.

Phew! That was a lot. Now how does all this apply to Narwhal Simulator? Well, the player needs to store a list of all the parts, and each type of part has something in common. For example, all the Flukes (back fins for people who didn’t read the last one) will have a speed or acceleration variable, but each one may want to do its own thing in Start, Update, or whatever. 

Well, that’s everything I have for you. Sorry that this one has been so technical (I feel like I’ve been saying that a lot lately), but I hope you learned something and maybe even enjoyed it. If you want to know more, here’s a good article about it on the MSDN: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/object-oriented-programming. I’m sure you can find a good tutorial for your language of choice, although many languages don’t support or need the full object-oriented experience that C# has. As always, if you have any questions, let me know in the comments and I’ll try my best to reply! Thanks for reading! I hope to have some actual progress on the game to show you by Tuesday!

Links recap:

GitHub: https://github.com/AgentD1/NarwhalSimulator

Trello: https://trello.com/b/Nd7rNvWU/narwhal-simulator

Leave a Reply