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.

Data Types In JavaScript

There are six different data types in JavaScript: Strings, integers, floats (decimal numbers), Boolean, null (which is “None” in Python), undefined and Symbol.

Strings

Strings are words (or numbers) that are surrounded by quotation marks (“”).

Here’s an example of one in JavaScript:

const name = "Zende";

As you can see, the word Zende is the string because it has quotes around it.

Output:

*the variable const is used so that we can’t change the value of the variable. if we were to try to change the value of name, we would get an error message say we’re not allowed.

Numbers

Here’s an example of an integer:

const age = 16;

And example of a float:

const temp = 98.6;

BOOLEAN

Here’s an example of a boolean:

const hasKis = true;

This makes the variable true. if we were to type false, it will make it false.

Null

Null, which is the same as “None” in python, happens when a variable doesn’t exist yet.

Here’s an example:

const homeRoom = null;

Undefined

undefined happens when a variable exist, but isn’t defined in the program.

Here’s an example:

const kd = undefined;

Symbol

symbols variables that always have to be unique. They cannot be the same.

Here’s an example:

const id = Symbol('id');
const id2 = Symbol('id');

And those are all the data types.

More stuff to Zelda game 😁

This is a combination of what I did yesterday AND today. This blog post is gonna be big…

Made an offset to the camera!!!

class YSortCameraGroup(pygame.sprite.Group):
    def __init__(self):
        
        # general setup
        super().__init__()
        self.display_surface = pygame.display.get_surface()
        self.half_width = self.display_surface.get_size()[0] // 2
        self.half_height = self.display_surface.get_size()[1] // 2
        self.offset = pygame.math.Vector2()
    
    def custom_draw(self, player):
        
        # getting the offset
        self.offset.x = player.rect.centerx - self.half_width
        self.offset.y = player.rect.centery - self.half_height
        for sprite in self.sprites():
            offset_pos = sprite.rect.topleft - self.offset
            self.display_surface.blit(sprite.image, offset_pos)

The code creates where the camera will be “placed” on the screen. It then puts an offset – what kind of angle or area the camera – will be “placed”.

RESULT:

This only offsets the camera, but doesn’t make the camera move with the player… yet.

Added an overlap for collisions (and also made the camera move with the player).

changes the size of the rectangle (the collision) and makes it smaller or larger. The parameters “x” and “y” are the numbers that will increase or decrease the size of the hitbox.

“x” will be zero and “y” will be a certain number (-26 to be specific)

Also replaced (almost) every rect with hitbox.

Also changed the for loop in YSortCameraGroup class so that we have overlap on ALL rocks.

BEFORE:

for sprite in self.sprites():
	offset_pos = sprite.rect.topleft - self.offset
	self.display_surface.blit(sprite.image, offset_pos)

AFTER:

