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 and 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.
  • 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:

*Note to self: going to add more in the future!

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.

Blog Post About 2023-24 School Year

This year went by FAST. Quicker than sophomore year and MUCH quicker than freshman year. I honestly don’t know what things we did this year that I liked the most. I did like learning about JavaScript and using it to make websites in the backend, even though it was pretty confusing. I do like messing around in the frontend more than the backend because it gives me more freedom, but the backend makes your website POP in a way that the frontend doesn’t. IDK I know there’s tons of other stuff we’ve done this year but my mind has forced me to not remember maybe because of how stressful and frustrating it was, but that’s how it is with coding. I kinda enjoyed this year. I just hope senior year is just as fun ;-;.