Since the start of the year I've been solo-working on my game called CompNerdSim. This isn't a game I'm making with the studio I'm a part of, STAG, that will come soon.
If you don't know the premise of CompNerdSim, the layout of the game is similar to a desktop, with icons and windows. The game includes a code editor, which can be used to write in an interpreted language called Slither.
The Graphics Library
I needed a way to let Slither interface with the screen, so I needed to add functions that can draw basic objects. Luckily, not too long ago, I had added objects, so I could bring these functions together into one object.
clr = graphics.Color(0, 0, 0)
That's black, but we can make any color, including white. This makes it easy to pass around colors.
graphics.fill(clr)
That's a good one for clearing the screen.
graphics.rect(100, 100, 100, 100, clr)
Now we can draw rectangles anywhere on the screen. In this case, clr
is black, but it can be any color.
graphics.circle(320, 160, 10, clr)
Using a position and a radius, the ball can be drawn with this circle. That's all we really need for now, there is a line drawing function, but we're not going to worry about that right now.
Also, we're not going to worry about score, so don't stress about text and fonts (although a tally system could be cool).
So now we have some nice functions we can use, but games need player input.
Creating an input API
This I only made in one day, so we don't care about the mouse. All we really want is to check whether a key is up or down, and we can.
p1up = input.keyDown("w")
It's that simple, nothing too interesting here, but just remember that we have this function now.
Writing Pong
Because I'm hardcore, I didn't write the code for the game in my usual code editor, Neovim, nor did I use notepad. I used the code editor in the game, which is called BScode. The editor is mostly fine, but you have to remember that I made it, so it's slightly sketchy. This was true until near the end of the project, which I'll get into later, but I switched to notepad after line width issues (I haven't implemented window resizing and this seemed like a bad time).
However, I persisted and this is the code I ended up with for pong.
clear()
white = graphics.Color(255, 255, 255)
black = graphics.Color(0, 0, 0)
class Ball {
x
y
dx
dy
func init() {
self.x = 320
self.y = 160
self.dx = 10
self.dy = 10
return self
}
func move(p1y, p2y) {
self.x = self.x + self.dx
self.y = self.y + self.dy
if self.y > 278 {
self.dy = 0-10
}
if self.y < 10 {
self.dy = 10
}
if self.x > 610 {
if self.y > p2y {
if self.y - 100 < p2y {
self.dx = 0-10
}
}
}
if self.x < 30 {
if self.y > p1y {
if self.y - 100 < p1y {
self.dx = 10
}
}
}
if self.x > 640 {
self.x = 320
self.y = 160
}
if self.x < 0 {
self.x = 320
self.y = 160
}
return self
}
}
ball = Ball()
class Game {
ball
p1y
p2y
running
func init(ball) {
self.ball = ball
self.p1y = 10
self.p2y = 10
self.running = true
return self
}
func movePlayers() {
p1up = input.keyDown("w")
if p1up {
self.p1y = self.p1y - 10
}
p1down = input.keyDown("s")
if p1down {
self.p1y = self.p1y + 10
}
p2up = input.keyDown("u")
if p2up {
self.p2y = self.p2y - 10
}
p2down = input.keyDown("j")
if p2down {
self.p2y = self.p2y + 10
}
return self
}
func update() {
self = self.movePlayers()
self.ball = self.ball.move(self.p1y, self.p2y)
return self
}
func tick(black, white) {
graphics.fill(black)
graphics.circle(self.ball.x, self.ball.y, 10, white)
graphics.rect(10,self.p1y,10,100,white)
graphics.rect(620,self.p2y,10,100,white)
self = self.update()
self = self.checkExit()
return self
}
func checkExit() {
escape = input.keyDown("escape")
if escape {
self.running = false
}
return self
}
}
game = Game(ball)
for i = 0; game.running; i = i + 1 {
game = game.tick(black, white)
}
graphics.fill(black)
This is 123 lines of code, which I'm pretty happy with considering it's in a language I made up. There is something really important to notice, however, and it's that most code that needs to run every frame is in functions and methods. The only thing that's run outside is the loop, and calling game.tick
. The reason for this is because Slither is interpreted one line per frame. This means that if you're writing 60 lines of code for each frame, your game will run at a frame per second. However, calling a function only counts as one line, rather than all the lines inside of the function. Therefore, I can speed up my program to run (somewhat) fast. Also, don't even worry about the absence of a while loop, or the increment operator.
Something you may have found interesting was I subtract from 0 sometimes. This is because I (as far as I know) haven't implemented unary operators.
Lastly, you probably noticed I'm always returning self
at the end of methods. This is because a copy is passed when calling methods, not a reference. In this way, objects are more like structs.
The Result
I can't really show you all the code and not give a demonstration of the game working (even though you've probably seen pong a million times).
Pong Post-Mortem
Was this a great thing to do? It was probably a bit of a waste of time, however it did point out a lot of weaknesses in my language, and just how far it has to go before it's usable. When I release this game, this will obviously be just the start, and hopefully people take it way further than this. Personally, after release I wouldn't mind implementing a raycaster in Slither, or even Slither in Slither. I will leave it to some crazy person to inevitably implement DOOM in Slither.
If you want to try this game out when it comes out check out CompNerdSim. It's due to come out on the 29th of August. If you have any suggestions or want a copy of the game for testing purposes, feel free to contact me (: