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 ;-;.
Tag: #coding
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.
(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).
March 13 Blog Post: Mario Maker Game
Made the scroll wheel move the origin up, down, left and right
editor.py
if event.type == pygame.MOUSEWHEEL:
if pygame.key.get_pressed()[pygame.K_LCTRL]:
self.origin.y -= event.y * 50
else:
self.origin.x -= event.y * 50
Allows the origin to move or right WITHOUT holding down left CTRL and up or down when holding down left CTRL.
Without holding down left CTRL:
Holding down left CTRL:
That’s really it for the pan input. Nothing extremely complex. Later on we’ll have to add more stuff, but for now this is good.
Drawing the tile lines to find what location we are in the grid
Making the tile lines should be infinite and relative to the origin point.
All of the lines should start at the position 0 (start of the window) and end at the height (the bottom) of the window. The x position for the top and bottom of the line should be the same.
Very rough sketch of what I’m trying to explain:

We would find this out by this code:
editor.py
for col in range(cols):
x = self.origin.x + col * TILE_SIZE
pygame.draw.line(self.display_surface, LINE_COLOR, (x,0), (x,WINDOW_HEIGHT))
Let’s say that the position of the origin point is (0,0). We would be getting that from self.origin.x. x = 0. We then add that to the column (which is 0) and then multiply by the TILE_SIZE (which will always be 64). The answer to that equation will be 0, which will be the line at the left side of the window.

if col is 1 and we multiply that by 64, we’ll get 64, which will move from the first point to the point to the right and so on until we reach the end of the columns.
If we run it, this is our result:

