3D Starfield made using Python and Pygame

In this tutorial I will show you how to create a pretty cool 3D Starfield simulation using Python and Pygame. See in the video below a demonstration of the simulation.

 

Click here to download the full source code.

NOTE: In previous tutorials, I have demonstrated how to create a Simple Starfield as well as how to create a Parallax Starfield.

The Code

To simulate the effect of a 3D starfield, we initially create a list of stars that are randomly positioned in the world. Each star is represented as a 3D coordinate, I mean, for each star we just store its X,Y and Z coordinates. Then we start the animation loop where we decrease the star’s Z coordinates on each frame. Decreasing the Z coordinate of a star makes it appear to be approaching the screen. When a star disappears from the screen, we reposition it again in the screen giving it random X and Y coordinates, and setting Z = maximum depth.

To make it even more interesting, we make closer stars bigger than distant stars. Similarly, we make closer stars brighter than the distant ones.

Since the stars are represented as 3D coordinates, they must be converted to 2D before being drawn into the screen. The code does that  using perspective projection formulas.

The code is presented below. As you can see, the simulation is made with very few lines of code. If you have any doubt or suggestion, please don’t hesitate to leave a comment.

"""
 3D Starfield Simulation
 Developed by Leonel Machava <[email protected]>

http://codeNtronix.com


http://twitter.com/codentronix

"""
import pygame, math
from random import randrange

class Simulation:
    def __init__(self, num_stars, max_depth):
        pygame.init()

        self.screen = pygame.display.set_mode((640, 480))
        pygame.display.set_caption("3D Starfield Simulation (visit codeNtronix.com)")

        self.clock = pygame.time.Clock()
        self.num_stars = num_stars
        self.max_depth = max_depth

        self.init_stars()

    def init_stars(self):
        """ Create the starfield """
        self.stars = []
        for i in range(self.num_stars):
            # A star is represented as a list with this format: [X,Y,Z]
            star = [randrange(-25,25), randrange(-25,25), randrange(1, self.max_depth)]
            self.stars.append(star)

    def move_and_draw_stars(self):
        """ Move and draw the stars """
        origin_x = self.screen.get_width() / 2
        origin_y = self.screen.get_height() / 2

        for star in self.stars:
            # The Z component is decreased on each frame.
            star[2] -= 0.19

            # If the star has past the screen (I mean Z<=0) then we
            # reposition it far away from the screen (Z=max_depth)
            # with random X and Y coordinates.
            if star[2] <= 0:
                star[0] = randrange(-25,25)
                star[1] = randrange(-25,25)
                star[2] = self.max_depth

            # Convert the 3D coordinates to 2D using perspective projection.
            k = 128.0 / star[2]
            x = int(star[0] * k + origin_x)
            y = int(star[1] * k + origin_y)

            # Draw the star (if it is visible in the screen).
            # We calculate the size such that distant stars are smaller than
            # closer stars. Similarly, we make sure that distant stars are
            # darker than closer stars. This is done using Linear Interpolation.
            if 0 <= x < self.screen.get_width() and 0 <= y < self.screen.get_height():
                size = (1 - float(star[2]) / self.max_depth) * 5
                shade = (1 - float(star[2]) / self.max_depth) * 255
                self.screen.fill((shade,shade,shade),(x,y,size,size))

    def run(self):
        """ Main Loop """
        while 1:
            # Lock the framerate at 50 FPS.
            self.clock.tick(50)

            # Handle events.
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    return

            self.screen.fill((0,0,0))
            self.move_and_draw_stars()
            pygame.display.flip()

if __name__ == "__main__":
    Simulation(512, 32).run()

Click here to download the full source code.

If you liked this article, please consider leaving a comment, or sharing this post using one of the buttons below, or even subscribing to the blog.

Leave a comment ?

10 Comments.

  1. waaaa, this reminds me of the old windows screensaver x3
    good old times… when i didnt knew nothing about programming xD

  2. Nice, thx for the code

  3. Yes! thanks! just what I needed for a project I’m working on! But I noticed that you don’t actually use any math, and it works fine without importing it… but still, this code is great!!

    • I applied basic 3D math to develop this demo. It wasn’t needed to import any math library since the math functions I used are available by default.

  4. Omg, these tutorials are so helpful!

  5. I don’t care about this, now i’m earning average £2500 a month.
    There is tricky method i found on the internet.
    If you want to learn it too, simply type in google: Irahsik’s betting system

  6. pretty nifty!

Reply to Fabyola ¬
Cancel reply

Notify me of followup comments via e-mail. You can also subscribe without commenting.

Trackbacks and Pingbacks: