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 ;-;.

Making a space shooter game ^-^

Made the startup code

main.py

import pygame as pg

# general setup
pg.init()
pg.display.set_caption("Space Shooter")
WINDOW_WIDTH, WINDOW_HEIGHT = 1280, 720
display_surf = pg.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
run = True

while run:
    #event loop
    for event in pg.event.get():
        if event.type == pg.QUIT:
            run = False
    
    #draw the game
    display_surf.fill('dodgerblue1')
    pg.display.update()

pg.quit()

created the window using pygame!!!!

Create a window width and height global variables for the window.

WINDOW_WIDTH, WINDOW_HEIGHT = 1280, 720

Make a display surface variable that sets the width and height for the pygame window.

display_surf = pg.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))

Make a while loop so that it stays on the screen and so the user can close the window at any time.

while run:
    #event loop
    for event in pg.event.get():
        if event.type == pg.QUIT:
            run = False

Now instead of having a black background, change the background color using the .fill() method. After that, use the .update() method to put it on the screen

 #draw the game
    display_surf.fill('dodgerblue1')
    pg.display.update()

RESULT:

Website Login Using React JS

Since we’ve been trying to learn React JS, I decided to make a website login using it!!

Made the login template

LoginRegister.jsx

import React from 'react'
import './LoginRegister.css';

const LoginRegister = () => {
    return (
        <div className='wrapper'>
            <div className="form-box-login">
                <form action="">
                    <h1>Login</h1>
                    <div className="input-box">
                        <input type="text"
                        placeholder='Username' required />
                    </div>
                    <div className="input-box">
                        <input type="password"
                        placeholder='Password' required />
                    </div>

                    <div className="remember-forgot">
                        <label><input type="checkbox" />Remember me</label>
                        <a href="#">Forgot Password?</a>
                    </div>

                    <button type="submit">Log in</button>

                    <div className="register-link">
                        <p>Don't have an account? <a
                            href="#">Register</a></p>
                    </div>
                </form>
            </div>
        </div>
    );
};

export default LoginRegister

index.css

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap');

body {
  font-family: "Poppins", sans-serif;
}

app.js

import LoginRegister from './components/LoginResgister/LoginRegister';

function App() {
  return (
    <div>
      <LoginRegister />
    </div>
  );
}

export default App;

I tweaked up app.js and took out all the sample code from index.css and put the stuff needed for the font we’re using. Then I added login inputs for username and password.

Username

<div className="input-box">
                        <input type="text"
                        placeholder='Username' required />
                    </div>

Password

Calculator in JS

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    
    <div id="calculator">
        <input id="display" readonly>
        <div id="keys">
            <button onclick="appendToDisplay('+')" class="operator-btn">+</button>
            <button onclick="appendToDisplay('7')">7</button>
            <button onclick="appendToDisplay('8')">8</button>
            <button onclick="appendToDisplay('9')">9</button>
            <button onclick="appendToDisplay('-')" class="operator-btn">-</button>
            <button onclick="appendToDisplay('4')">4</button>
            <button onclick="appendToDisplay('5')">5</button>
            <button onclick="appendToDisplay('6')">6</button>
            <button onclick="appendToDisplay('*')" class="operator-btn">*</button>
            <button onclick="appendToDisplay('1')">1</button>
            <button onclick="appendToDisplay('2')">2</button>
            <button onclick="appendToDisplay('3')">3</button>
            <button onclick="appendToDisplay('/')" class="operator-btn">/</button>
            <button onclick="appendToDisplay('0')">0</button>
            <button onclick="appendToDisplay('.')">.</button>
            <button onclick="calculate()">=</button>
            <button onclick="clearDisplay()" class="operator-btn">C</button>
        </div>
    </div>

    <script src="index.js"></script>
</body>
</html>

CSS:

