3D Game Engine

This program renders a procedurally generated landscape in 3D. The perspective is off because I have to lower the fov(field of view) and shrink the size of the screen because repl runs pygame much slower and only allows the screen to be up to 800x 800 not the usual size I use 1200x 750. Also you will have to wait a moment for the program to create a map every time you start the game. I'm also sorry for any lag as pygame just isn't designed for 3D combined with using an online programing website to run it. The program also uses color blending and a basic shader based on the angle of the triangle being colored. Finally, I would recommend making the program window as big as possible for the best viewing experience.

Controls:

WASD(forward, left, backward, right)
Space(up)
Right Shift(Not left)(left)

Interesting facts:

There are 22500 polygons(triangles) in each map
There are 67500 3D points the program has to convert to 2D

Some images of the program running on my computer(not running on repl and without a max render distance):

And here's some more images of the world(not ran on repl) using my ray tracing lighting system that traces a ray from each point to the sun and check to see if it collides with anything. This feature is to slow for repl and will not be implemented. In this image I was getting around 0.3 fps:

How to project 3D objects using math and code:

If you want to make a 3D game, first, I wouldn't recommend pygame or repl. The best way to go about it would be to use one of the following, Open GL, Unreal Engine, Unity, and Godot. There are other libraries and game engines that will also allow for 3D games but those are some popular ones that are a great starting point. But if you do want to use pygame or another python3 library(with some minor modifications to the code), some of the code is shown bellow starting with the most complicated snippet of code that calculates the position to draw each 3D point on the screen:

``````def convert_3D_to_2D(vec3_pos):
vec3_dist = [vec3_player_pos[0] - vec3_pos[0], vec3_player_pos[1] - vec3_pos[1], vec3_player_pos[2] - vec3_pos[2]]
vec2_intercection_point = [0, 0]

try:
m = vec3_dist[1] / vec3_dist[2]
except ZeroDivisionError:
m = 0
y = m * player_fov + vec3_pos[1]
vec2_intercection_point[1] = y

try:
m2 = vec3_dist[0] / vec3_dist[2]
except ZeroDivisionError:
m2 = 0
y2 = m2 * player_fov + vec3_pos[0]
inwerds = y2
vec2_intercection_point[0] = inwerds

return vec2_intercection_point``````

Than from there, if you want to get the color and some other data about the object the code to do that it:

``````    new_points = []
for triangle in mesh:
if int(triangle[0][2]) - int(vec3_player_pos[2]) in range(-100, render_dist) and int(triangle[0][0]) - int(vec3_player_pos[0]) in range(-100, render_dist2):
vec2_1 = convert_3D_to_2D(triangle[0])
vec2_2 = convert_3D_to_2D(triangle[1])
vec2_3 = convert_3D_to_2D(triangle[2])
# draw the triangle
if int(vec2_1[0]) in range(0, width * 3) and int(vec2_1[1]) in range(1, height * 3) and int(vec2_2[0]) in range(0, width * 3) and int(vec2_2[1]) in range(1, height * 3) and int(vec2_3[0]) in range(0, width * 3) and int(vec2_3[1]) in range(1, height * 3):
# shading the color based on the angle on the triangle
shaded2 = (triangle[0][1] - triangle[2][1]) * 2
# the next line is the color of your mesh, change it to be any rgb color you want
object_color = (0, 180, 0)
color = (clamp(clamp(object_color[0] - shaded2, object_color[0]] - 25, object_color[0] + 25), 0, 255), clamp(clamp(object_color[1] - shaded2, object_color[1] - 25, object_color[1] + 25), 0, 255), clamp(clamp(object_color[2] - shaded2, > object_color[2] - 25, object_color[2] + 25), 0, 255))``````

And the code to draw the new object using the data obtained from the code above is bellow:

``````for n in new_points:
pygame.draw.polygon(screen, n[3], [n[0], n[1], n[2]])``````

To make both these functions work, you will need to have the var mesh be a list of list with each of the lists in the mesh variable being a list of three vector3(x, y, z) positions aka the positions of each of the 3 points on a triangle. You can also change the objects color by changing object_color to any rgb(red, green, blue) value you want.
One more function needed to make the functions above work is bellow:

``````def clamp(value, min_, max_):
return min(max(value, min_), max_)``````

I hope you enjoy!

You are viewing a single comment. View All
JonDoeBeep (21)

And you somehow did this with a 2d game library

TurtleAndrew (60)

@JonDoeBeep Yes, 3D graphics are 2D graphics. You just have to convert the 3D point to a 2D point. There's a link to a tutorial I posted that explains the math and how it works. You basically create two 1D lines and find the intersection point of the players eye at z 30. The number 30 would be the players fov aka field fo view.

JonDoeBeep (21)

@TurtleAndrew I know, I was praising you. I have trouble doing 3d in 2d libraries. My games always run at like 2 frames per minute

TurtleAndrew (60)

@JonDoeBeep It dose run slower because I have not implemented a lot of features that 3D game engines would normally use.

TurtleAndrew (60)

@JonDoeBeep Mine to, it runs about 4 - 12 fps when not running on repl without a maximum render distance.

TurtleAndrew (60)

@TurtleAndrew This is also my first 3D game fyi.

TurtleAndrew (60)

@TurtleAndrew That would be about 1 - 3 fps on repl

JonDoeBeep (21)

@TurtleAndrew yours ran wayy faster than mine. I got to look up some tutorials

TurtleAndrew (60)

@JonDoeBeep I can help you make yours run faster. Also pygame just runs so slow on repl. Nothing will ever make it run fast. A game that runs at 15 fps which is pretty normal for me on repl runs at like 2.

TurtleAndrew (60)

@JonDoeBeep If you know linear equations than the math behind the 3D to 2D conversions would be very understandable.

TurtleAndrew (60)

@TurtleAndrew There's some images above of what the program can do when not running on repl at about 4 fps.

TurtleAndrew (60)

@JonDoeBeep If you want help, I can help you make it run faster.

TurtleAndrew (60)

@JonDoeBeep I'm also working on a ray tracer. It's not very close to working and runs at about 1/5 a frame per minute.