When you move the origin point the lines will move with it.
There’s a problem though. We run out of points when we move and there’s just a giant empty white space. The same thing happens when you move the origin point to the left.
What we have to do is make sure that the lines are always on the display and that we’re never running out of lines.
We will have to create columns between the origin’s position and the next column so that we can move the origin wherever we want (and so they don’t go out the window).
To do this, we have to divide origin_offset with the TILE_SIZE. Let’s say it is 100. We divide that by the TILE_SIZE (64) and then multiply that number by the TILE_SIZE, which would be 1, which means we’re in the 1st column. Same thing for y.
editor.py
origin_offset = vector(
offset_vector.x - int(self.origin.x / TILE_SIZE)* TILE_SIZE,
y = self.origin.y - int(self.origin.y / TILE_SIZE)* TILE_SIZE)
Result:
That’s all I did. Keep in mind that this tutorial is over 10 hours long…
March 12 Blog Post: Mario Maker Game
Created the origin to follow the mouse by holding the middle mouse button.
editor.py
import pygame, sys
from settings import *
from pygame.math import Vector2 as vector
from pygame.mouse import get_pressed as mouse_buttons
from pygame.mouse import get_pos as mouse_pos
class Editor:
def __init__(self):
# main setup
self.display_surface = pygame.display.get_surface()
# navigation
self.origin = vector()
self.pan_active = False
def event_loop(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
self.pan_input(event)
----------------------------------------- look between these
def pan_input(self, event):
'''checks if middle button is pressed'''
if event.type == pygame.MOUSEBUTTONDOWN and mouse_buttons()[1]:
self.pan_active = True
if not mouse_buttons()[1]:
self.pan_active = False
#panning update
if self.pan_active:
self.origin = mouse_pos()
------------------------------------- look between these
def run(self, dt):
self.display_surface.fill('white')
self.event_loop()
pygame.draw.circle(self.display_surface, 'blue', self.origin, 10)
The code between the dotted lines is what makes the origin move by holding down the mouse button.
Result:

Origin in the middle.

Origin on the left.

And the origin on the right.
There is a slight problem with this. The origin follows where the mouse’s position is. For example. If the mouse is at the bottom right-hand corner of the screen and the origin is on the top left-hand corner of the screen and the user presses the middle mouse button, the origin will go from its original position to the mouse’s position.

If we keep this, it will get pretty confusing later when we progress making the game, especially having different tiles and objects all around the screen.
The BETTER way to move the origin.
editor.py
def pan_input(self, event):
'''checks if middle button is pressed'''
if event.type == pygame.MOUSEBUTTONDOWN and mouse_buttons()[1]:
self.pan_active = True
self.pan_offset = vector(mouse_pos()) - self.origin
if not mouse_buttons()[1]:
self.pan_active = False
#panning update
if self.pan_active:
self.origin = vector(mouse_pos()) - self.pan_offset
The bolded lines of code helps with making it better to move the origin.
What you get from the first bolded line of code is the distance between the origin and the mouse position.
To use it you subtract the mouse_pos() with the pan_offset to get the distance IF the pan_active is true.

The teal x is the origin. The yellow one is the mouse. vector(mouse_pos()) – self.origin calculates the distance (in pink) between the mouse_pos() and the origin.
self.origin = vector(mouse_pos()) – self.pan_offset creates an offset of the pan when holding down the middle mouse button. This will move the origin point WITHOUT moving the origin point with the mouse (aka. clicking on it).
Result:

When moving the mouse, the origin will move with it, but not follow its exact position.
Ignore my chicken scratch. It’s hard writing with a right-handed mouse when you’re left-handed :/
March 11th Blog Post: Mario Maker type game
Created a main, settings, and editor file.
main.py
import pygame
from settings import *
from editor import Editor
class Main:
def __init__(self):
pygame.init()
self.display_surface = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
self.clock = pygame.time.Clock()
self.editor = Editor()
def run(self):
while True:
dt = self.clock.tick() / 1000
self.editor.run(dt)
pygame.display.update()
if __name__ == '__main__':
main = Main()
main.run()
The code that runs the whole program. Is tied to settings.py and editor.py.
settings.py
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'
A HUGE amount of code that contains all the images and info for the program…
editor.py
import pygame, sys
from settings import *
from pygame.math import Vector2 as vector
from pygame.mouse import get_pressed as mouse_buttons
class Editor:
def __init__(self):
# main setup
self.display_surface = pygame.display.get_surface()
# navigation
self.origin = vector()
self.pan_active = False
def event_loop(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
self.pan_input(event)
def pan_input(self, event):
'''checks if middle button is pressed'''
if event.type == pygame.MOUSEBUTTONDOWN and mouse_buttons()[1]:
self.pan_active = True
print('middle mouse button')
def run(self, dt):
self.display_surface.fill('white')
self.event_loop()
pygame.draw.circle(self.display_surface, 'blue', self.origin, 10)
Has all the info to edit the program. Will get HUGE from adding more stuff to it.
There’s not a lot to it because I kept putting my files in the wrong folders (I did it THREE TIMES and was STRESSING where they were) and didn’t want to redo the excessive work I put in… (when I have more energy I swear I’ll add more).
March 8th Blog Post: Zelda Game
World Boundary
Added a world boundary on the map so that the player can’t walk out of it.
layouts = {
'boundary': import_csv_layout('map//map_FloorBlocks.csv'), << Looking at this
'grass': import_csv_layout('map//map_Grass.csv'),
'object': import_csv_layout('map//map_Objects.csv')
This the csv directory of where the floor blocks (the barrier) of the world map. I made a function in another file (support.py) that has all the stuff to make it work.
support.py
def import_csv_layout(path):
terrain_map = []
with open(path) as level_map:
layout = reader(level_map, delimiter = ',')
for row in layout:
terrain_map.append(list(row))
return terrain_map
This code reads the csv file, then in level.py it draws it on the map and places the blocks around the edge of it.

world barrier shown.

world barrier hidden ( I just took off self.visible_sprites).
Grass
Added plants and collision on them!!!!
layouts = {
'boundary': import_csv_layout('map//map_FloorBlocks.csv'),
This one >>'grass': import_csv_layout('map//map_Grass.csv'),
'object': import_csv_layout('map//map_Objects.csv')
same thing as boundary, but has a graphics directory AND a csv (as does object).
graphics = {
'grass': import_folder('graphics//grass'),
'objects': import_folder('graphics//object')
made an import_folder() function that kinda does the same thing but loads the images and appends them to a list.
def import_folder(path):
surface_list = []
for _,__,img_files in walk(path):
for image in img_files:
full_path = path + '/' + image
image_surf = pygame.image.load(full_path).convert_alpha()
surface_list.append(image_surf)
also added them to an if statement so that it puts them in their correct places (kinda.)
if style == 'grass':
random_grass_image = choice(graphics['grass'])
Tile((x,y),[self.visible_sprites,
self.obstacle_sprites],'grass', random_grass_image)
RESULT:

no grass

yes grass (and collisions!!!!)
Currently working on the larger objects right now :))))
Additions to Aim Trainer game
Added a collide function to be able to click the targets
def collide(self, x, y):
'''creates the collisions with the mouse and the circle'''
dis = math.sqrt((x - self.x)**2 + (y - self.y)**2)
return dis <= self.size
Added ANOTHER draw function that updates the screen every frame so that the program doesn’t slow down
def draw(win, targets):
'''wipes the screen, draws the objects, and updates the display'''
win.fill(BG_COLOR)
for target in targets:
target.draw(win)
pygame.display.update()
additional code for collide in main
if event.type == TARGET_EVENT:
x = random.randint(TARGET_PADDING, WIDTH - TARGET_PADDING)
y = random.randint(TARGET_PADDING, HEIGHT - TARGET_PADDING)
target = Target(x, y)
targets.append(target)
if event.type == pygame.MOUSEBUTTONDOWN:
click = True
clicks += 1
for target in targets:
target.update()
if target.size <= 0:
targets.remove(target)
misses += 1
if click and target.collide(*mouse_pos):
targets.remove(target)
target_pressed += 1
if misses >= LIVES:
pass # end game
Aim Trainer game
I’m taking a small break with the Zelda game for now because it’s making me a little burnt out and it’s becoming slightly repetitive so I decided to start something new. I will go back to it though.
the ‘Target” class:
class Target:
MAX_SIZE = 30
GROWTH_RATE = 0.2
COLOR = "red"
SECOND_COLOR = "white"
def __init__(self, x, y):
self.x = x
self.y = y
self.size = 0
self.grow = True
def update(self):
'''Udpates the target's size when it grows or shrinks'''
if self.size + self.GROWTH_RATE >=self.MAX_SIZE:
self.grow = False
if self.grow:
self.size += self.GROWTH_RATE
else:
self.size -= self.GROWTH_RATE
def draw(self, win):
'''draws a circle on the screen'''
pygame.draw.circle(win, self.COLOR, (self.x, self.y), self.size)
pygame.draw.circle(win, self.SECOND_COLOR, (self.x, self.y), self.size * 0.8)
pygame.draw.circle(win, self.COLOR, (self.x, self.y), self.size * 0.6)
pygame.draw.circle(win, self.SECOND_COLOR, (self.x, self.y), self.size * 0.4)
This creates the target. The target will and stop at a certain size and then shrink down to zero.
The update() function updates the size when the target grows and shrinks.
the draw() function creates the circles for the target. There are four circles because if we drew one it would just be on big circle growing and shrinking on the screen.
The “Main” loop
# Main Loop
def main():
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
break
pygame.quit()
This is the main loop of the program. All it does right now is that it allows you to quit the program.
You’re probably wondering why there isn’t much to this. The reason is 1. It’s career day so that made me loose time and 2. I wanted to make a post of the simple stuff I had for now before I added anything that would be long and tedious.