body{
    margin: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: hsl(0, 0%, 90%);

}
#calculator{
    font-family: Arial, sans-serif;
    background-color: hsl(0, 0%, 15%);
    border-radius: 15px;
    max-width: 500px;
    overflow: hidden;
}
#display{
    width: 100%;
    padding: 20px;
    font-size: 5rem;
    text-align: left;
    border: none;
    background-color: hsl(0, 0%, 20%);
}
#keys{
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
    padding: 25px;
}
button{
    width: 100px;
    height: 100px;
    border-radius: 50px;
    border: none;
    background-color: hsl(0, 0%, 30%);
    color: white;
    font-size: 3rem;
    font-weight: bold;
    cursor: pointer;
}
button:hover{
    background-color: hsl(0, 0%, 40%);

}
button:active{
    background-color: hsl(0, 0%, 60%);

}
.operator-btn{
    background-color: hsl(198, 83%, 47%);

}
.operator-btn:hover{
    background-color: hsl(198, 83%, 67%);

}
.operator-btn:active{
    background-color: hsl(198, 83%, 87%);

}

I don’t have JS yet because I’ve not finished it :/

Created the display screen and buttons

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    
    <div id="calculator">
        <input id="display" readonly>
        <div id="keys">
            <button onclick="appendToDisplay('+')" class="operator-btn">+</button>
            <button onclick="appendToDisplay('7')">7</button>
            <button onclick="appendToDisplay('8')">8</button>
            <button onclick="appendToDisplay('9')">9</button>
            <button onclick="appendToDisplay('-')" class="operator-btn">-</button>
            <button onclick="appendToDisplay('4')">4</button>
            <button onclick="appendToDisplay('5')">5</button>
            <button onclick="appendToDisplay('6')">6</button>
            <button onclick="appendToDisplay('*')" class="operator-btn">*</button>
            <button onclick="appendToDisplay('1')">1</button>
            <button onclick="appendToDisplay('2')">2</button>
            <button onclick="appendToDisplay('3')">3</button>
            <button onclick="appendToDisplay('/')" class="operator-btn">/</button>
            <button onclick="appendToDisplay('0')">0</button>
            <button onclick="appendToDisplay('.')">.</button>
            <button onclick="calculate()">=</button>
            <button onclick="clearDisplay()" class="operator-btn">C</button>
        </div>
    </div>

    <script src="index.js"></script>
</body>
</html>

result:

wow so cool!!!!!

and the buttons

okay not so cool…

Made the buttons less gross using Styles.css

styles.css

#keys{
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
    padding: 25px;
}
button{
    width: 100px;
    height: 100px;
    border-radius: 50px;
    border: none;
    background-color: hsl(0, 0%, 30%);
    color: white;
    font-size: 3rem;
    font-weight: bold;
    cursor: pointer;
}

#keys is the id of the buttons. it changes the size and spaces the buttons have. button customizes the buttons to make them look better.

result:

The buttons

Display screen (I just changed the color and made it larger)

Code of the display screen:

#display{
    width: 100%;
    padding: 20px;
    font-size: 5rem;
    text-align: left;
    border: none;
    background-color: hsl(0, 0%, 20%);
}

Made the calculator center in the document.

styles.css

body{
    margin: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: hsl(0, 0%, 90%);

}

before:

after:

the screen is darker b/c i changed the background color.

Added button hovering and clicking indications(?)(and color)

styles.css

body{
    margin: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: hsl(0, 0%, 90%);

}
#calculator{
    font-family: Arial, sans-serif;
    background-color: hsl(0, 0%, 15%);
    border-radius: 15px;
    max-width: 500px;
    overflow: hidden;
}
#display{
    width: 100%;
    padding: 20px;
    font-size: 5rem;
    text-align: left;
    border: none;
    background-color: hsl(0, 0%, 20%);
}
#keys{
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
    padding: 25px;
}
button{
    width: 100px;
    height: 100px;
    border-radius: 50px;
    border: none;
    background-color: hsl(0, 0%, 30%);
    color: white;
    font-size: 3rem;
    font-weight: bold;
    cursor: pointer;
}
button:hover{
    background-color: hsl(0, 0%, 40%);

}
button:active{
    background-color: hsl(0, 0%, 60%);

}
.operator-btn{
    background-color: hsl(198, 83%, 47%);

}
.operator-btn:hover{
    background-color: hsl(198, 83%, 67%);

}
.operator-btn:active{
    background-color: hsl(198, 83%, 87%);

}

