Steven Kirby

Portfolio - Coursework


Return to Home Page | Highlights Year 1 Year 2 Year 3 | Personal Projects Follow me on GitHub

Coursework - Highlights


Dissertation - Generation of Islands and Simulating Climate Change using OpenGL

My dissertation is available to read online(.pdf) at the link above.


Most images on my portfolio can be enlarged by holding down the left mouse button on the image

Poster

For my 3rd year dissertation I wanted to explore graphics within programming as I had never quite grasped how to implement them.

Tackling this topic enabled me to explore the belly of the beast, I utilised a codebase provided to us during the graphics module I was doing that year.

This provided a framework in which to easily set up a window using OpenGL as well as a few other features, however understanding the codebase I had never used before made this slightly more difficult; albeit increasing my confidence in using another programmers complex code.


Planning - Gantt Chart

In order to organise my dissertation I used a Gantt chart which changed over time as needed.

I enjoy games with wide open worlds that can be explored, and naturally wanted to generate random islands to replicate this, this changed after discussion with my tutors.

The biggest change was to incorperate climate change and rising sea levels, which are returning to the forefront of issues we face once again.

I made the decision to use heightmaps of the UK rather then randomly generated islands, in hopes of making people aware that these are real issues, not just an interesting graphics demo.


The Result

This project was a challenging experience for me, however I managed to achieve what I had set out to do, albeit not as pretty as I would have liked.

The image shows the erosion and the inundation of water upon the UK after the sea level had risen.


Data Analysis Graph

Another aspect of this dissertation I enjoyed was the data analysis of testing performance of the simulation with different detail or tesselation levels, amount of textures being rendered etc.

This is just one example of the graphs I produced in Excel, this particular graph using the fps, x and y position of the 'camera' to see how much the render times/fps were effected by how much of the model was showing on the screen.


Assignment 1 - Space Scene

Using OpenGL to create a space scene which needed to incorporate the sun, stars, a planet and a spaceship (user controlled).

I also added in a moving comet which randomly starts at a location in the distance and flys towards the player, when leaving the screen it starts somewhere randomly in the distance again.


Assignment 2 - Shaders

Using OpenGL and GLSL I was to create four requested effects on cubes, and come up with two of my own.

The two that I came up with on my own were the shattering cube and the twisting smiley cube.


Moodboard, Fontboard, Storyboard and Business Case

This stage was designing and developing ideas for the app, once I had started the storyboard I had a pretty good idea of what I wanted the app to look like.

I also kept track of any ideas or problems I came across for the app in a spreadsheet


Coding the App

In this stage I programmed my app using Android Studio, I used Java for this rather then Kotlin.

The embedded Youtube video shows the app in action with voice over explaining what I am doing on the app.

I then wrote a reflective essay on my experience designing and programming the app, highlighting what went right and what went wrong, as well as what I had learnt from this assignment.


What 'off' earth is Space Chess?

The task for this assignment was to create a simulation of a Rook , Bishop, and Queen on a board, these pieces could move any distance by teleportation within the board including non-integer values (unlike chess).

I learnt a lot about polymorphism and inheritance as well as collision detection of simple shapes within a 2d space.

Show me the code! (Game.cpp)

/**
Space Chess, Game.cpp
Purpose: Test Space Chess

@author Steven Kirby
@date 07/12/18
*/

#include "Piece.h"
#include "Queen.h"
#include "Bishop.h"
#include "Rook.h"
#include <time.h>
#include <iostream>
#include <vector>
#include <string>


using namespace std;

int main() {

	const int MAX_TURNS = 1000;
	const int PIECE_QUANTITY = 5;

	//counter for how many turns has been had
	int turns = 0;

	//total scores{Rook, Bishop, Queen}
	int piecesScore[] = {0,0,0};

	vector<Piece*> pieces;

	//random seed
	srand(time(NULL));
	
	// For loop creates PIECE_QUANTITY of each piece and places the pointer to the piece in the vector pieces 
	for (int i = 0; i < PIECE_QUANTITY; i++) {
		Piece* p1 = new Rook;
		Piece* p2 = new Queen;
		Piece* p3 = new Bishop;

		pieces.emplace_back(p1);
		pieces.emplace_back(p2);
		pieces.emplace_back(p3);
	}

	// Runs whilst there is more then 1 piece and we havent exceeded MAX_TURNS
	while (pieces.size() > 1 && turns < MAX_TURNS) {

		// Move each piece in turn
		for (int i = 0; i < pieces.size(); i++) {
			pieces[i]->Move();

			// Check if this piece has collided with all other pieces, if it has add to total score for this piece type, and call deconstructor for other piece that was "captured" and remove from vector
			for (int j = 0; j < pieces.size(); j++) {
				if (pieces[i]->CheckCollision(pieces[j]) == true) {
					pieces[i]->AddScore(piecesScore);
					pieces[j]->~Piece();
					pieces.erase(pieces.begin() + j);

					// Move onto next piece as shouldnt capture more then 1 piece each turn
					break;
				}
			}	
			
		}
		turns++;
	}


	// Print totals information
	cout << endl << "Turns taken by each piece:" << turns << endl;
	cout << "The Rook Pieces took " << piecesScore[0] << " in Total." << endl;
	cout << "The Bishop Pieces took " << piecesScore[1] << " in Total." << endl;
	cout << "The Queen Pieces took " << piecesScore[2] << " in Total." << endl;

	// Stop program from ending automatically, and allow user to exit
	cout << endl << "Press enter to exit: ";
	cin.ignore();
}


Show me the code! (Piece.cpp)

/**
Space Chess, Piece.cpp
Purpose: Abstract Chess Piece type

@author Steven Kirby
@date 07/12/18
*/

#include <string>
#include "Piece.h"
#include <iostream>
#include <algorithm>



//Limit the shapes
enum class shape { circle, square };

//Shorten main body of code when printing information using a info function with limited options
enum class info { p_position, p_symbol, e_collision, p_score };


/**
	Piece constructor, assigns shape based on symbol it recieves and assigns a random x,y position within the grid
	@param sym takes in a representative symbol of a piece type
*/
Piece::Piece(char sym)
{

	this->symbol = sym;
	
	//if its a rook, its a square shape, else its a circle shape
	this->shape = (this->symbol == 'R' ? square : circle);

	this->xpos = (float(rand()) / (float(RAND_MAX)) * GRID_X) ;
	this->ypos = (float(rand()) /  (float(RAND_MAX)) * GRID_Y) ;
}

/**
	Destructor frees memory taken by this piece when it is captured
*/
Piece::~Piece()
{
	free(this);
}

/**
	Clamp implementation, keep value between these params
	@param n value being tested
	@param lower the lower bound
	@param upper the upper bound
*/
float Piece::Clamp(float n, float lower, float upper) {
	return std::max(lower, std::min(n, upper));
}

/**
	Function that takes in a enum value and either 1 or 2 pieces to display information about
	@param req Request information
	@param piece Chess piece
	@param other Required for e_collison, 2nd Chess Piece

*/
string Piece::Info(Piece::info req, Piece* piece, Piece* other) {
	//p for position, e for event, i for information
	string str;

	switch (req) {
	case Piece::info::p_position:
		str = "(" + to_string(piece->xpos) + "," + to_string(piece->ypos) + ")";
		return str;
	case Piece::info::p_symbol:
		str = piece->symbol;
		return str;
	case Piece::info::e_collision:
		str = Info(Piece::p_symbol, piece) + " at position " + Info(Piece::p_position, piece) + " collided with " + Info(Piece::p_symbol, other) + " at position " + Info(Piece::p_position, other);
		return str;
	case Piece::info::p_score:
		str = "This piece has taken " + to_string(piece->takes) + " pieces";
		return str;
	default:
		return "ERROR";
	};
}



