Making Minecraft Using Ursina & Python! (2/7/25 blog post)

**This continues from the 1/19/25 blog post**

KEYBOARD INPUTS

  • Now that we know how to speed the object up and down, let’s add some keyboard inputs.
  • in “def_update()”, we’re gonna add a module called “held_keys”. This will let you use any key you want on your keyboard (or your mouse keys) to control objects and entities on the screen.
def update():
    if held_keys['a']:
        test_square.x -= 1 * time.dt
  • You’ll also need to indent “test_square” for it to work (as shown above).
  • Now if we run it, we’ll be able to move the square by pressing “A” on the keyboard.

ADDING IMAGES IN URSINA

  • We now have our object and a way to move it. Now let’s add a picture. The picture will also need to be and entity (and will also be a square, or “quad” in this case).
  • We’re gonna call this entity “sans” (the short skeleton guy from Undertale that is probably the hardest character to go against in a Genocide run.)
sans = Entity(model = 'quad', texture = sans_texture)
  • Before we can see sans on the screen, we must make a texture. This will be simply called ‘sans_texture”, which will need an image (this will just be called “Sans.png”. You can store this in a folder if you want.)
sans_texture = load_texture('assets/Sans.png')
  • NOW we can run the program and see sans staring into your soul.
He can smell you.

*You also could just pass the “assets/Sans.png” instead of making a variable for it, and it’ll generate the same thing (unless you’re an overachiever and like doing things the difficult way).

sans = Entity(model = 'quad', texture = 'assets/Sans.png') #<- like this

CREATING 3D OBJECTS IN URSINA

  • Now, in an actual game, you’d want more control over all these things, so the code above is usually made to create simple images. To create more complex images, you’ll need to create a class for it, which we will do now.
  • Let’s make a cube. For this, we’ll make a class called “Test_cube” (I know, again, so creative). In it, we need it to inherit from something, which well be called “Entity”.
class Test_cube(Entity):
  • Inside the class, we need and “def __init__()” method so we can call our variables (there’s a reason why we need this, but I forgot why and don’t feel like looking it up). We’ll also need “super().__init__()” in order to call some attributes for the cube (model, color, texture, etc…).
class Test_cube(Entity):
    def __init__(self):
        super().__init__(
            model = 'cube',
            color = color.white,
            texture = 'white_cube'
        )

*Put this towards the top of your program btw (or don’t. I’m not your boss).

  • Now, we just need to call it, and it’ll show up on the screen when we run the program.
test_cube = Test_cube()
  • It doesn’t look 3D, but that’s because we haven’t added any rotation yet. In order to do that, we’ll add a rotation argument.
class Test_cube(Entity):
    def __init__(self):
        super().__init__(
            model = 'cube',
            color = color.white,
            texture = 'white_cube',
            rotation = Vec3(45, 45, 45)
        )
  • If we run the code, the cube should be rotated 45°.

*SO flipping cool.

  • You can also add images as a texture to a 3D object, like you can with a 2D object.

*Only terminally online people will get this reference

CREATING BUTTONS IN URSINA

  • We’ve covered a lot of stuff in this, but before we make an actual game (yes, this is just the basics of Ursina), we need to create a button. Buttons work slightly differently (not really).
  • To create a button, you have to create a class. This’ll be called “Test_button”. This will inherit from the class “Button” itself (which is already in Ursina, we don’t have to make a class called “Button”, same with “Test_cube”).
  • We will also add a “def__init__” method and a “super().__init__()” method in the class (where we’ll add some attributes in it too).
class Test_button(Button):
    def __init__(self):
        super().__init__(
            model = 'cube',
            texture = 'brick',
            color = color.orange
        )
NOTE: MAKE SURE TO COMMENT OUT “test_cube = Test_cube” OR ELSE IT’LL BE IN THE WAY!!!

If we run it, we’ll have a GIANT orange brick button created at the center of the screen.

test_button = Test_button()