button hovering

button clicking

COLORED OPERATOR BUTTONS AYAYAYAYA

I did a miniscule bit of JS, but it’s not an ABSURD amount.

More stuff to racing game

added the ability to move the player’s car left/right using the arrow keys.

if event.type == KEYDOWN:
            
            if event.key == K_LEFT and player.rect.center[0] > left_lane:
                player.rect.x -= 100
            elif event.key == K_RIGHT and player.rect.center[0] < right_lane:
                player.rect.x += 100

result:

left lane

and right lane (also added other cars. i’ll get to that later)

Made the crash image pop up determining where the player crashed into the npc car

# check if there's a side swipe collision after changing lanes
            for vehicle in vehicle_group:
                if pygame.sprite.collide_rect(player, vehicle):
                    
                    gameover = True
                    
                    # place the player's car next to other vehicle
                    # and determine where to position the crash image
                    if event.key == K_LEFT:
                        player.rect.left = vehicle.rect.right
                        crash_rect.center = [player.rect.left, (player.rect.center[1] + vehicle.rect.center[1]) / 2]
                    elif event.key == K_RIGHT:
                        player.rect.right = vehicle.rect.left
                        crash_rect.center = [player.rect.right, (player.rect.center[1] + vehicle.rect.center[1]) / 2]

crashing into the left side of a car

crashing into the right side

and crashing into the car from behind

nice

list for the different car images:

image_filenames = ['pickup_truck.png', 'semi_trailer.png', 'taxi.png', 'van.png']

*FINISH LATER (or when you get home)

ANOTHER racing game

Made the screen green for da grass 🙂

 #draw the grass
    screen.fill(green)

so green

Added a huge gray line on the screen(it’s the road)

#draw the road
    pygame.draw.rect(screen, gray, road)

wow so cool

ANNNND made the edge markers of the road :))

# marker size
marker_width = 10
marker_height = 50

# draw edge markers
    pygame.draw.rect(screen, yellow, left_edge_marker)
    pygame.draw.rect(screen, yellow, right_edge_marker)

RESULT:

Added the lane markers and created the player’s car

line markers

lane_marker_move_y += speed *2
    if lane_marker_move_y >= marker_height * 2:
        lane_marker_move_y = 0
        
    for y in range(marker_height * -2, HEIGHT, marker_height * 2):
        pygame.draw.rect(screen, white, (left_lane + 45, 
        y + lane_marker_move_y, marker_width, marker_height))
        
        pygame.draw.rect(screen, white, (center_lane + 45,
        y + lane_marker_move_y, marker_width, marker_height))

player car (inherits from the Vehicle class)

class PlayerVehicle(Vehicle):
    
    def __init__(self, x, y):
        image = pygame.image.load('images//car.png')
        super().__init__(image, x, y)

vehicle class

class Vehicle(pygame.sprite.Sprite):
    def __init__(self, image, x, y):
        pygame.sprite.Sprite.__init__(self)

        # scale image down to fit in the lane
        image_scale = 45 / image.get_rect().width
        new_width = image.get_rect().width * image_scale
        new_height = image.get_rect().height * image_scale
        self.image = pygame.transform.scale(image, 
        (new_width, new_height))
        
        self.rect = self.image.get_rect()
        self.rect.center = [x, y]
    

RESULT

ok that’s it byeeee

Racing Game not working…

So my main.py file for the racing game just pooped out for no reason and I can’t open it back up without getting an error. The only thing I am able to open is utils.py and the images. That’s it.

So, I copied the code from github and started off from where I think I left off.

Added the images for the game

main.py

GRASS = scale_image(pygame.image.load("imgs/grass.jpg"), 2.5)
TRACK = scale_image(pygame.image.load("imgs/track.png"), 0.9)

TRACK_BORDER = scale_image(pygame.image.load("imgs/track-border.png"), 0.9)

RED_CAR = scale_image(pygame.image.load("imgs/red-car.png"), 0.55)
GREY_CAR = scale_image(pygame.image.load("imgs/grey-car.png"), 0.55)