/**
	Method to check whether this piece collides with another
	@param other The other piece to check
*/
bool Piece::CheckCollision(Piece * other)
{
	//cout << "checking" << endl;
	if (this == other) {
		return false;
	}

	/*	Switch case checks what shape is colliding with what, it has the form
	circle(this)
	|  |
	|  ---circle(other)
	|  |
	|  ---square(other)
	|  |
	|  ---default;
	|
	square(this)
	|  |
	|  ---circle(other)
	|  |
	|  ---square(other)
	|  |
	|  ---default;
	|
	default;
	*/
	switch (this->shape) {
	case circle: {
		switch (other->shape) {
		case circle: {
			//SOHCAHTOA ( a^2 + b^2 = c^2)
			//Difference of x positions squared + Difference of y positions squared < Radius1 + Radius2 (same for these) squared
			if (fabs(((this->xpos - other->xpos) * (this->xpos - other->xpos)) + ((this->ypos - other->ypos) * (this->ypos - other->ypos))) < ((this->RADIUS + other->RADIUS) * (this->RADIUS + other->RADIUS))) {
				cout << Info(e_collision, this, other) << endl;
				return true;
			}
			return false;
			break;
		}
		case square: {

			//Clamp returns the max value between (other->xpos) and (minimum between other->xpos + side length or this->xpos)  
			float deltaX = this->xpos - Clamp(this->xpos, other->xpos, other->xpos + SIDE);
			float deltaY = this->ypos - Clamp(this->ypos, other->ypos, other->ypos + SIDE);

			//SOHCAHTOA again
			if (((deltaX * deltaX) + (deltaY*deltaY)) < (this->RADIUS * this->RADIUS)) {
				cout << Info(e_collision, this, other) << endl;
				return true;
			}
			return false;
			break;
		}
		default: {
			return false;
			break;
		}
		}
		return false;
		break;
	} // end of this == circle case

	case square: {
		switch (other->shape) {
		case circle: {
			//as above
			float deltaX = other->xpos - Clamp(other->xpos, this->xpos, this->xpos + SIDE);
			float deltaY = other->ypos - Clamp(other->ypos, this->ypos, this->ypos + SIDE);

			if (((deltaX * deltaX) + (deltaY*deltaY)) < (other->RADIUS * other->RADIUS)) {
				cout << Info(e_collision, this, other) << endl;
				return true;
			}
			return false;
			break;
		}
		case square: {

			//find the minimum and maximum x and y values
			float x1Min = this->xpos - (SIDE / 2);
			float y1Min = this->ypos - (SIDE / 2);
			float x1Max = this->xpos + (SIDE / 2);
			float y1Max = this->ypos + (SIDE / 2);
			float x2Min = other->xpos - (SIDE / 2);
			float y2Min = other->ypos - (SIDE / 2);
			float x2Max = other->xpos + (SIDE / 2);
			float y2Max = other->ypos + (SIDE / 2);

			//if one rectangle is to the left of the other completely then they haven't collided
			if (x1Min > x2Max || x1Max < x2Min) {
				return false;
			}
			//if one rectangle is above the other completely then they haven't collided
			else if (y1Min > y2Max || y1Max < y2Min) {
				return false;
			}
			//Must of collided so return true;
			else {
				cout << Info(e_collision, this, other) << endl;
				return true;
			}
			return false;
			break;
		}
		}
		return false;
		break;
	} // end of this == square case

	default: {
		return false;
		break;
	}
	} // end of switch
	
	
}

/**
	Adds a score to individual piece takes and displays how many pieces this piece has taken
	@param pieceScore Needs to be passed for derivitives to take in the array
*/
void Piece::AddScore(int pieceScore[])
{
	this->takes += 1;
	cout << Info(p_score, this) << endl;
}

Show me the code! (Queen.cpp)

/**
Space Chess, Queen.cpp
Purpose: A Queen Chess Piece type

@author Steven Kirby
@date 07/12/18
*/

