Also called the beginning

So, as you can read one level higher, I decided to give Pascal a try. Because I am a very unoriginal person, I decided to make another game-thing. What can I say? I just like making things move on the screen for no apparent reason.

The idea

Ok, this will require a bit of cooperation.

Picture a vapor-wave-ish/neon road going through space. Some thematic music plays and beams of colorful light are next to the road on both sides. You are driving on the road, so the beams are scrolling by. As new ones appear, they change their height and color in sync with the music.

You are not driving just any plain old car. This is S P A C E, so you drive a spaceship. As you drive, enemy ships appear Galaxan style and you have to fight them, while dodging their attacks. Since it's already 3D, you have full 3D movement.

It's a simple retro-themed game in raylib, so there are no complex models. Most of the environment is made of simple shapes and ships are multi-layered 2D sprites.

I don't have all that much ideas as far as gameplay goes, but the visuals seem cool...

The beginning

So how does a project like this start? Well, you get raylib bindings of course!

One popular binding seems to be ray4laz. It looks very complete, but it seems to require some wrapper for using outside of Lazarus (free pascal IDE) and, more importantly, It bundles it's own raylib binaries in the repo, which I'm not a fan of.

I did however use it as a reference for how a C binding in pascal should look like. It is very easy to make C bindings in pascal. I already elaborated on that in my First thoughts about pascal b-log, so I will not repeat repeat myself here. I should probably add ont thing tho. You should not use 'cbool' as a return type. It does not work, just use 'boolean'.

Then I decided to split the codebase into many parts. I will further split most of them into 'logic' and 'draw' subparts, so that it's not all in one file.

I will now go ever them all.

Main, Core

Ok, those are not really that big, but they are important. Main is, as the name suggests, the entry point of the program.

It should not do that much. It just calls some initialise procedures and then calls some update and draw procedures inside a loop.

Core is more interesting.

There I store all the constants that are relevant for multiple different parts, so they don't really belong to any of them. I also store there program directory string and functions for converting between degrees and radians for good measure.

Highway

This is the fundamental drawing function.

It draws the highway and stars around it. For the highway, I can use raylib's 'DrawPlane' function. Drawing the central lines (I'm too lazy to look up how are they called) is fun. There are three rows, but I only have to store one variable. This variable stores how much have they moved and it loops when it reaches length + gap.

Then I just have two nested for-loops that draw the entire grid with the offset. The highway itself is transparent, as I want it to:

It still looks bad tho, because I'm drawing a transparent color on a black background. I solved this by drawing a bunch of white particles under the road. They are long rectangles, similar to the road lines.

Each particle is a Vector3 and I have 1600 of them. In addition to 700 stars, it might seem like I already use a bunch of resources without actually doing anything, but isn't that how most games are nowdays? We have good hardware today, so it should not be a problem, don't worry.

At the beginning, I place them randomly and then move them forward each frame. When they reach the end of the road, I move them at the end with random Z offset, so the road doesn't seem too repetitious.

Most of the road seems solid now, but it has cool prolonged transparent spots through which you can see the bottom of the beams. I think that it looks cool enough.

As far as the stars go, I have them in two 3D blocks, one on each side of the road. They move slower than the road, so it seems like they're distant, but not too slow, so that they aren't stationary.

I don't draw them under the road, because they wouldn't bee seen much anyways.

Originally, I tried drawing each star as a sphere. Turns out even modern hardware does not like drawing hundreds of spheres each frame, so I draw them as cubes now. They are too small to notice anyways. I should probably draw them as billboards, but nah, cubes are fine.

I sure hope that Pascal precalculates all it can, because I'm doing a lot of constant division.

You cannot create an anonymous record in pascal, so I create a lot of variables, just to pass them to one procedure and nothing else. It might be a bit more readable tho, so don't really mind.

Pascal does have a build in random function. You have to call 'Randomize' in each unit you use it in tho, so that is something to keep track of.

Beams

After the road, I also need the beams. I like beams.

After some testing, I have decided that the beams look best composed of three blocks. One is solid, in the center. Then I draw one bit bigger over it with some transparency. Finally, I draw a loooong one piercing them both vertically. This one is also transparent.

Each beam has a height, which also determines it's color. For now, I generate the size randomly, and then loop them. I tried to simulate a wave, but it didn't work. I will get the data from msic, once I have the music.

For the size, I used Pascal's range-limited types.

type
   TBeamSize = 1..MAX_BEAM_SIZE;