for sprite in sorted(self.sprites(), 
	key = lambda sprite: sprite.rect.centery):
	offset_pos = sprite.rect.topleft - self.offset
	self.display_surface.blit(sprite.image, offset_pos

RESULT:

Character overlaping behind the rock.

Character overlaping in front of the rock.

NOTE: I will add a short clip of the camera following the player, just not now (can’t screen record if the settings are blocked ˙◠˙).

PUTTING THE FLOOR MAP ON THE SCREEN (and putting the player in the middle of the map)!!!

Created the floor map of the game :

self.floor_surf = pygame.image.load('graphics//tilemap//ground.png')
self.floor_rect = self.floor_surf.get_rect(topleft = (0,0))

And drew the floor map.

floor_offset_pos = self.floor_rect.topleft - self.offset
self.display_surface.blit(self.floor_surf, floor_offset_pos)

Put the player in the middle of the map (idk if the numbers are temporary or not :/)

self.player = Player((2000,1430),
[self.visible_sprites],self.obstacle_sprites)

RESULT:

This was before I added that code to center the player.

ANNND this is after!!! There are no collisions on the plants or anything yet.

Zelda Game Problem :(

By Clear Code

The collision is currently NOT working (she keeps teleporting when you hit left). I’m trying to figure out the issue and it might be something about the vector class. I might try to figure it out at home.

UPDATE: I found out what was the problem:

I changed the “self” in the for loop and if statement to “sprite”. Self was what was making the player character teleport from one side of the screen to the other and then made the character disappear out of nowhere. Also the vector wasn’t the problem. It’s supposed to be there because we’re making a 2D game and it needs that for math or whatever (in depth info is on the pygame website Pygame Math)

Zelda type Game (with some Dark Souls Elements)

Making a python program of a Zelda type game!!!! (tutorial by Clear Code)

‘main.py’

import pygame, sys
from settings import *

class Game:
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
        pygame.display.set_caption('Zelda meets Dark Souls')
        self.clock = pygame.time.Clock()
        
    def run(self):
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
            
            self.screen.fill('black')
            pygame.display.update()
            self.clock.tick(FPS)
            
if __name__ =='__main__':
    game = Game()
    game.run()

This is the main file (as it says in the name) that runs the game. It takes the parameters from both settings.py and debug.py. Basically the brain of the program.

‘settings.py’

WIDTH = 1280
HEIGHT = 720
FPS = 60
TILESIZE = 64

WORLD_MAP = [
['x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'],
['x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', 'p', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x', 'x', 'x', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', ' ', ' ', ' ', ' ', 'x', ' ', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', ' ', ' ', ' ', ' ', 'x', 'x', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x'],
['x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x']]

The settings and world map for the game. These can be changed at any time by just changing the values.

‘debug.py’

import pygame
pygame.init()
font = pygame.font.Font(None, 30)

def debug(info,y = 10, x = 10):
    display_surface = pygame.display.get_surface()
    debug_surf = font.render(str(info), True, 'White')
    debug_rect = debug_surf.get_rect(topleft = (x,y))
    pygame.draw.rect

This is for the window and everything.

Files that were added:

‘level.py’

import pygame
from settings import *
from tile import Tile
from player import Player

class Level:
    def __init(self):
        # Get the display surface
        self.display_surface = pygame.display.get_surface()
        
        '''Sprite group setup'''
        self.visible_sprites = pygame.sprite.Group()
        self.obsracles_sprites = pygame.sprite.Group()

        # sprite setup
        self.create_map()
        
    def create_map(self):
        for row_index,row in enumerate(WORLD_MAP):
            for col_index,col in enumerate(row):
                x = col_index * TILESIZE
                y = row_index * TILESIZE
                if col == 'x':
                    Tile((x,y),[self.visible_sprites])
                    
    
    def run (self):
        '''Update and draw the game'''
        self.visible_sprites.draw(self.display_surface)

Basically the core of this program. Will have all the sprites for the level (player.py and tile.py are important too, but if the levels don’t work, nor will the other files…)

’tile.py’

import pygame
from settings import *

class Tile(pygame.sprite.Sprite):
    def __init__(self, pos, groups):
        super().__init__(groups)
        self.image = pygame.image.load('../graphics/test/rock.png').convert_alpha()
        self.rect = self.image.get_rect(topleft = pos)

Will have all the info for the tiles (the x’s in settings.py) implemented in the game. Levels will display the sprites using ‘visible_sprites’.

‘player.py’

import pygame
from settings import *

class Player(pygame.sprite.Sprite):
    def __init__(self, pos, groups):
        super().__init__(groups)
        self.image = pygame.image.load('../graphics/test/player.png').convert_alpha()
        self.rect = self.image.get_rect(topleft = pos)

Same as tile.py, but with the player character. Level.py will also display the sprites there.

Result:

*Still a WIP

What is Threading?

Threading allows to make multiple threads of execution to take place in a Python program. Though threads appear to run simultaneously, only one can be executed at a time (enforced by Python’s global interpreter lock). Threading is a helpful module when working with tasks that are I/O bound (including web-oriented tasks like web scraping or downloading files).

Here’s an example of Threading:

import threading
import time


def eat_breakfast():
    time.sleep(3)
    print("You eat breakfast")


def drink_coffee():
    time.sleep(4)
    print("You drank coffee")


def study():
    time.sleep(5)
    print("You finish studying")


x = threading.Thread(target=eat_breakfast, args=())
x.start()

y = threading.Thread(target=drink_coffee, args=())
y.start()

z = threading.Thread(target=study, args=())
z.start()

x.join()
y.join()
z.join()

print(threading.active_count())
print(threading.enumerate())
print(time.perf_counter())

The method active_count() returns the number of thread objects that are currently there. The returned number is equal to the length of the list returned by the method ennumerate().

Sources: Threading – Python Python Multithreading