WIDTH, HEIGHT = TRACK.get_width(), TRACK.get_height()
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Racing Game!")

made a class called AbstractCar to initialize the velocity, angle and acceleration. PlayerCar inherits from this class.

main.py

class AbstractCar:
    def __init__(self, max_vel, rotation_vel):
        self.img = self.IMG
        self.max_vel = max_vel
        self.vel = 0
        self.rotation_vel = rotation_vel
        self.angle = 0
        self.x, self.y = self.START_POS
        self.acceleration = 0.1

    def rotate(self, left=False, right=False):
        if left:
            self.angle += self.rotation_vel
        elif right:
            self.angle -= self.rotation_vel

    def draw(self, win):
        blit_rotate_center(win, self.img, (self.x, self.y), self.angle)

    def move_forward(self):
        self.vel = min(self.vel + self.acceleration, self.max_vel)
        self.move()

    def move(self):
        radians = math.radians(self.angle)
        vertical = math.cos(radians) * self.vel
        horizontal = math.sin(radians) * self.vel

        self.y -= vertical
        self.x -= horizontal

    def reduce_speed(self):
        self.vel = max(self.vel - self.acceleration / 2, 0)
        self.move()

PlayerCar is MUCH shorter and only has the image of the car that we need and the start position of the car.

class PlayerCar(AbstractCar):
    IMG = GREY_CAR
    START_POS = (180, 200)

and a draw function that draws the images, and the player car on the screen.

def draw(win, images, player_car):
    for img, pos in images:
        win.blit(img, pos)

    player_car.draw(win)
    pygame.display.update()

made while loop function that starts and quits the game (when the user clicks the x) and also has the keys to control the player car.

while run:
    clock.tick(FPS)

    draw(WIN, images, player_car)

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

    keys = pygame.key.get_pressed()
    moved = False

    if keys[pygame.K_a]:
        player_car.rotate(left=True)
    if keys[pygame.K_d]:
        player_car.rotate(right=True)
    if keys[pygame.K_w]:
        moved = True
        player_car.move_forward()

    if not moved:
        player_car.reduce_speed()


pygame.quit()

result:

You can move it but these dang computers don’t have screen recording (curse you IT!!!!)

(Kinda) Small Weather App project

main.py

get_weather() gets the weather info from the OpenWeatherApp Api website.

def get_weather(city):
    '''gets weather info from OpenWeatherMap API'''
    API_key = "***********************"
    url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={API_key}"
    res = requests.get(url)
    
    if res.status_code == 404:
        messagebox.showerror("Error", "City not found")
        return None
    
    # Parse response JSON to get weather info
    weather = res.json()
    icon_id = weather['weather'][0]['icon']
    temperature = weather['main']['temp'] - 273.15

it also gets the temperature and icon to make it into readable text.

search() allows the user to search for the current weather of a city.

mian.py

def search():
    '''Searches the current weather of a city'''
    city = city_entry.get()
    result = get_weather(city)
    if result is None:
        return

The rest is the set up for the GUI.

window = ttkbootstrap.Window(themename="morph")
window.title("Weather App")
window.geometry("400x400")

# Entry widget - enter city name
city_entry = ttkbootstrap.Entry(window, font="Helvetica, 18")
city_entry.pack(pady=10)

# Button widget - search for weather information
search_button = ttkbootstrap.Button(window, text="Search", 
command=search, bootstyle="warning")
search_button.pack(pady=10)

# label widget - show country/city name
location_label = tk.Label(window, font="Helvetica, 25")
location_label.pack(pady=20)

# Label widget - show weather icon
icon_label = tk.Label(window)
icon_label.pack()

# Label widget - show the temperature
temperature_label = tk.Label(window, font="Helvetica, 20")
temperature_label.pack()

# Label widget - show weather desc.
desc_label = tk.Label(window, font="Helvetica, 20")
desc_label.pack()

window.mainloop()

That’s really all I did… 1. because I started a little late and 2. it took too long for me to get an account for the API key

March 14 Blog Post: Mario Maker Game

Added the Y tile lines for the game