Also, the case statement does support ranges, so that's nice.

Texture stuff

Ok, this one is complex. First of all, I decided that if I get to the point where I have multiple levels with different enemies, I only want the used textures to be loaded. It won't change much, as The textures are very small, but I want to do it anyways.

Some textures are used all the time, so I don't want to reload them all the time. Thus I have two hash maps, one for static and other for dynamic textures. I interact with them via some wrapper functions, so that rest of the program does not need to think about it. I use the file names as the keys.

For the map, I used the built-in TFPGMap object. Note that the 'Keys' and 'Data' arrays are actually only methods, so you can not use them in 'for..in' loop or use functions like 'Length' on them. It does have a 'Count' attribute tho, so it's servicable.

At least in my experience, they complain about some inlining stuff, but you can ignore those warnings. They don't break anything.

One more thing about Pascal and raylib.

Raylib can store images in two ways. 'Image' and 'Texture2D'. (There is no 'Texture3D')

'Image' is stored in the RAM. This is good if you want to manipulate the texture, because you can access it. 'Texture2D' is stored in the VRAM. When you draw stuff on the screen, you use your GPU. The GPU has one problem tho: it sucks at accessing the RAM. This is why it has it's own RAM, the VRAM. You can not access it from outside the GPU, so that is why you also have 'Image'. I only want to draw stuff, so I'm using 'Texture2D'.

But there is one more problem. When you want to interact with the GPU, you have to initialise some stuff first. This is usually not a problem, because it is done in the 'InitWindow' function. Normally, I would make each part of my code have some init function that would get called in main directly after 'InitWindow'.

But pascal has other ways to do this. In your unit, you can have the 'Initialization' section, which will be called before the main program code. This means before 'InitWindow' gets called.

In short, don't be like me and don't try loading 'Texture2D' in there.

Ok, I have some textures, so now I only have to draw them, right? RIGHT? Well, not really. You see, raylib does support 3D, but it sucks at doing so. You can draw models, you can draw a billboard (Think entities in DOOM) but if you want to draw a texture in a fixed rotation on any axis, you cannot do that.

Ok, there is the 'DrawBillboardPro' function that might be able to do that, but it takes a shit ton of args, including a camera, which I don't like. (And now that I look at it, it does not seem much promising either)

Luckily, there is another way. RLGL: raylibs GL interface.

It is not all that well documented, but there is this example (you can find it on the examples page under 'models', 'draw cube texture', but I cannot link to that), which is enough to make a simple function for drawing textures in 3D space.

It did not work for me on the first try. Just keep shuffling the vertices and their offsets. It will work eventually.

My code does not currently do rotations, as I don't need them for now. Once again, the 'with' statement is very nice, more language should have one.

Entity system

I decided that entities should be objects inheriting from one parent 'Entity' object. I don't do much OOP, so don't expect anything crazy, but it seems fitting in this case.

OOP in Pascal is... verbse. It makes sense, but that does not mean that I must like it.

You see, Pascal was designed for single-pass compilation. This means that compilers don't have to backtrack while compiling. It means faster compilation, which was even more important back then when Pascal was created, but it is not without it's downsides. Functions can only refer to functions defined before them.

Due to this, you first define a object type in the 'type' section of the unit, including all method headers and then in the 'Implementation' section, you write the actual implementation in whatever order is needed. To specify that it is a method of this specific class, fou prefix the name like so:

unit test;
interface

type
  TFoo = class
    public
      function DoStuff(X, Y : integer): integer;
  end;

implementation

function Addition(X, Y : integer): integer
beign
  Result := X + Y;
end;


function TFoo.DoStuff(X, Y : integer): integer;
begin
  Result := Addition(X, Y*2);
end;

Sure, you can copy and paste, but it's just that you have to define one function on two distant places in the file. Well, at least it's not a header file.

Each entity also has a static list of texture files it uses, so that they can be loaded. They also have hitboxes, that are used as a origin for the texture drawing.

Summary

Here, have a gif of the final product. You can compare it with your imaginations now.

Project seems to be going well. I like Pascal so far, even tho I still need to have the maual open all the time. It has been a while since I tried to make a proper game with pixelart and all (I made gforth-tetris but that's about it), So I'm looking forward to it.

Oh, and there is also a repo. I do not promise that it will produce a usable program at all times, nor that I will even ever finish it, it is primarily an experiment, and a game secondarily, but feel free to look into the code.

Bye!