3D Game Engine
TurtleAndrew (63)

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_)

If you need any help getting this code to work than you can ask in the comments and I will try to get back to you and help you make your own(mostly) 3D game. I have not implemented collision detection and do not plan on doing and the same for some other features so I will only be able to help you to a certain level before your going to have to go off on your own. I hope this code will help you and here's a link to a more in depth tutorial I posted:

Click Here To Go To The Tutorial
Click Here To Go To My Ray Tracer

I hope you enjoy!

You are viewing a single comment. View All
TurtleAndrew (63)

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