#include "Queen.h"

/**
Calls Piece constructor with 'Q' symbol
*/
Queen::Queen() : Piece('Q')
{
	
}


Queen::~Queen()
{

}

/**
	Adds to total score of Queen pieces (hard coded) and adds to each pieces individual takes
	@param pieceScore array of total scores for pieces
*/
void Queen::AddScore(int pieceScore[]) {
	Piece::AddScore(pieceScore);
	pieceScore[2] += 1;
}

/**
	Queen can randomly move diagonally in either of 4 directions with equal distance moved x and y (direction can vary)like a bishop or like
	a rook can also randomly move horizontally or vertically in any of 4 directions 
*/
void Queen::Move()
{
	//Random whether going to be like a rook or like a bishop this move
	bool diagOrStr = rand() % 2;

	if (diagOrStr) {

		//see Bishop Move()
		float dis;
		int dir;
		dis = (float(rand()) / float(RAND_MAX)) * MAX_DISTANCE;
		dis = (dis == 0.0f) ? 0.1f : dis;
			
		do {	
			dir = (rand() % 2);
			dir = (dir == 0) ? -1 : 1;
		} while ((dir == 1) ? (dis + xpos) > GRID_X : (-dis + xpos) < 0);
			xpos = Clamp((dis * dir) + xpos, 0.0f, GRID_X);
		do {
			dir = (rand() % 2);
			dir = (dir == 0) ? -1 : 1;
		} while ((dir == 1) ? (dis + ypos) > GRID_Y : (-dis + ypos) < 0);
			ypos = Clamp((dis * dir) + ypos, 0.0f, GRID_Y);
		
	}
	else {

		//see Rook Move()
		float dis;
		bool dir = rand() % 2;
		do {	
			dis = ((float(rand()) / float(RAND_MAX)) * (MAX_DISTANCE + MAX_DISTANCE)) - MAX_DISTANCE;
			dis = (dis == 0.0f) ? 0.1f : dis;
		} while ((dir) ? (dis + xpos) < 0 || (dis + xpos) > GRID_X : (dis + ypos) < 0 || (dis + ypos) > GRID_Y);

		if (dir) {
			xpos = Clamp(dis + xpos, 0.0f, GRID_X);
		}
		else {
			ypos = Clamp(dis + ypos, 0.0f, GRID_Y);
		}
	}
	
}


Game Development - Godot

Link above takes you to a 'playable in browser' version of this prototype game.


Godot - Exported to HTML

The screenshot shows the game in action, it isn't perfect and was extremely ambitious for the time I had, alongside looming deadlines for other modules and my dissertation. More importantly I learned a lot about Godot and game development in general whilst making this prototype game.


Team Project - Seaton Valley Council - Android App

Link above leads to a git repository with only the code which was written by myself or a team member for this app and as such will not work as an imported project.


As part of our Software Engineering - Group Project module we were to design and develop an android app, this could be a variety of different options chosen by the university.

We decided as a group to take on the Seaton Valley Council app, which could provide information to residents of the parish.

The gif here shows the app in use, for this project I was lead programmer along with 2 other programmers and 2 testers, ensuring any code pushed using gitlab was functional and could integrate with previous code.





Lift Simulator

Using assembly language, we were tasked with controlling a lift.

We had a very limited amount of memory to work with.

This was the first time delving into a completely different type of programming, I had completed a few smaller tasks to help learn for this assignment including a traffic light control system.

Show me the code!
; ----- LIFT --------------------------
	JMP	Start		; Skip the db's
	db	A8		; Code for Timer Interupt stored in A8
	db	00		; Keyboard Interupt not used
	db 	AA		; Keypad Interupt Code stored in AA

Start:
	STI			; Set the Interupt
	MOV	CL, 4F	;o	; Set Register CL to char o
	MOV	DL, 54	;t	; Set Register DL to char t
	OUT	08		; Display Key Pad
	OUT	06		; Display lift window
	JMP	WaitUpButton	; Jump to check for button pressed

;------------ Display up and start up motor ------------
UP:
	
	IN	06		; Read Lift Status
	AND	AL, 04		; Isolate Near top check bit
	JNZ	WaitDownButton	; If near top go back to wait for buttons
				; else continue
	MOV	BL, 55		; Display "UP"
	MOV	[C0], BL	; |
	MOV	BL, 50		; |
	MOV	[C1], BL	; v
	MOV	BL, 0		; Clear Excess Letters using null
	MOV	[C2], BL	; |
	MOV	[C3], BL	; |	
	MOV	[C4], BL	; |
	MOV	[C5], BL	; v

	OR	AL, 01		; Set UP motor bit
	OUT	06		; Turn on UP motor
;------------ Start checking if near top -----------------
CheckU:	   
	AND	AL, 4		; Isolate near top check bit
	IN	06		; Read lift status
	JZ	CheckU		; If reached top continue else keep checking
	AND	AL, FE		; Turn off up motor
	OUT	06		; Send command to lift - turns off lift motor
	MOV	[C0], DL	; T
	MOV	[C1], CL	; O
	MOV	BL, 50		; set bl to p
	MOV	[C2], BL	; P
	
;------------- Check if any buttons have been pressed -----------
WaitDownButton:
	IN	06		; Read lift status
	AND	AL, 10		; Isolate down button
	JNZ	Down		; Jump to down if pressed else continue
	JMP	WaitDownButton  ; Keep checking
WaitUpButton:
	IN	06		; Read Status again
	AND	AL, 20		; Isolate up button
	JNZ	UP		; Jump to up if Pressed else continue
	JMP	WaitUpButton	; Keep checking till button pressed
;------------ Display down and start down motor ----------------
Down:
	
	IN	06		; Read lift status
	AND	AL, 08		; Isolate near bottom check bit
	JNZ	WaitUpButton	; If near bottom, go back and wait for buttons
				; Else continue
	MOV	BL, 44		; BL set to D
	MOV	[C0], BL	; D
	MOV	[C1], CL	; O
	MOV	BL, 57		; BL set to W
	MOV	[C2], BL	; W
	MOV	BL, 4E		; BL set to N
	MOV	[C3], BL	; N

	OR	AL, 02		; Set Down motor bit
	OUT	06		; Turn on Down motor
;------------ Start checking if lift is at bottom --------------
CheckD:
	AND	AL, 08		; Isolate near bottom check bit
	IN	06		; Read lift status
	JZ	CheckD		; If near bottom continue else keep checking
	AND	AL, FD		; Turn off down motor
	OUT	06		; Send command to lift - turns off lift motor

	MOV	BL, 42		; Set BL to B
	MOV	[C0], BL	; B
	MOV	[C2], DL	; T miss O as this would already be there from dOwn
	MOV	[C3], DL	; T
	MOV	[C4], CL	; O
	MOV	BL, 4D		; Set Bl to M
	MOV	[C5], BL	; M
	JMP	WaitUpButton	; Go back to wait for buttons again	
	
ORG A8
	iret			; Do nothing, return
ORG AA
	POP 	AL		; POP to prevent code overwriting, done first to prevent
				; quick presses of button affecting code

	IN	08		; Port for the peripheral keypad
	CMP	AL,0D		; Check if enter was pressed on pad
	JZ 	DOWN		; If it was jump to Down
	IN	06		; Read Lift Status
	AND	AL, 1		; Check if up motor was on
	JNZ	CheckU		; If it was check if near top to prevent crash		
	JMP	CheckD		; Else check if near bottom to prevent crash

END
; --------------------------------------------------------------


Tutorial Website




Voice clips and slides from the course are laid out in easy to use sections separating the different topics of the course

The user can use what they learn from the website and gain feedback immediately by using the live HTML, CSS, Javascript testing area, this was adapted from some code found online, the layout changes depending on what section of the tutorial website the user is on (shown in the pictures).