*You’re able to press it, but it doesn’t do anything except light up and stuff.

  • Now, the problem with this is that the button is significantly larger than “test_cube”. In order to fix this, we need the “parent” argument for the button. In the parent argument, we need the “scene”, which is the game scene itself (I tried to find some information on what the parent argument doe and what a scene is, but I was left empty-handed…)
class Test_button(Button):
    def __init__(self):
        super().__init__(
            parent= scene,
            model = 'cube',
            texture = 'brick',
            color = color.orange
        )
  • If we run it, the button won’t absolutely massive anymore (massive?).

*This joke is so stupid.

Making Minecraft Using Ursina & Python! (1/19/25 blog post)

Ursina is an easy-to-use, open source 3D game engine that can run better than Pygame. Since Pygame has some issues with frame-rate, poor performance, and is not the best when making games with 3D capability, I won’t be using it (for this project). This is 3D games-wise, though. Pygame is still better and MUCH easier to use when making simpler looking games. Ursina only needs a few lines of code to really make a game, and is beginner friendly when making a 3D program. However, like Pygame, it does have some bugs that come with it such as player model issues, blend files unable to load, and collider issues when making a player model. Unfortunately, Ursina isn’t available for MacOS (you can use Panda3D though, which is available for MacOS and Windows).

Besides these issues, Ursina is quite powerful and a good option for a 3D game engine for beginners. Now, let’s get started.

INTRO TO URSINA

First and possibly the most obvious step is to install Ursina.

  • Open your terminal in whatever code editor you use and type in “pip install Ursina”
pip install Ursina
  • We’re now able to start coding. first import all objects of Ursina using the * character.
from ursina import *
  • Now, we must create an instance of the game. You can name this whatever you’d like, but for this it will be named “app” (I know, so creative).
app = Ursina()

*Make sure to add parenthesis at the end or the code will yell at you ( I learnt this the hard way numerous times).

  • Now, lets run it. This will create the interface where the game will be displayed.
from ursina import *
app = Ursina()
app.run()

* If you thought that it would look like something such as unity or unreal engine, remember that we are using Python, not C# or C++ lol.

  • The astronomically microscopic numbers on the top right-hand corner of the screen shows the frame rate, the number of entities on the screen, and the number of collisions.

OBJECTS IN URSINA

  • Lets add an entity, which is a base object for anything in Ursina. This can be anything, like a square, a circle, a cube, etc… Anything you see on the screen will count as an entity. It will be automatically added to the game, rather than calling it in a loop. An entity doesn’t need a color (it will default to white if no color is stated).
test_square = Entity(model='circle', color=color.blue)
  • This will create circle at the center of the screen when we run the program.
  • Let’s change it to a different shape.
test_square = Entity(model='quad', color=color.blue) 
  • This will change the circle into a square which it known as a “quad” in Ursina.

* You are able to add 3D objects like cubes, but since we’re looking at only one side at the moment, it’s kind of redundant to call a 3D object at the moment. We’ll get to that later, though.

  • You can also scale the entity by passing a number for the x and y axies.
test_square = Entity(model='quad', color=color.blue, scale = (1, 4))
  • In this instance, the 1 is how wide the entity will be, and the 4 is how long.
  • You can also change the position of the entity. It uses the same way we changed the scale of the entity, but this time we use “position” (or “pos” if you’re too lazy to write the whole word out).
test_square = Entity(model='quad', color=color.blue, scale = (1, 4), position = (5, 1))
  • This will move the square up 1 unit and right 5 units.
  • It should be obvious, but the center of the screen is the origin point (0,0). Making the y-axis positive or negative will scale or move the entity up or down, same with the x-axis (I know this is obvious but this 3D engine is interesting and fun to mess around in).
  • Now, lets make a function to move the entity. You will simply call the object you want to move in the function, the axis you wish to change, and how fast it will move.
def update():
    test_square.x -= 1
  • This will move the entity to the left at a speed of 1. Now, that may sound slow, but watch this:
Don’t blink or you’ll miss it lol
  • Now obviously we need to slow it down, so we’ll use “time.dt”. This will be multiplied by the speed at which the object is going, and will adjust to any frame-rate.
