Friday, March 04, 2022

Obysuf: A Lazy Programmer's First Attempt at a Roblox Game

To inspire my Nieces and Nephew to see Roblox as a platform to create games, not just play them, I decided I should code my own.

The biggest hurdle to tackling this challenge is that I don't play games; Roblox or otherwise. Me crafting a game is like someone writing a novel who's never actually read one.

Still, I couldn't resist giving this a try.

My first step was to run through Introduction to Roblox Studio tutorial. Here I coded my very first game, an absurdly short obstacle course. Or is it's known in gamer lingo, an 'obby'.

But now what? Carefully crafting an obby would take hours of meticulous effort. To a lover of this art form, this would be fun. For myself it seemed like tedious work. And then it hit me: why not code the game so that it generates itself?

And with that, Obysuf was born. 'Ainsuf' is the Hebrew word for infinity, and if all went to plan, that's what I'd get: an infinitely long Obby that I didn't have to create from scratch.

After many false starts, I ended up with the following initialization code:

spawn(1, CFrame.new(-12, 0, 0));
spawn(1, CFrame.new(12, 0, 0));
spawn(1, CFrame.new(0, 0, -12));
spawn(1, CFrame.new(0, 0, 12));

These lines of code create four different Parts for the user to jump to. They are positioned around the user's SpawnLocation.

The magic happens when a Part is touched and the following code is executed:

function touched(depth, part)
	return function(source)
		if(part.BrickColor == untouchedColor and (source.Name == "RightFoot" or source.Name == "LeftFoot")) then
			part.BrickColor = touchedColor;
			earnPoint();
			local currentCf = part.CFrame;
			local gap = fuzz(depth * .1, depth * 1) + fuzz(-3, 3);
			local sX = (part.Size.Z + 2.5 + gap) * direction(part.Position.X);
			local sZ = (part.Size.X + 2.5 + gap) * direction(part.Position.Z);
			local sY = fuzz(-5, 5);
			local rX = math.deg(fuzz(1, 100) > 50 and fuzz(-3, 3) or 0);
			local rY = math.deg(fuzz(1, 100) > 50 and fuzz(-3, 3) or 0);
			local rZ = math.deg(fuzz(1, 100) > 50 and fuzz(-3, 3) or 0);

			local twist = CFrame.Angles(rX, rY, rZ);
			local nextCf = (currentCf + Vector3.new(sX, sY, sZ)) * twist;
			spawn(depth + 1, nextCf);
		end;
	end;
end

If the Part still has the untouchedColor, then the system knows this part hasn't been visited yet. Knowing this, the system can grant the user a point, change the color of the Part to the touchedColor and most importantly spawn a new Part. This freshly minted Part uses the fuzz function to add some randomness to its look and placement.

And that's essentially it. Every time the player lands on an obstacle the system will generate a fresh one for them to visit.

I'm really impressed with how little code I had to write before I could see Obysuf do something useful. Even in this very crude form, I found that after I died I'd check my point score and instinctually want to try again to best it.

Of course, I'm a long way from calling this a high quality game. The obstacles are being positioned too regularly, and I need to add more factors that impact the user's score. Still, it's a solid start and gives me some serious street cred when the kids start talking about gaming in Roblox.

You can play Obysuf on Roblox over here. And you can access the source code here.

No comments:

Post a Comment