editor.py

for row in range(rows + 1):
            y = origin_offset.y + row * TILE_SIZE
            pygame.draw.line(self.display_surface, LINE_COLOR, (0,y), (WINDOW_WIDTH,y))

Same as x, but it makes lines horizontal from the left to the right of the window

This is what the it should look like. The y tile lines will be horizontal, and the x tile lines will be vertical.

Result:

Tried to make the lines green so it will look better and…

oh boy…

Okay I took out the green and made the lines a little transparent.

Changing the mouse cursor

Changed the mouse cursor to this:

What we need in order to change the mouse is to find the clickable area, which would be somewhere around the tip of the mouse, the rest is the attached stuff to it.

main.py

surf = load('.//graphics//cursor//mouse.png').convert_alpha()
		cursor = pygame.cursors.Cursor((0,0), surf)
		pygame.mouse.set_cursor(cursor)

We load the image in, then we set where it should be clickable. In this case, it’s (o,0). After that, we replace the mouse with the cursor that we have.

result:

Creating the menu

To make the menu work, in editor.py we’ll have a variable called selection_index that will have value between 2 and 18. Each number represents a certain kind of tile in the editor.

Ex. 2: water, 3; terrain, 4: gold coin and so on.

The selection_index can be changed by clicking on the menu or via hotkeys (this is where that colossal file settings.py comes in).

settings.py

# general setup
TILE_SIZE = 64
WINDOW_WIDTH = 1280
WINDOW_HEIGHT = 720
ANIMATION_SPEED = 8

# editor graphics 
EDITOR_DATA = {
	0: {'style': 'player', 'type': 'object', 'menu': None, 'menu_surf': None, 'preview': None, 'graphics': '../graphics/player/idle_right'},
	1: {'style': 'sky',    'type': 'object', 'menu': None, 'menu_surf': None, 'preview': None, 'graphics': None},
	
	2: {'style': 'terrain', 'type': 'tile', 'menu': 'terrain', 'menu_surf': '../graphics/menu/land.png',  'preview': '../graphics/preview/land.png',  'graphics': None},
	3: {'style': 'water',   'type': 'tile', 'menu': 'terrain', 'menu_surf': '../graphics/menu/water.png', 'preview': '../graphics/preview/water.png', 'graphics': '../graphics/terrain/water/animation'},
	
	4: {'style': 'coin', 'type': 'tile', 'menu': 'coin', 'menu_surf': '../graphics/menu/gold.png',    'preview': '../graphics/preview/gold.png',    'graphics': '../graphics/items/gold'},
	5: {'style': 'coin', 'type': 'tile', 'menu': 'coin', 'menu_surf': '../graphics/menu/silver.png',  'preview': '../graphics/preview/silver.png',  'graphics': '../graphics/items/silver'},
	6: {'style': 'coin', 'type': 'tile', 'menu': 'coin', 'menu_surf': '../graphics/menu/diamond.png', 'preview': '../graphics/preview/diamond.png', 'graphics': '../graphics/items/diamond'},

	7:  {'style': 'enemy', 'type': 'tile', 'menu': 'enemy', 'menu_surf': '../graphics/menu/spikes.png',      'preview': '../graphics/preview/spikes.png',      'graphics': '../graphics/enemies/spikes'},
	8:  {'style': 'enemy', 'type': 'tile', 'menu': 'enemy', 'menu_surf': '../graphics/menu/tooth.png',       'preview': '../graphics/preview/tooth.png',       'graphics': '../graphics/enemies/tooth/idle'},
	9:  {'style': 'enemy', 'type': 'tile', 'menu': 'enemy', 'menu_surf': '../graphics/menu/shell_left.png',  'preview': '../graphics/preview/shell_left.png',  'graphics': '../graphics/enemies/shell_left/idle'},
	10: {'style': 'enemy', 'type': 'tile', 'menu': 'enemy', 'menu_surf': '../graphics/menu/shell_right.png', 'preview': '../graphics/preview/shell_right.png', 'graphics': '../graphics/enemies/shell_right/idle'},
	
	11: {'style': 'palm_fg', 'type': 'object', 'menu': 'palm fg', 'menu_surf': '../graphics/menu/small_fg.png', 'preview': '../graphics/preview/small_fg.png', 'graphics': '../graphics/terrain/palm/small_fg'},
	12: {'style': 'palm_fg', 'type': 'object', 'menu': 'palm fg', 'menu_surf': '../graphics/menu/large_fg.png', 'preview': '../graphics/preview/large_fg.png', 'graphics': '../graphics/terrain/palm/large_fg'},
	13: {'style': 'palm_fg', 'type': 'object', 'menu': 'palm fg', 'menu_surf': '../graphics/menu/left_fg.png',  'preview': '../graphics/preview/left_fg.png',  'graphics': '../graphics/terrain/palm/left_fg'},
	14: {'style': 'palm_fg', 'type': 'object', 'menu': 'palm fg', 'menu_surf': '../graphics/menu/right_fg.png', 'preview': '../graphics/preview/right_fg.png', 'graphics': '../graphics/terrain/palm/right_fg'},

	15: {'style': 'palm_bg', 'type': 'object', 'menu': 'palm bg', 'menu_surf': '../graphics/menu/small_bg.png', 'preview': '../graphics/preview/small_bg.png', 'graphics': '../graphics/terrain/palm/small_bg'},
	16: {'style': 'palm_bg', 'type': 'object', 'menu': 'palm bg', 'menu_surf': '../graphics/menu/large_bg.png', 'preview': '../graphics/preview/large_bg.png', 'graphics': '../graphics/terrain/palm/large_bg'},
	17: {'style': 'palm_bg', 'type': 'object', 'menu': 'palm bg', 'menu_surf': '../graphics/menu/left_bg.png',  'preview': '../graphics/preview/left_bg.png',  'graphics': '../graphics/terrain/palm/left_bg'},
	18: {'style': 'palm_bg', 'type': 'object', 'menu': 'palm bg', 'menu_surf': '../graphics/menu/right_bg.png', 'preview': '../graphics/preview/right_bg.png', 'graphics': '../graphics/terrain/palm/right_bg'},
}

NEIGHBOR_DIRECTIONS = {
	'A': (0,-1),
	'B': (1,-1),
	'C': (1,0),
	'D': (1,1),
	'E': (0,1),
	'F': (-1,1),
	'G': (-1,0),
	'H': (-1,-1)
}

LEVEL_LAYERS = {
	'clouds': 1,
	'ocean': 2,
	'bg': 3,
	'water': 4,
	'main': 5
}

# colors 
SKY_COLOR = '#ddc6a1'
SEA_COLOR = '#92a9ce'
HORIZON_COLOR = '#f5f1de'
HORIZON_TOP_COLOR = '#d1aa9d'
LINE_COLOR = 'black'

what we will need are the indexes 2-18. 0 and 1 are ignored b/c 0 is the player and 1 is the sky. They will also be in the editor so they don’t need to be created.

2-18 the player can create like the terrain, coin, etc…

Making the hotkeys for the menu

editor.py

def selection_hotkeys(self, event):
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:
                self.selection_index += 1
            if event.key == pygame.K_LEFT:
                self.selection_index -= 1

Detects if the user is pressing a button. It’s not checking if we’re holding down a button so there’s no need for a timer.

The problem is that when you repeatedly press the button the number can go below 0 and above 18.

Above 18 when pressing right arrow.

Below 0 when pressing left arrow.

To fix it we just needed one line of code.

editor.py

self.selection_index = max(2,min(self.selection_index,18))

This will cap the max at 18 and the min at 2.

Building the menu

First, we’ll create the general area of the menu.

In the menu area we’ll have smaller squares the user can click on.

menu.py

size = 180
margin = 6

The width and height of the menu will be size. The left and top of the menu will be the WINDOW_WIDTH – size – margin.

Then we draw it on the window.

menu.py

pygame.draw.rect(self.display_surface, 'blue', self.rect)

The menu took a little bit for me b/c there was something wrong with the place of the rectangle. It kept going offscreen (I put a random number for one of the window dimensions instead of its variable).