def update():
    test_square.x -= 1 * time.dt
  • It will now look like this:

1/10/25 BLog Post (Happy New Year!)

Attempting to finish up the Drum Kit in Python!!!!

What it does so far…

ADDING A PLAY/PAUSE BUTTON

First, create the button in the main loop, and place it on the screen.

play_pause = py.draw.rect(screen, grey, [50, HEIGHT - 150, 200, 100], 0, 5)
    play_text = label_font.render('Play/Pause', True, white)
    screen.blit(play_text, (70, HEIGHT - 130))

After that, create a new variable called “mediumFont” as in indicator if the program is playing or not. This will be connected to “play_text2”.

 if playing:
        play_text2 = mediumFont.render('Playing', True, darkGrey)
    else:
        play_text2 = mediumFont.render('Paused', True, darkGrey)
        screen.blit(play_text2, (70, HEIGHT - 100))

The “play_text2” will have “Playing” or “Pausing” shown on screen when the “Play/Pause” button is pressed.

So… we made the button show up on screen, but we haven’t made it actually work yet.

Down into where the buttons pressed on your keyboard are called, make a new event type of ‘MOUSEBUTTONUP”. This will make the program able to play and pause when the button is clicked.

if event.type == py.MOUSEBUTTONUP:
            if play_pause.collidepoint(event.pos):
                if playing:
                    playing = False
                elif not playing:
                    playing = True

RESULTS:

11/8/24 Blog Post

MAKING (still) A BEAT MAKER IN PYTHON WHOO!!!!

FULL CODE(so far)

import pygame as py

from pygame import mixer
py.init()

WIDTH, HEIGHT = 1400, 800

black = (0,0,0)
white = (255,255,255)
grey = (128, 128, 128)
green = (0, 255, 0)
gold = (212, 175, 55)
blue = (0, 255, 255)


screen = py.display.set_mode([WIDTH, HEIGHT])
py.display.set_caption("Beat Maker")
label_font = py.font.Font('Roboto-Bold.ttf', 32)

FPS = 60
timer = py.time.Clock()
beats = 8
instrumnents = 6
boxes = []
clicked = [[-1 for _ in range(beats)] for _ in range(instrumnents)]
bpm = 240
playing = True
active_length = 0
active_beat = 1
beat_changed = True

# ---------Sounds---------#
hi_hat = mixer.Sound('sounds\hi hat.WAV')
snare = mixer.Sound('sounds\snare.WAV')
clap = mixer.Sound('sounds\clap.wav')
kick = mixer.Sound('sounds\kick.WAV')
crash = mixer.Sound('sounds\crash.wav')
tom = mixer.Sound('sounds\\tom.WAV')
py.mixer.set_num_channels(instrumnents * 3)
# ------------------------#


def play_notes():
    '''plays the sound of the instrument'''
    for i in range(len(clicked)):
        if clicked[i][active_beat] == 1:
            if  i == 0:
                hi_hat.play()
            if  i == 1:
                snare.play()
            if  i == 2:
                kick.play()
            if  i == 3:
                crash.play()
            if  i == 4:
                clap.play()
            if  i == 5:
                tom.play()


def draw_grid(clicks, beat):
    # Making the boxes for the interface
    left_box = py.draw.rect(screen, grey, [0, 0, 200, HEIGHT - 200], 5)
    bottom_box = py.draw.rect(screen, grey, [0, HEIGHT - 200, WIDTH, 200], 5)
    boxes = []
    colors = [grey, white, grey]
    # Making the names of all the instruments
    hi_hat_text = label_font.render('Hi-hat', True, white)
    screen.blit(hi_hat_text, (30, 30))
    snare_text = label_font.render('Snare', True, white)
    screen.blit(snare_text, (30, 130))
    kick_text = label_font.render('Kick', True, white)
    screen.blit(kick_text, (30, 230))
    crash_text = label_font.render('Crash', True, white)
    screen.blit(crash_text, (30, 330))
    clap_text = label_font.render('Clap', True, white)
    screen.blit(clap_text, (30, 430))
    floor_tom_text = label_font.render('Floor Tom', True, white)
    screen.blit(floor_tom_text, (30, 530))
    # draw some lines between the instrument names
    for i in range(instrumnents):
        py.draw.line(screen, grey, (0, (i * 100) + 100), (200, (i * 100) + 100), 5)
    # check how many boxes there are for each instrument
    for i in range(beats):
        for j in range(instrumnents):
            if clicks[j][i] == -1:
                color = grey
            else:
                color = green
                # Making a tri-color effect with rects
            rect = py.draw.rect(screen, color, 
            [i * ((WIDTH - 200) // beats) + 205, (j * 100) + 5, ((WIDTH - 200) // beats) - 10, 
            ((HEIGHT- 200)// instrumnents) - 10], 0, 3)
            # Blank/ NOT colorful rect
            py.draw.rect(screen, gold, 
            [i * ((WIDTH - 200) // beats) + 200, (j * 100), ((WIDTH - 200) // beats), 
             ((HEIGHT- 200)// instrumnents)], 5, 5)
            py.draw.rect(screen, black, 
            [i * ((WIDTH - 200) // beats) + 200, (j * 100), ((WIDTH - 200) // beats), 
             ((HEIGHT- 200)// instrumnents)], 2, 5)
            boxes.append((rect, (i, j)))
        active = py.draw.rect(screen, blue, [beat * ((WIDTH-200)//beats) + 200, 0, 
                ((WIDTH-200)//beats), instrumnents*100], 5, 3)
    return boxes


# main loop
run = True
while run:
    timer.tick(FPS)
    screen.fill(black)
    boxes = draw_grid(clicked, active_beat)
    if beat_changed:
        play_notes()
        beat_changed = False

    for event in py.event.get():
        if event.type == py.QUIT:
            run = False
        if event.type == py.MOUSEBUTTONDOWN:
            for i in range(len(boxes)):
                if boxes[i][0].collidepoint(event.pos):
                    coords = boxes[i][1]
                    clicked[coords[1]][coords[0]] *= -1

    beat_length = 3600 // bpm

    if playing:
       if active_length < beat_length:
           active_length += 1
       else:
           active_length = 0
           if active_beat < beats - 1:
               active_beat += 1
               beat_changed = True
           else:
               active_beat  = 0
               beat_changed = True

    py.display.flip()
py.quit()

What it does so far:

Adding later: Different kits, a menu to select the kits, bpm change, and more.

def play_notes does as the name says… it plays the notes.

def draw_grid just makes the interface and puts them on the screen. It shows the names and the initial design of the program.

def draw_grid:

def draw_grid(clicks, beat):
    # Making the boxes for the interface
    left_box = py.draw.rect(screen, grey, [0, 0, 200, HEIGHT - 200], 5)
    bottom_box = py.draw.rect(screen, grey, [0, HEIGHT - 200, WIDTH, 200], 5)
    boxes = []
    colors = [grey, white, grey]
    # Making the names of all the instruments
    hi_hat_text = label_font.render('Hi-hat', True, white)
    screen.blit(hi_hat_text, (30, 30))
    snare_text = label_font.render('Snare', True, white)
    screen.blit(snare_text, (30, 130))
    kick_text = label_font.render('Kick', True, white)
    screen.blit(kick_text, (30, 230))
    crash_text = label_font.render('Crash', True, white)
    screen.blit(crash_text, (30, 330))
    clap_text = label_font.render('Clap', True, white)
    screen.blit(clap_text, (30, 430))
    floor_tom_text = label_font.render('Floor Tom', True, white)
    screen.blit(floor_tom_text, (30, 530))
    # draw some lines between the instrument names
    for i in range(instrumnents):
        py.draw.line(screen, grey, (0, (i * 100) + 100), (200, (i * 100) + 100), 5)
    # check how many boxes there are for each instrument
    for i in range(beats):
        for j in range(instrumnents):
            if clicks[j][i] == -1:
                color = grey
            else:
                color = green
                # Making a tri-color effect with rects
            rect = py.draw.rect(screen, color, 
            [i * ((WIDTH - 200) // beats) + 205, (j * 100) + 5, ((WIDTH - 200) // beats) - 10, 
            ((HEIGHT- 200)// instrumnents) - 10], 0, 3)
            # Blank/ NOT colorful rect
            py.draw.rect(screen, gold, 
            [i * ((WIDTH - 200) // beats) + 200, (j * 100), ((WIDTH - 200) // beats), 
             ((HEIGHT- 200)// instrumnents)], 5, 5)
            py.draw.rect(screen, black, 
            [i * ((WIDTH - 200) // beats) + 200, (j * 100), ((WIDTH - 200) // beats), 
             ((HEIGHT- 200)// instrumnents)], 2, 5)
            boxes.append((rect, (i, j)))
        active = py.draw.rect(screen, blue, [beat * ((WIDTH-200)//beats) + 200, 0, 
                ((WIDTH-200)//beats), instrumnents*100], 5, 3)
    return boxes

Voxel Engine in Python and OpenGL(Blog Post 10/4/24)

MAKING THE OPENGL WINDOW

To install OpenGL and other modules:

pip install PyOpenGL
pip install pygame moderngl PyGLM numba

First import the common modules for the program in “settings.py”.

from numba import njit
import numpy as np
import glm
import math

Put in the respective background color and window resolution in “settings.py”.

# Window resolution
WIN_RES = glm.vec2(1600, 900)

# Colors
BG_COLOR = glm.vec3(0.1, 0.16, 0.25)

Import modules in “main.py” and create a class of VoxelEngine.

from settings import *
import moderngl as mgl
import pygame as pg
import sys

class VoxelEngine:

class VoxelEngine:
    def __init__(self):
        pg.init()
        pg.display.gl_set_attribute(pg.GL_CONTEXT_MAJOR_VERSION, 3)
        pg.display.gl_set_attribute(pg.GL_CONTEXT_MINOR_VERSION, 3)
        pg.display.gl_set_attribute(pg.GL_CONTEXT_PROFILE_MASK, pg.GL_CONTEXT_PROFILE_CORE)
        pg.display.gl_set_attribute(pg.GL_DEPTH_SIZE, 24)

        pg.display.set_mode(WIN_RES, flags=pg.OPENGL | pg.DOUBLEBUF)
        self.ctx = mgl.create_context()

        self.ctx.enable(flags=mgl.DEPTH_TEST | mgl.CULL_FACE | mgl.BLEND)
        self.ctx.gc_mode = 'auto'

        self.clock = pg.time.Clock()
        self.delta_time = 0
        self.time = 0

        self.is_running = True

    def update(self):
        self.delta_time = self.clock.tick()
        self.time = pg.time.get_ticks() * 0.001
        pg.display.set_caption(f'{self.clock.get_fps() :.0f}')

    def render(self):
        self.ctx.clear(color=BG_COLOR)
        pg.display.flip()

    def handle_events(self):
        for event in pg.event.get():
            if event.type == pg.QUIT or (event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE):
                self.is_running = False

    def run(self):
        while self.is_running:
            self.handle_events()
            self.update()
            self.render()
        pg.quit()
        sys.exit()

if __name__ == '__main__':
    app = VoxelEngine()
    app.run()

(this will get larger overtime)

Define the attributes for the program (in “def __init__”).

pg.init()
        pg.display.gl_set_attribute(pg.GL_CONTEXT_MAJOR_VERSION, 3)
        pg.display.gl_set_attribute(pg.GL_CONTEXT_MINOR_VERSION, 3)
        pg.display.gl_set_attribute(pg.GL_CONTEXT_PROFILE_MASK, pg.GL_CONTEXT_PROFILE_CORE)

Set the window resolution and create OpenGL context

  pg.display.set_mode(WIN_RES, flags=pg.OPENGL | pg.DOUBLEBUF)
        self.ctx = mgl.create_context()

Enable the context and set the garbage collection mode(gc_mode) to ‘auto’

self.ctx.enable(flags=mgl.DEPTH_TEST | mgl.CULL_FACE | mgl.BLEND)
        self.ctx.gc_mode = 'auto'

After that, set a time variable to keep the window on the screen a variable to run things in the main function

self.clock = pg.time.Clock()
        self.delta_time = 0
        self.time = 0

        self.is_running = True

In “def update()”, set the delta time and update its tick for every frame, then put it as a caption on the top left-hand corner of the screen.

self.delta_time = self.clock.tick()
        self.time = pg.time.get_ticks() * 0.001
        pg.display.set_caption(f'{self.clock.get_fps() :.0f}')

Plaster the background color from “settings.py” and update it to the screen in “def render()”

 self.ctx.clear(color=BG_COLOR)
        pg.display.flip()

In “def handle_events()”, make a for loop that checks if the player has clicked the “x” on the window or the down arrow key and the “escape” key (Esc) and will turn “is_running” to be false, which closes the window.

def handle_events(self):
        for event in pg.event.get():
            if event.type == pg.QUIT or (event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE):
                self.is_running = False

Initialize all functions in “def run()”.

def run(self):
        while self.is_running:
            self.handle_events()
            self.update()
            self.render()
        pg.quit()
        sys.exit()

and this too for the code to actually work 🙂

if __name__ == '__main__':
    app = VoxelEngine()
    app.run()

RESULT:

W/O the background color:

WITH the background:

I’m now working on the initial setup 😀

9/36/24 Blog Post

making 2048 in Python.

SETTING UP THE SCREEN

Made a blank pygame screen.

Made it using the WINDOW constant variable.

WINDOW = py.display.set_mode((WIDTH, HEIGHT))

The tuple (WIDTH, HEIGHT) are also constants set at 800 by 800.

WIDTH, HEIGHT = 800, 800

DRAWING THE WINDOW

Made a function of draw to fill the window with the background color (BG_COLOR).

Outside draw()

BG_COLOR = (205, 192, 180)

Used the variable to fill the window color and then displaying it on the window.

def draw()

def draw(window):
    window.fill(BG_COLOR)
    draw_grid(window)
    py.display.update()

Added draw() to the main loop

Main Loop:

def main(window):
    clock = py.time.Clock()
    run = True
    while run:
        clock.tick(FPS)
 
        for event in py.event.get():
            if event.type == py.QUIT:
                run = False
                break
        draw(window)
            
    py.quit()

RESULT:

9/20/24 Blog Post

Added LOTS of stuff (more collision, lasers, rockets, pause menu, etc…)

ADDED LASERS ON THE SCREEN

def gen_laser:

laser_type = random.randint(0, 1)
    offset = random.randint(10,300) # how far off the screen
    match laser_type:
        case 0:
            laser_width = random.randint(100, 300) # horiz. laser
            laser_y = random.randint(100, HEIGHT - 100) 
            new_laser = [[WIDTH + offset, laser_y], [WIDTH + offset + laser_width, laser_y]]
        
        case 1:
            laser_height = random.randint(100, 300) # vert. laser
            laser_y = random.randint(100, HEIGHT - 400)
            new_laser = [[WIDTH + offset, laser_y], [WIDTH + offset + laser_y, laser_height]]
    
    return new_laser

Sets a random laser type (Horizontal is “0”, vertical is “1”) then sets the offset for how far it should be on the screen.

It then sees if the line is 0 or 1, then gives it a random height and offset and draws it on the screen (which is in the draw_screen function).

def draw_screen code for lasers:

# Using x values to stop lasers from moving if paused
lase[0][0] -= game_speed
lase[1][0] -= game_speed

    #drawing the laser lines on the screen

lase_line = py.draw.line(screen, "yellow", (lase[0][0], lase[0][1]), (lase[1][0], lase[1][1]), 10) #puts laser line on the screen
    py.draw.circle(screen, "yellow", (lase[0][0], lase[0][1]), 12) # top laser ball
    py.draw.circle(screen, "yellow", (lase[1][0], lase[1][1]), 12) # botton laser ball

Added an if statement in main loop. Will generate a laser if there isn’t one on already on the screen (also added laser variables to draw_screen()).

main loop:

if new_laser:
        laser = gen_laser()
        new_laser = False
    lines, top_plat, bottom_plat, laser, laser_line = draw_screen(lines, laser)

 if laser[0][0] <0 and laser[1][0] <0:
        new_laser = True

RESULT:

(Also added collision but I forgot to record it ;-;)

check_colliding(for the lasers):

 if laser_line.colliderect(player):
        rstrt = True

ADDED A RESTART FUNCTION WHEN COLLIDING WITH AN OBJECT

Made a restart global variable that is false on default.

restart_cmd = False

Made a separate restart local variable in check_colliding() which is also false by default.

check_colliding:

rstrt = False

Returns the restart variable when check_colliding() is finished.

check_colliding:

return coll, rstrt

Added restart_cmd with check_colliding in main loop.

main loop:

  colliding, restart_cmd = check_colliding()

Created an if statement that resets everything if the player hits an object.

main loop:

if restart_cmd: #literally restarts everything
        distance = 0
        rocket_active = False
        rocket_counter = 0
        pause = False
        player_y = init_y
        y_vel = 0
        restart_cmd = 0
        new_laser =True

RESULT:

(Also added distance and high score on the screen and made some simple code for it)

draw_screen:

 screen.blit(font.render(f"Distance: {int(distance)} m", True, "white"), (10, 10)) #distance text
    screen.blit(font.render(f"High Score: {int(high_score)} m", True, "white"), (10, 70))#high score text

main loop:

if distance > high_score:

    high_score = int(distance)

Only distance will reset when hitting an object. Not high score.

ADDED ROCKETS ON THE SCREEN

9/15/24 Blog Post

MADE COLLISION AND GRAVITY FOR THE JETPACK TO WORK!!!!!

Added a y velocity and gravity for the player and jetpack.

y_vel = 0 

grav = 0.2

made a if statement for the jetpack to work

if not pause:
        if booster:
            y_vel -= grav
            #makes player go up when pressing button
        else: y_vel += grav

        if (colliding[0] and y_vel > 0) or (colliding[1] and y_vel < 0):
            y_vel = 0
        #makes player go down when not pressing button
        player_y += y_vel

if the player presses the key down, the y vel will become negative, causing the player to go up (- gravity). if the player lets go of the key, the y vel will become positive, causing the player to go down (+ gravity).

colliding is a function to check_colliding. colliding[0] is the top of the game’s screen, and colliding[1] is the bottom. when the player goes up. check_colliding will check if the player has reached the top, and will add collision. Same thing will happen to the bottom of the screen.

check_colliding function

def check_colliding():
    coll = [False, False]
    if player.colliderect(bottom_plat):
        coll[0] = True
    elif player.colliderect(top_plat):
        coll[1] = True
    return coll

RESULT.

9/5/24 Blog post: Jetpack joyride

FULL code (so far)

#Jetpack Joyride in Python

import random
import pygame as py

py.init()

WIDTH = 1000
HEIGHT = 600

screen = py.display.set_mode([WIDTH, HEIGHT])
surface = py.Surface((WIDTH, HEIGHT), py.SRCALPHA)
py.display.set_caption("Jetpack Joyride Remake")
FPS = 60
timer = py.time.Clock()
font = py.font.Font('freesansbold.ttf', 32)
BG_COLOR = (128, 128, 128)
lines = [0, WIDTH//4, 2* WIDTH//4, 3* WIDTH//4]
game_speed = 2
pause = False
init_y = HEIGHT - 130
player_y = init_y
booster = False
counter = 0


#Drawing the background screen
def draw_screen(line_list):
    screen.fill("black")
    py.draw.rect(surface, (BG_COLOR[0], BG_COLOR[1], BG_COLOR[2], 50), [0, 0, WIDTH, HEIGHT])
    screen.blit(surface, (0, 0))
    top_rect = py.draw.rect(screen, 'gray', [0, 0, WIDTH, 50])
    bottom_rect = py.draw.rect(screen, 'gray', [0, HEIGHT - 50, WIDTH, 50])

    #making the infinite lines on the screen
    for i in range(len(line_list)):
        py.draw.line(screen, 'black', (line_list[i], 0), (line_list[i], 50), 3)
        py.draw.line(screen, 'black', (line_list[i], HEIGHT - 50), (line_list[i], HEIGHT), 3)
        if not pause:
            line_list[i] -= game_speed
        if line_list[i] < 0:
            line_list[i] = WIDTH
    return line_list, top_rect, bottom_rect


#Dawing the player and animated states
def draw_player():
    player_hitbox = py.rect.Rect((120, player_y + 10), (25, 60)) # Player' hitbox
    if player_y < init_y or pause:
        if booster:
            py.draw.ellipse(screen, 'red', [100, player_y + 50, 20, 30])# overall body of the flame
            py.draw.ellipse(screen, 'orange', [105, player_y + 50, 10, 30])# detail
            py.draw.ellipse(screen, 'yellow', [110, player_y + 50, 5, 30])# also detail
        py.draw.rect(screen,'#ffca69', [128, player_y + 60, 10, 20], 0, 3)#ligher leg
        py.draw.rect(screen,'#ffa600', [130, player_y + 60, 10, 20], 0, 3)#darker leg
    else:
        #drawing the animated legs
        if counter < 10:
            py.draw.line(screen, '#ffca69', [128, player_y + 60], [140, player_y + 80], 10)#lighter leg
            py.draw.line(screen, '#ffa600', [130, player_y + 60], [120, player_y + 80], 10)#darker leg
        elif 10 <= counter < 20:
            py.draw.rect(screen,'#ffca69', [128, player_y + 60, 10, 20], 0, 3)#ligher leg
            py.draw.rect(screen,'#ffa600', [130, player_y + 60, 10, 20], 0, 3)#darker leg
        elif 20 <= counter < 20:
            py.draw.line(screen, '#ffca69', [128, player_y + 60], [120, player_y + 80], 10)#lighter leg
            py.draw.line(screen, '#ffa600', [130, player_y + 60], [140, player_y + 80], 10)#darker leg
        else:
            py.draw.rect(screen,'#ffca69', [128, player_y + 60, 10, 20], 0, 3)#ligher leg
            py.draw.rect(screen,'#ffa600', [130, player_y + 60, 10, 20], 0, 3)#darker leg

    # Player's body        
    py.draw.rect(screen, 'white', [100, player_y + 20, 20, 30], 0, 5) # Player's jetpack
    py.draw.ellipse(screen, '#ffa600', [120, player_y + 20, 20, 50]) # Player's main body
    py.draw.circle(screen, '#ffa600', (135, player_y + 15), 10)# Player's head
    py.draw.circle(screen, 'black', (138, player_y + 12), 3)# Player's head
    return player_hitbox

# Main loop
run = True
while run:
    timer.tick(FPS)
    if counter < 40:
        counter += 1
    else: 
        counter = 0
    lines, top_plat, bottom_plat = draw_screen(lines)
    player = draw_player()

    for event in py.event.get():
        if event.type == py.QUIT:
            run = False

    py.display.flip()
py.quit()

DRAWING THE BACKGROUND SCREEN (and making the lines)!!!

“BG_COLOR” is the gray rectangle at the top and bottom of the screen evenly separated by the lines. They are then made to be transparent where the player and obstacles are going to be placed.

8/29/24 Blog post

I didn’t actually try to do a project today but I did watch a few videos on how to make a FPS 3D game in Unity. It explained the basics on how to make the player rig, and the different components to make the player rig be able to be controlled. It also explained the basic movement for the player rig, how to connect them to VS code in Unity, and rigging components together to make the player rig moveable.

That’s the farthest I got since I decided it would be a splendid idea and go do other errands… I promise to actually work on something next Friday :D.