Back to home ©Catonator 2021
Programming portfolio

I have tinkered with several languages over the years:
C#, C++, Java, Python, GML...
Here are some more recent examples of work I've done, mostly entirely on my own.


BeepScript is my proprietary scripting language written for use in CatEngine.
For example, here's a small GIF of the player controller in a test project written in the engine:

The player script goes as follows:

//test comment, this is all ignored
int x = 0;
int y = 0;

int xspeed = 0;
int yspeed = 0;

//for multiplayer
int PlayerIndex = 0;

//should be turned into a macro once that's done
//macro PlayerHeight 11;
int PlayerHeight = 11; //11px, in the penguin sprite

//macro Gravity 0.32;

int Direction = 1;

int Landed = 0;

/*this is a comment*/
int AnimationIndex = 0;
float ImageIndex = 0.0;

/*this is a comment, it should be ignored
even in multiline form*/
func void Spawn()
	xspeed = 0;
	yspeed = 0;

//finding the current floor height
func int FindFloorHeight()
	//no break statement yet
	int i = 0;
	//3 loops
	while (i < 3):
		if (GetTileSolidityPoint(0, x, y + 16*i)):
			return GetTileFloorPoint(0, x, y + 16*i);
		i += 1;
	//no floor found, so we'll just set an arbitrary value below the player
	return y + 128;

func void Update()
	//tile collision logic
	int Floor = FindFloorHeight();
	if (y + PlayerHeight >= Floor - 2):
		y = Floor - PlayerHeight;
		Landed = 1;
		yspeed = 0;
		Landed = 0;
	//horizontal movement
	if (IsButtonHeld(KEY_LEFT)):
		xspeed = -2;
		Direction = -1;
	else if (IsButtonHeld(KEY_RIGHT)):
		xspeed = 2;
		Direction = 1;
		xspeed = 0;
	if (IsButtonPressed(KEY_A) && Landed):
		yspeed = -5;
		Landed = 0;
	else if (IsButtonReleased(KEY_A) && Landed == 0 && yspeed < 0):
		//stopping the jump
		yspeed = 0;
	if (IsButtonPressed(KEY_B)):
		entity bullet = SpawnEntity(x, y, enPlayerBullet);
		bullet->Direction = Direction;
	if (Landed == 0 && yspeed < 7):
		yspeed += Gravity; //f-f-f-falling
	//quick animation code
	if (Landed == 0):
		AnimationIndex = PlayerJump;
		ImageIndex = 0;
	else if (xspeed != 0):
		AnimationIndex = PlayerWalk;
		ImageIndex += 0.25;
		AnimationIndex = PlayerIdle;
		ImageIndex = 0;

	x += xspeed;
	y += yspeed;
	SetCameraPos(x, y);

func void Draw()
	//DrawSpriteExt(x, y, PlayerGunWalk, ImageIndex, 0, Direction, 1);
	DrawSpriteExt(x, y, AnimationIndex, ImageIndex, 0, Direction, 1);

The compiled bytecode takes about 900 bytes. It's not the most efficient in terms of shaving off the size; the full script is about 2.5kb,
but the end result is that the game code is extremely modular and easy to manage. The interpreter is also reasonably fast.

The language isn't very complex. My main inspirations for the design of it were Game Maker Language (GML) as well as C#.
GML's structure is extremely simple, which makes it absolutely perfect for simple 2D games.
Something of note is the lack of #include and class structures: while the game engine does have entity "classes," the language doesn't!

Each *.bs script file is its own class. The compiled bytecode is loaded from the class into memory, and the game engine calls the functions
Spawn(), Update() and Draw() on the required occasions (entity creation, game tick update and drawing after update, respectively).
This design has some unfortunate effects, such as the fact that inheritance doesn't really exist. It can be worked around, but it's
sometimes very annoying.

The interpreter turned out to be the easier part. While some aspects of instruction set and interpreter design were kind of a mystery to me,
such as the pros and cons of fully register-based VMs compared to stack-based ones, writing the interpreter turned out quite well in the end.

Shown here is a snippet of the compiled script in its bytecode form. I'm not 100% sure what this code piece does.

Writing the compiler was a harder task. I didn't really know how to write one, I didn't know what parts go to writing a compiler or what makes a good one.
Resources online were scant, and to my surprise I couldn't even find any solid-looking books about compiler design either. In the end I ended up writing
a solid-ish lexer and parsed almost by sheer accident. The compiler isn't very memory efficient and has a pretty notable amount of bugs still remaining,
which I've been too tired to work on for the past few months.

Keen readers may have noticed the large number of functions in the code not defined in the example before. Those are wrapper functions for the game engine,
Stored entirely on the C++ interpreter's side. The function is executed using the EXFNC instruction you can spot in the output above.

Similarly a mystery is the commented-out "macro", which sets a compiler constant, and the use of semicolons (':') after statements. The former is one of the
aforementioned bugs and the latter is a leftover from when parentheses were still broken.

Work in progress...

I haven't finished writing my programming portfolio fully yet...