diff --git a/.gitignore b/.gitignore index 1930ca0..26750c3 100644 --- a/.gitignore +++ b/.gitignore @@ -956,3 +956,4 @@ FodyWeavers.xsd # Additional files built by Visual Studio # End of https://www.toptal.com/developers/gitignore/api/vim,node,data,emacs,python,pycharm,executable,sublimetext,visualstudio,visualstudiocode +.null-ls_574349_tetris.py diff --git a/aforest.py b/aforest.py new file mode 100644 index 0000000..47db5fe --- /dev/null +++ b/aforest.py @@ -0,0 +1,108 @@ +import math + +import noise +import pygame + +# set up pygame +pygame.init() + +# set up the window +screen_width, screen_height = 1280, 800 +screen = pygame.display.set_mode((screen_width, screen_height)) +# set up the noise surface +noise_width, noise_height = 1280, 800 +noise_scale = 10 +noise_width = int(screen_width / noise_scale) +noise_height = int(screen_height / noise_scale) +# noise_width, noise_height = round(1280 / 10), round(800 / 10) +noise_surface = pygame.Surface((noise_width, noise_height)) +# set up the colors +BLACK = (0, 0, 0) +GREEN = (0, 255, 0) +BLUE = (0, 0, 255) +colors = [(0, 128, 0), (0, 64, 0), (0, 32, 0)] +# set up the noise +octaves = 1 +freq = 256 * octaves +# generate the noise +noise_map = [ + [ + noise.pnoise2(x / freq, y / freq, octaves, repeatx=3024, repeaty=3024) + for x in range(screen_width) + ] + for y in range(screen_height) +] +# set up the clock +clock = pygame.time.Clock() +# set up the animation +frame = 0 +# set up the noise surface cache +noise_surface_cache = [] +# set up the noise surface cache index +noise_surface_cache_index = 0 +# set up the noise surface cache size +noise_surface_cache_size = 120 +# set up the noise surface cache +for i in range(noise_surface_cache_size): + + print(f"caching {i} of {noise_surface_cache_size}") + # draw the background + for y in range(noise_height): + for x in range(noise_width): + color = colors[2] + if ( + noise_map[y * noise_scale][x * noise_scale] + + math.sin(i * (3.14 / noise_surface_cache_size)) + > 0.2 + ): + color = colors[1] + elif ( + noise_map[y * noise_scale][x * noise_scale] + + math.sin(i * (3.14 / noise_surface_cache_size)) + < 0.15 + ): + color = colors[0] + noise_surface.set_at((x, y), color) + # cache the noise surface + + noise_surface_scaled = pygame.transform.scale( + noise_surface, (screen_width, screen_height) + ) + # noise_surface_scaled_pil = Image.frombytes( + # "RGB", + # (screen_width, screen_height), + # pygame.image.tostring(noise_surface_scaled, "RGB", False), + # ) + + # noise_surface_scaled_pil = noise_surface_scaled_pil.filter( + # ImageFilter.GaussianBlur(radius=20) + # ) + # noise_surface_scaled = pygame.image.fromstring( + # noise_surface_scaled_pil.tobytes(), (screen_width, screen_height), "RGB" + # ) + noise_surface_cache.append(noise_surface_scaled) + +noise_surface_cache.extend([n for n in noise_surface_cache[::-1]]) +# main loop +running = True +print("running") +while running: + # keep loop running at the right speed + clock.tick(60) + # process events + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + # increment the frame + frame += 0.2 + if frame > noise_surface_cache_size - 1: + frame = 0 + # draw the noise surface onto the screen + screen.blit(noise_surface_cache[int(frame)], (0, 0)) + + # display the fps on the screen + pygame.display.set_caption(str(clock.get_fps())) + # update the display + pygame.display.flip() + +pygame.quit() diff --git a/camera.py b/camera.py new file mode 100644 index 0000000..807f8e7 --- /dev/null +++ b/camera.py @@ -0,0 +1,180 @@ +"""Basic showcase on how the transform property on SpaceDebugDrawOptions can +be used as a camera to allow panning. Use arrows to move the camera. +""" + +__docformat__ = "reStructuredText" + +import random +import sys + +import pygame +import pymunk.pygame_util +from pymunk.vec2d import Vec2d + +random.seed(0) + + +def main(): + pygame.init() + screen = pygame.display.set_mode((600, 600)) + clock = pygame.time.Clock() + running = True + font = pygame.font.Font(None, 16) + text = font.render( + "Use Arrows (up, down, left, right) to move the camera, " + "a and z to zoom in / out and s and x to rotate.", + True, + pygame.Color("black"), + ) + + ### Physics stuff + space = pymunk.Space() + space.gravity = Vec2d(0.0, 900.0) + draw_options = pymunk.pygame_util.DrawOptions(screen) + + ## Balls + balls = [] + + body = pymunk.Body() + body.position = pymunk.Vec2d(407, 354) + s1 = pymunk.Segment(body, Vec2d(-300, -30), Vec2d(0, 0), 1.0) + s2 = pymunk.Segment(body, Vec2d(0, 0), Vec2d(0, -100), 1.0) + s1.density = 0.1 + s2.density = 0.1 + s1.friction = 1 + s2.friction = 1 + space.add(body, s1, s2) + + c1 = pymunk.constraints.DampedSpring( + space.static_body, + body, + (427, 200), + (0, -100), + Vec2d(407, 254).get_distance((427, 200)), + 2000, + 100, + ) + + c2 = pymunk.constraints.DampedSpring( + space.static_body, + body, + (87, 200), + (-300, -30), + Vec2d(107, 324).get_distance((87, 200)), + 2000, + 100, + ) + space.add(c1, c2) + + # extra to show how constraints are drawn when very small / large + body = pymunk.Body(1, 100) + body.position = 450, 305 + c3 = pymunk.constraints.DampedSpring( + space.static_body, body, (450, 300), (0, 0), 5, 1000, 100 + ) + space.add(body, c3) + body = pymunk.Body(1, 100) + body.position = 500, 2025 + c3 = pymunk.constraints.DampedSpring( + space.static_body, body, (500, 25), (0, 0), 2000, 1000, 100 + ) + space.add(body, c3) + + ticks_to_next_ball = 10 + + translation = pymunk.Transform() + scaling = 1 + rotation = 0 + + while running: + for event in pygame.event.get(): + if ( + event.type == pygame.QUIT + or event.type == pygame.KEYDOWN + and event.key == pygame.K_ESCAPE + ): + running = False + elif event.type == pygame.KEYDOWN and event.key == pygame.K_p: + pygame.image.save(screen, "camera.png") + + keys = pygame.key.get_pressed() + left = int(keys[pygame.K_LEFT]) + up = int(keys[pygame.K_UP]) + down = int(keys[pygame.K_DOWN]) + right = int(keys[pygame.K_RIGHT]) + + zoom_in = int(keys[pygame.K_a]) + zoom_out = int(keys[pygame.K_z]) + rotate_left = int(keys[pygame.K_s]) + rotate_right = int(keys[pygame.K_x]) + + translate_speed = 10 + translation = translation.translated( + translate_speed * left - translate_speed * right, + translate_speed * up - translate_speed * down, + ) + + zoom_speed = 0.1 + scaling *= 1 + (zoom_speed * zoom_in - zoom_speed * zoom_out) + + rotation_speed = 0.1 + rotation += rotation_speed * rotate_left - rotation_speed * rotate_right + + # to zoom with center of screen as origin we need to offset with + # center of screen, scale, and then offset back + draw_options.transform = ( + pymunk.Transform.translation(300, 300) + @ pymunk.Transform.scaling(scaling) + @ translation + @ pymunk.Transform.rotation(rotation) + @ pymunk.Transform.translation(-300, -300) + ) + + ticks_to_next_ball -= 1 + if ticks_to_next_ball <= 0: + ticks_to_next_ball = 100 + mass = 10 + radius = 25 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0, 0)) + body = pymunk.Body(mass, inertia) + x = random.randint(115, 350) + body.position = x, 100 + if random.random() > 0.5: + shape = pymunk.Circle(body, radius) + else: + shape = pymunk.Poly.create_box( + body, size=(radius * 2, radius * 2), radius=2 + ) + shape.friction = 1 + space.add(body, shape) + balls.append(shape) + + ### Clear screen + screen.fill(pygame.Color("white")) + + ### Draw stuff + space.debug_draw(draw_options) + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y > 500: + balls_to_remove.append(ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + screen.blit(text, (5, 5)) + + ### Update physics + dt = 1.0 / 60.0 + space.step(dt) + + ### Flip screen + pygame.display.flip() + clock.tick(50) + pygame.display.set_caption("fps: " + str(clock.get_fps())) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/constraints.py b/constraints.py new file mode 100644 index 0000000..a9d518d --- /dev/null +++ b/constraints.py @@ -0,0 +1,250 @@ +""" +Pymunk constraints demo. Showcase of all the constraints included in Pymunk. + +Adapted from the Chipmunk Joints demo: +https://github.com/slembcke/Chipmunk2D/blob/master/demo/Joints.c +""" + +import inspect +import math + +import pygame +import pymunk.pygame_util +from pymunk.vec2d import Vec2d + +pygame.init() +screen = pygame.display.set_mode((1200, 600)) +clock = pygame.time.Clock() +font = pygame.font.Font(None, 24) + + +help_txt = font.render( + "Pymunk constraints demo. Use mouse to drag/drop. Hover to see descr.", + True, + pygame.Color("darkgray"), +) + +space = pymunk.Space() +space.gravity = (0.0, 900.0) +draw_options = pymunk.pygame_util.DrawOptions(screen) + +# containers +box_size = 200 +w = screen.get_width() +h = screen.get_height() +for i in range(6): + sw = pymunk.Segment(space.static_body, (0, i * box_size), (w, i * box_size), 1) + sw.friction = 1 + sw.elasticity = 1 + sh = pymunk.Segment( + space.static_body, (i * box_size, 0), (i * box_size, h - box_size), 1 + ) + sh.friction = 1 + sh.elasticity = 1 + space.add(sw, sh) + + +def add_ball(space, pos, box_offset): + body = pymunk.Body() + body.position = Vec2d(*pos) + box_offset + shape = pymunk.Circle(body, 20) + shape.mass = 1 + shape.friction = 0.7 + space.add(body, shape) + return body + + +def add_bar(space, pos, box_offset): + body = pymunk.Body() + body.position = Vec2d(*pos) + box_offset + shape = pymunk.Segment(body, (0, 40), (0, -40), 6) + shape.mass = 2 + shape.friction = 0.7 + space.add(body, shape) + return body + + +def add_lever(space, pos, box_offset): + body = pymunk.Body() + body.position = pos + Vec2d(*box_offset) + (0, -20) + shape = pymunk.Segment(body, (0, 20), (0, -20), 5) + shape.mass = 1 + shape.friction = 0.7 + space.add(body, shape) + return body + + +def main(): + txts = {} + + box_offset = 0, 0 + b1 = add_ball(space, (50, 60), box_offset) + b2 = add_ball(space, (150, 60), box_offset) + c: pymunk.Constraint = pymunk.PinJoint(b1, b2, (20, 0), (-20, 0)) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size, 0 + b1 = add_ball(space, (50, 60), box_offset) + b2 = add_ball(space, (150, 60), box_offset) + c = pymunk.SlideJoint(b1, b2, (20, 0), (-20, 0), 40, 80) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size * 2, 0 + b1 = add_ball(space, (50, 60), box_offset) + b2 = add_ball(space, (150, 60), box_offset) + c = pymunk.PivotJoint(b1, b2, Vec2d(*box_offset) + (100, 60)) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size * 3, 0 + b1 = add_ball(space, (50, 60), box_offset) + b2 = add_ball(space, (150, 60), box_offset) + c = pymunk.GrooveJoint(b1, b2, (50, 50), (50, -50), (-50, 0)) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size * 4, 0 + b1 = add_ball(space, (50, 60), box_offset) + b2 = add_ball(space, (150, 60), box_offset) + c = pymunk.DampedSpring(b1, b2, (30, 0), (-30, 0), 20, 5, 0.3) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size * 5, 0 + b1 = add_bar(space, (50, 80), box_offset) + b2 = add_bar(space, (150, 80), box_offset) + # Add some joints to hold the circles in place. + space.add(pymunk.PivotJoint(b1, space.static_body, (50, 80) + Vec2d(*box_offset))) + space.add(pymunk.PivotJoint(b2, space.static_body, (150, 80) + Vec2d(*box_offset))) + c = pymunk.DampedRotarySpring(b1, b2, 0, 3000, 60) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = 0, box_size + b1 = add_lever(space, (50, 100), box_offset) + b2 = add_lever(space, (150, 100), box_offset) + # Add some joints to hold the circles in place. + space.add(pymunk.PivotJoint(b1, space.static_body, (50, 100) + Vec2d(*box_offset))) + space.add(pymunk.PivotJoint(b2, space.static_body, (150, 100) + Vec2d(*box_offset))) + # Hold their rotation within 90 degrees of each other. + c = pymunk.RotaryLimitJoint(b1, b2, math.pi / 2, math.pi / 2) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size, box_size + b1 = add_lever(space, (50, 100), box_offset) + b2 = add_lever(space, (150, 100), box_offset) + # Add some pin joints to hold the circles in place. + space.add(pymunk.PivotJoint(b1, space.static_body, (50, 100) + Vec2d(*box_offset))) + space.add(pymunk.PivotJoint(b2, space.static_body, (150, 100) + Vec2d(*box_offset))) + # Ratchet every 90 degrees + c = pymunk.RatchetJoint(b1, b2, 0, math.pi / 2) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size * 2, box_size + b1 = add_bar(space, (50, 100), box_offset) + b2 = add_bar(space, (150, 100), box_offset) + # Add some pin joints to hold the circles in place. + space.add(pymunk.PivotJoint(b1, space.static_body, (50, 100) + Vec2d(*box_offset))) + space.add(pymunk.PivotJoint(b2, space.static_body, (150, 100) + Vec2d(*box_offset))) + # Force one to sping 2x as fast as the other + c = pymunk.GearJoint(b1, b2, 0, 2) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size * 3, box_size + b1 = add_bar(space, (50, 100), box_offset) + b2 = add_bar(space, (150, 100), box_offset) + # Add some pin joints to hold the circles in place. + space.add(pymunk.PivotJoint(b1, space.static_body, (50, 100) + Vec2d(*box_offset))) + space.add(pymunk.PivotJoint(b2, space.static_body, (150, 100) + Vec2d(*box_offset))) + # Make them spin at 1/2 revolution per second in relation to each other. + c = pymunk.SimpleMotor(b1, b2, math.pi) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + # TODO add one or two advanced constraints examples, such as a car or rope + + mouse_joint = None + mouse_body = pymunk.Body(body_type=pymunk.Body.KINEMATIC) + + # Build rendered help texts + box_texts = {} + for k in txts: + l = 0 + box_texts[k] = [] + # Only take the first 5 lines. + for line in txts[k].splitlines()[:5]: + txt = font.render(line, True, pygame.Color("black")) + box_texts[k].append(txt) + + while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + exit() + elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: + exit() + elif event.type == pygame.MOUSEBUTTONDOWN: + if mouse_joint is not None: + space.remove(mouse_joint) + mouse_joint = None + + p = Vec2d(*event.pos) + hit = space.point_query_nearest(p, 5, pymunk.ShapeFilter()) + if hit is not None and hit.shape.body.body_type == pymunk.Body.DYNAMIC: + shape = hit.shape + # Use the closest point on the surface if the click is outside + # of the shape. + if hit.distance > 0: + nearest = hit.point + else: + nearest = p + mouse_joint = pymunk.PivotJoint( + mouse_body, + shape.body, + (0, 0), + shape.body.world_to_local(nearest), + ) + mouse_joint.max_force = 50000 + mouse_joint.error_bias = (1 - 0.15) ** 60 + space.add(mouse_joint) + + elif event.type == pygame.MOUSEBUTTONUP: + if mouse_joint is not None: + space.remove(mouse_joint) + mouse_joint = None + + screen.fill(pygame.Color("white")) + + screen.blit(help_txt, (5, screen.get_height() - 20)) + + mouse_pos = pygame.mouse.get_pos() + + # Display help message + x = mouse_pos[0] // box_size * box_size + y = mouse_pos[1] // box_size * box_size + + if (x, y) in box_texts: + txts = box_texts[(x, y)] + i = 0 + for txt in txts: + pos = (5, box_size * 2 + 10 + i * 20) + screen.blit(txt, pos) + i += 1 + + mouse_body.position = mouse_pos + + space.step(1.0 / 60) + + space.debug_draw(draw_options) + pygame.display.flip() + + clock.tick(60) + pygame.display.set_caption(f"fps: {clock.get_fps()}") + + +if __name__ == "__main__": + main() diff --git a/creeper_adventure/assets/bee/idle/1.png b/creeper_adventure/assets/bee/idle/1.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/creeper/idle/1.png b/creeper_adventure/assets/creeper/idle/1.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/creeper/idle/2.png b/creeper_adventure/assets/creeper/idle/2.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/creeper/idle/3.png b/creeper_adventure/assets/creeper/idle/3.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/creeper/idle/4.png b/creeper_adventure/assets/creeper/idle/4.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/creeper/idle/5.png b/creeper_adventure/assets/creeper/idle/5.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/leaf.png b/creeper_adventure/assets/leaf.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/oak_trees/1.png b/creeper_adventure/assets/oak_trees/1.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/oak_trees/2.png b/creeper_adventure/assets/oak_trees/2.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/oak_trees/4.png b/creeper_adventure/assets/oak_trees/4.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/oak_trees/5.png b/creeper_adventure/assets/oak_trees/5.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/spotlight.png b/creeper_adventure/assets/spotlight.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/creeper.py b/creeper_adventure/creeper.py old mode 100755 new mode 100644 index 8cb48a8..f9eccd1 --- a/creeper_adventure/creeper.py +++ b/creeper_adventure/creeper.py @@ -1,10 +1,12 @@ -import random from copy import copy from itertools import cycle, repeat from pathlib import Path +import random +from typing import List, Optional -import pygame from more_itertools import flatten +from pydantic import BaseModel +import pygame from creeper_adventure.game import Game @@ -348,7 +350,6 @@ class MainMenu(Menu): h = 50 x = self.game.screen.get_size()[0] / 2 - w / 2 y = 300 - print(self.game.frames) return Button(self.game, self.surf, self.button_text, x, y, w, h, self.toggle) def set_button_text(self): diff --git a/creeper_adventure/game.py b/creeper_adventure/game.py old mode 100755 new mode 100644 diff --git a/forest.py b/forest.py new file mode 100644 index 0000000..3a67d9c --- /dev/null +++ b/forest.py @@ -0,0 +1,63 @@ +import math + +from noise import pnoise2 +import pygame + +# Initialize pygame +pygame.init() + +base = 0 +persistence = 0.4 +lacunarity = 2.0 +more_x = 0 +# Set up the drawing window +screen = pygame.display.set_mode([800, 600]) + + +def S(): + i = 0 + while True: + i += 0.1 + yield math.sin(i) + + +s = S() + +# Run until the user asks to quit +running = True +while running: + + # Did the user click the window close button? + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + # Fill the background with white + screen.fill((255, 255, 255)) + + m = next(s) + # Generate Perlin noise + for x in range(800): + for y in range(600): + noise = pnoise2( + x / 10, + y / 10, + octaves=4, + persistence=persistence + m / 10, + lacunarity=lacunarity, + repeatx=1024, + repeaty=1024, + base=base, + ) + if noise > 0.2: + pygame.draw.rect(screen, (0, 255, 0), (x, y, 1, 1)) + elif noise > 0: + pygame.draw.rect(screen, (0, 128, 0), (x, y, 1, 1)) + else: + pygame.draw.rect(screen, (0, 64, 0), (x, y, 1, 1)) + + # Flip the display + pygame.display.flip() + +# Done! Time to quit. +pygame.quit() diff --git a/gpt-menu.py b/gpt-menu.py new file mode 100644 index 0000000..12c26fe --- /dev/null +++ b/gpt-menu.py @@ -0,0 +1,85 @@ +import pygame + +# Initialize Pygame +pygame.init() + +EVENTS = [] +# Set screen size +screen = pygame.display.set_mode((800, 600)) + +# Set title +pygame.display.set_caption("My RPG Game") + +# Load font +font = pygame.font.Font(None, 30) + +# Define button class +class Button: + def __init__(self, text, x, y, w, h, on_click=lambda: ...): + self.text = text + self.x = x + self.y = y + self.w = w + self.h = h + self.on_click = on_click + + def draw(self, surface): + pygame.draw.rect(surface, (255, 255, 255), (self.x, self.y, self.w, self.h)) + label = font.render(self.text, True, (0, 0, 0)) + label_rect = label.get_rect() + label_rect.center = (self.x + self.w / 2, self.y + self.h / 2) + surface.blit(label, label_rect) + for event in EVENTS: + if event.type == pygame.MOUSEBUTTONDOWN: + if self.is_clicked(event.pos): + self.on_click() + # elif quit_button.is_clicked(event.pos): + # running = False + # if self.is_clicked: + # self.on_click() + + def is_clicked(self, pos): + if pos[0] > self.x and pos[0] < self.x + self.w: + if pos[1] > self.y and pos[1] < self.y + self.h: + return True + return False + + +# Create buttons +start_button = Button( + "Start Game", 300, 300, 200, 50, lambda: print("start this thing") +) +running = True + + +def stop(): + global running + running = False + + +quit_button = Button("Quit Game", 300, 400, 200, 50, stop) + +# Main loop +while running: + EVENTS = pygame.event.get() + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + # Check for button clicks + + # Draw background + screen.fill((0, 0, 0)) + + # Draw title + title = font.render("Creeper Adventure", True, (255, 255, 255)) + screen.blit(title, (250, 200)) + + # Draw buttons + start_button.draw(screen) + quit_button.draw(screen) + + pygame.display.update() + +# Quit Pygame +pygame.quit() diff --git a/gradients.py b/gradients.py new file mode 100644 index 0000000..4834b3b --- /dev/null +++ b/gradients.py @@ -0,0 +1,42 @@ +from noise import pnoise2 +import pygame +import random + +# Initialize pygame +pygame.init() + +# Set the size of the window +width, height = 800, 600 +screen = pygame.display.set_mode((width, height)) + +# Create a list of 3 random blues +blues = [] +for i in range(3): + blues.append( + (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) + ) + +# Create a perlin noise surface +noise_surface = pygame.Surface((width, height)) +for x in range(width): + for y in range(height): + # Calculate the perlin noise value + noise_value = pnoise2(x / 100, y / 100) + # Map the noise value to a color + color_index = int(noise_value * (len(blues) - 1)) + color = blues[color_index] + # Set the color of the pixel + noise_surface.set_at((x, y), color) + +# Blit the noise surface to the screen +screen.blit(noise_surface, (0, 0)) + +# Update the display +pygame.display.flip() + +# Keep the window open until it is closed +while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + exit() diff --git a/grass.png b/grass.png new file mode 100644 index 0000000..894be7d Binary files /dev/null and b/grass.png differ diff --git a/iso.py b/iso.py new file mode 100644 index 0000000..6923180 --- /dev/null +++ b/iso.py @@ -0,0 +1,56 @@ +import sys + +import pygame +from pygame.locals import DOUBLEBUF, K_ESCAPE, KEYUP, QUIT + +pygame.init() + +DISPLAYSURF = pygame.display.set_mode( + (640, 480), DOUBLEBUF +) # set the display mode, window title and FPS clock +pygame.display.set_caption("Map Rendering Demo") +FPSCLOCK = pygame.time.Clock() + +map_data = [ + [1, 1, 1, 1, 1], + [1, 0, 0, 0, 1], + [1, 0, 0, 0, 1], + [1, 0, 0, 0, 1], + [1, 0, 0, 0, 1], + [1, 1, 1, 1, 1], +] # the data for the map expressed as [row[tile]]. + +wall = pygame.image.load("wall.png").convert_alpha() # load images +grass = pygame.image.load("grass.png").convert_alpha() + +TILEWIDTH = 64 # holds the tile width and height +TILEHEIGHT = 64 +TILEHEIGHT_HALF = TILEHEIGHT / 2 +TILEWIDTH_HALF = TILEWIDTH / 2 + +for row_nb, row in enumerate(map_data): # for every row of the map... + for col_nb, tile in enumerate(row): + if tile == 1: + tileImage = wall + else: + tileImage = grass + cart_x = row_nb * TILEWIDTH_HALF + cart_y = col_nb * TILEHEIGHT_HALF + iso_x = cart_x - cart_y + iso_y = (cart_x + cart_y) / 2 + centered_x = DISPLAYSURF.get_rect().centerx + iso_x + centered_y = DISPLAYSURF.get_rect().centery / 2 + iso_y + DISPLAYSURF.blit(tileImage, (centered_x, centered_y)) # display the actual tile + +while True: + for event in pygame.event.get(): + if event.type == QUIT: + pygame.quit() + sys.exit() + if event.type == KEYUP: + if event.key == K_ESCAPE: + pygame.quit() + sys.exit() + + pygame.display.flip() + FPSCLOCK.tick(30) diff --git a/pyproject.toml b/pyproject.toml index ec8968e..58be8c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ classifiers = [ dependencies = [ "click", "pygame", + "noise", "more_itertools", ] dynamic = ["version"] diff --git a/requirements.txt b/requirements.txt old mode 100755 new mode 100644 diff --git a/site/static/creeper-1.png b/site/static/creeper-1.png old mode 100755 new mode 100644 diff --git a/spacegame.py b/spacegame.py new file mode 100644 index 0000000..f2aecf6 --- /dev/null +++ b/spacegame.py @@ -0,0 +1,99 @@ +import pygame + +# Define some colors +BLACK = (0, 0, 0) +WHITE = (255, 255, 255) +GREEN = (0, 255, 0) +RED = (255, 0, 0) +BLUE = (0, 0, 255) + +# Define some constants +WIDTH = 800 +HEIGHT = 600 +FPS = 60 +GRAVITY = 0.5 + +# Define some variables +x = WIDTH / 2 +y = HEIGHT / 2 +vx = 0 +vy = 0 + +# Define some functions + + +def draw_dot(x, y): + pygame.draw.circle(window, BLACK, (int(x), int(y)), 10) + + +def move_dot(x, y, vx, vy): + x += vx + y += vy + return x, y + + +def apply_gravity(vy): + vy += GRAVITY + return vy + + +def jump(vy): + vy = -10 + return vy + + +# Initialize pygame +pygame.init() + +# Create a window +# Create a clock +clock = pygame.time.Clock() + +# Create a window +window = pygame.display.set_mode((WIDTH, HEIGHT)) + +# Set window title +pygame.display.set_caption("My Game") + +# Game loop +running = True +# Set the frame rate +clock.tick(FPS) + +while running: + # Process events + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_a: + vx = -5 + if event.key == pygame.K_d: + vx = 5 + if event.key == pygame.K_SPACE: + vy = jump(vy) + if event.type == pygame.KEYUP: + if event.key == pygame.K_a: + vx = 0 + if event.key == pygame.K_d: + vx = 0 + + running = False + x, y = move_dot(x, y, vx, vy) + vy = apply_gravity(vy) + + # Render + # Clear the screen + + # Draw the dot + draw_dot(x, y) + + # Update the display + # Update + + # Render + window.fill((255, 255, 255)) + pygame.display.update() + +# Close window on quit +pygame.quit() diff --git a/tetris.py b/tetris.py new file mode 100644 index 0000000..33626bf --- /dev/null +++ b/tetris.py @@ -0,0 +1,521 @@ +# Tetromino (a Tetris clone) +# By Al Sweigart al@inventwithpython.com +# http://inventwithpython.com/pygame +# Released under a "Simplified BSD" license + +import random +import time +import pygame +import sys +from pygame.locals import * + +FPS = 25 +WINDOWWIDTH = 640 +WINDOWZE = 20 +BOARHEIGHT = 480 +BOXSIDWIDTH = 10 +BOARDHEIGHT = 20 +BLANK = '.' + +MOVESIDEWAYSFREQ = 0.15 +MOVEDOWNFREQ = 0.1 + +XMARGIN = int((WINDOWWIDTH - BOARDWIDTH * BOXSIZE) / 2) +TOPMARGIN = WINDOWHEIGHT - (BOARDHEIGHT * BOXSIZE) - 5 + +# R G B +WHITE = (255, 255, 255) +GRAY = (185, 185, 185) +BLACK = (0, 0, 0) +RED = (155, 0, 0) +LIGHTRED = (175, 20, 20) +GREEN = (0, 155, 0) +LIGHTGREEN = (20, 175, 20) +BLUE = (0, 0, 155) +LIGHTBLUE = (20, 20, 175) +YELLOW = (155, 155, 0) +LIGHTYELLOW = (175, 175, 20) + +BORDERCOLOR = BLUE +BGCOLOR = BLACK +TEXTCOLOR = WHITE +TEXTSHADOWCOLOR = GRAY +COLORS = (BLUE, GREEN, RED, YELLOW) +LIGHTCOLORS = (LIGHTBLUE, LIGHTGREEN, LIGHTRED, LIGHTYELLOW) +assert len(COLORS) == len(LIGHTCOLORS) # each color must have light color + +TEMPLATEWIDTH = 5 +TEMPLATEHEIGHT = 5 + +S_SHAPE_TEMPLATE = [['.....', + '.....', + '..OO.', + '.OO..', + '.....'], + ['.....', + '..O..', + '..OO.', + '...O.', + '.....']] + +Z_SHAPE_TEMPLATE = [['.....', + '.....', + '.OO..', + '..OO.', + '.....'], + ['.....', + '..O..', + '.OO..', + '.O...', + '.....']] + +I_SHAPE_TEMPLATE = [['..O..', + '..O..', + '..O..', + '..O..', + '.....'], + ['.....', + '.....', + 'OOOO.', + '.....', + '.....']] + +O_SHAPE_TEMPLATE = [['.....', + '.....', + '.OO..', + '.OO..', + '.....']] + +J_SHAPE_TEMPLATE = [['.....', + '.O...', + '.OOO.', + '.....', + '.....'], + ['.....', + '..OO.', + '..O..', + '..O..', + '.....'], + ['.....', + '.....', + '.OOO.', + '...O.', + '.....'], + ['.....', + '..O..', + '..O..', + '.OO..', + '.....']] + +L_SHAPE_TEMPLATE = [['.....', + '...O.', + '.OOO.', + '.....', + '.....'], + ['.....', + '..O..', + '..O..', + '..OO.', + '.....'], + ['.....', + '.....', + '.OOO.', + '.O...', + '.....'], + ['.....', + '.OO..', + '..O..', + '..O..', + '.....']] + +T_SHAPE_TEMPLATE = [['.....', + '..O..', + '.OOO.', + '.....', + '.....'], + ['.....', + '..O..', + '..OO.', + '..O..', + '.....'], + ['.....', + '.....', + '.OOO.', + '..O..', + '.....'], + ['.....', + '..O..', + '.OO..', + '..O..', + '.....']] + +PIECES = {'S': S_SHAPE_TEMPLATE, + 'Z': Z_SHAPE_TEMPLATE, + 'J': J_SHAPE_TEMPLATE, + 'L': L_SHAPE_TEMPLATE, + 'I': I_SHAPE_TEMPLATE, + 'O': O_SHAPE_TEMPLATE, + 'T': T_SHAPE_TEMPLATE} + + +def main(): + global FPSCLOCK, DISPLAYSURF, BASICFONT, BIGFONT + pygame.init() + FPSCLOCK = pygame.time.Clock() + DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT)) + BASICFONT = pygame.font.Font('freesansbold.ttf', 18) + BIGFONT = pygame.font.Font('freesansbold.ttf', 100) + pygame.display.set_caption('Tetromino') + + showTextScreen('Tetromino') + while True: # game loop + # if random.randint(0, 1) == 0: + # pygame.mixer.music.load('tetrisb.mid') + # else: + # pygame.mixer.music.load('tetrisc.mid') + #pygame.mixer.music.play(-1, 0.0) + runGame() + # pygame.mixer.music.stop() + showTextScreen('Game Over') + + +def runGame(): + # setup variables for the start of the game + board = getBlankBoard() + lastMoveDownTime = time.time() + lastMoveSidewaysTime = time.time() + lastFallTime = time.time() + movingDown = False # note: there is no movingUp variable + movingLeft = False + movingRight = False + score = 0 + level, fallFreq = calculateLevelAndFallFreq(score) + + fallingPiece = getNewPiece() + nextPiece = getNewPiece() + + while True: # game loop + if fallingPiece == None: + # No falling piece in play, so start a new piece at the top + fallingPiece = nextPiece + nextPiece = getNewPiece() + lastFallTime = time.time() # reset lastFallTime + + if not isValidPosition(board, fallingPiece): + return # can't fit a new piece on the board, so game over + + checkForQuit() + for event in pygame.event.get(): # event handling loop + if event.type == KEYUP: + if (event.key == K_p): + # Pausing the game + DISPLAYSURF.fill(BGCOLOR) + pygame.mixer.music.stop() + showTextScreen('Paused') # pause until a key press + pygame.mixer.music.play(-1, 0.0) + lastFallTime = time.time() + lastMoveDownTime = time.time() + lastMoveSidewaysTime = time.time() + elif (event.key == K_LEFT or event.key == K_a): + movingLeft = False + elif (event.key == K_RIGHT or event.key == K_d): + movingRight = False + elif (event.key == K_DOWN or event.key == K_s): + movingDown = False + + elif event.type == KEYDOWN: + # moving the piece sideways + if (event.key == K_LEFT or event.key == K_a) and isValidPosition(board, fallingPiece, adjX=-1): + fallingPiece['x'] -= 1 + movingLeft = True + movingRight = False + lastMoveSidewaysTime = time.time() + + elif (event.key == K_RIGHT or event.key == K_d) and isValidPosition(board, fallingPiece, adjX=1): + fallingPiece['x'] += 1 + movingRight = True + movingLeft = False + lastMoveSidewaysTime = time.time() + + # rotating the piece (if there is room to rotate) + elif (event.key == K_UP or event.key == K_w): + fallingPiece['rotation'] = ( + fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']]) + if not isValidPosition(board, fallingPiece): + fallingPiece['rotation'] = ( + fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']]) + elif (event.key == K_q): # rotate the other direction + fallingPiece['rotation'] = ( + fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']]) + if not isValidPosition(board, fallingPiece): + fallingPiece['rotation'] = ( + fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']]) + + # making the piece fall faster with the down key + elif (event.key == K_DOWN or event.key == K_s): + movingDown = True + if isValidPosition(board, fallingPiece, adjY=1): + fallingPiece['y'] += 1 + lastMoveDownTime = time.time() + + # move the current piece all the way down + elif event.key == K_SPACE: + movingDown = False + movingLeft = False + movingRight = False + for i in range(1, BOARDHEIGHT): + if not isValidPosition(board, fallingPiece, adjY=i): + break + fallingPiece['y'] += i - 1 + + # handle moving the piece because of user input + if (movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ: + if movingLeft and isValidPosition(board, fallingPiece, adjX=-1): + fallingPiece['x'] -= 1 + elif movingRight and isValidPosition(board, fallingPiece, adjX=1): + fallingPiece['x'] += 1 + lastMoveSidewaysTime = time.time() + + if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1): + fallingPiece['y'] += 1 + lastMoveDownTime = time.time() + + # let the piece fall if it is time to fall + if time.time() - lastFallTime > fallFreq: + # see if the piece has landed + if not isValidPosition(board, fallingPiece, adjY=1): + # falling piece has landed, set it on the board + addToBoard(board, fallingPiece) + score += removeCompleteLines(board) + level, fallFreq = calculateLevelAndFallFreq(score) + fallingPiece = None + else: + # piece did not land, just move the piece down + fallingPiece['y'] += 1 + lastFallTime = time.time() + + # drawing everything on the screen + DISPLAYSURF.fill(BGCOLOR) + drawBoard(board) + drawStatus(score, level) + drawNextPiece(nextPiece) # Here + if fallingPiece != None: + drawPiece(fallingPiece) + + pygame.display.update() + FPSCLOCK.tick(FPS) + + +def makeTextObjs(text, font, color): + surf = font.render(text, True, color) + return surf, surf.get_rect() + + +def terminate(): + pygame.quit() + sys.exit() + + +def checkForKeyPress(): + # Go through event queue looking for a KEYUP event. + # Grab KEYDOWN events to remove them from the event queue. + checkForQuit() + + for event in pygame.event.get([KEYDOWN, KEYUP]): + if event.type == KEYDOWN: + continue + return event.key + return None + + +def showTextScreen(text): + # This function displays large text in the + # center of the screen until a key is pressed. + # Draw the text drop shadow + titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTSHADOWCOLOR) + titleRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2)) + DISPLAYSURF.blit(titleSurf, titleRect) + + # Draw the text + titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTCOLOR) + titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3) + DISPLAYSURF.blit(titleSurf, titleRect) + + # Draw the additional "Press a key to play." text. + pressKeySurf, pressKeyRect = makeTextObjs( + 'Press a key to play.', BASICFONT, TEXTCOLOR) + pressKeyRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 100) + DISPLAYSURF.blit(pressKeySurf, pressKeyRect) + + while checkForKeyPress() == None: + pygame.display.update() + FPSCLOCK.tick() + + +def checkForQuit(): + for event in pygame.event.get(QUIT): # get all the QUIT events + terminate() # terminate if any QUIT events are present + for event in pygame.event.get(KEYUP): # get all the KEYUP events + if event.key == K_ESCAPE: + terminate() # terminate if the KEYUP event was for the Esc key + pygame.event.post(event) # put the other KEYUP event objects back + + +def calculateLevelAndFallFreq(score): + # Based on the score, return the level the player is on and + # how many seconds pass until a falling piece falls one space. + level = int(score / 10) + 1 + fallFreq = 0.27 - (level * 0.02) + return level, fallFreq + + +def getNewPiece(): + # return a random new piece in a random rotation and color + shape = random.choice(list(PIECES.keys())) + newPiece = {'shape': shape, + 'rotation': random.randint(0, len(PIECES[shape]) - 1), + 'x': int(BOARDWIDTH / 2) - int(TEMPLATEWIDTH / 2), + 'y': -2, # start it above the board (i.e. less than 0) + 'color': random.randint(0, len(COLORS) - 1)} + return newPiece + + +def addToBoard(board, piece): + # fill in the board based on piece's location, shape, and rotation + for x in range(TEMPLATEWIDTH): + for y in range(TEMPLATEHEIGHT): + if PIECES[piece['shape']][piece['rotation']][y][x] != BLANK: + board[x + piece['x']][y + piece['y']] = piece['color'] + + +def getBlankBoard(): + # create and return a new blank board data structure + board = [] + for i in range(BOARDWIDTH): + board.append([BLANK] * BOARDHEIGHT) + return board + + +def isOnBoard(x, y): + return x >= 0 and x < BOARDWIDTH and y < BOARDHEIGHT + + +def isValidPosition(board, piece, adjX=0, adjY=0): + # Return True if the piece is within the board and not colliding + for x in range(TEMPLATEWIDTH): + for y in range(TEMPLATEHEIGHT): + isAboveBoard = y + piece['y'] + adjY < 0 + if isAboveBoard or PIECES[piece['shape']][piece['rotation']][y][x] == BLANK: + continue + if not isOnBoard(x + piece['x'] + adjX, y + piece['y'] + adjY): + return False + if board[x + piece['x'] + adjX][y + piece['y'] + adjY] != BLANK: + return False + return True + + +def isCompleteLine(board, y): + # Return True if the line filled with boxes with no gaps. + for x in range(BOARDWIDTH): + if board[x][y] == BLANK: + return False + return True + + +def removeCompleteLines(board): + # Remove any completed lines on the board, move everything above them down, and return the number of complete lines. + numLinesRemoved = 0 + y = BOARDHEIGHT - 1 # start y at the bottom of the board + while y >= 0: + if isCompleteLine(board, y): + # Remove the line and pull boxes down by one line. + for pullDownY in range(y, 0, -1): + for x in range(BOARDWIDTH): + board[x][pullDownY] = board[x][pullDownY - 1] + # Set very top line to blank. + for x in range(BOARDWIDTH): + board[x][0] = BLANK + numLinesRemoved += 1 + # Note on the next iteration of the loop, y is the same. + # This is so that if the line that was pulled down is also + # complete, it will be removed. + else: + y -= 1 # move on to check next row up + return numLinesRemoved + + +def convertToPixelCoords(boxx, boxy): + # Convert the given xy coordinates of the board to xy + # coordinates of the location on the screen. + return (XMARGIN + (boxx * BOXSIZE)), (TOPMARGIN + (boxy * BOXSIZE)) + + +def drawBox(boxx, boxy, color, pixelx=None, pixely=None): + # draw a single box (each tetromino piece has four boxes) + # at xy coordinates on the board. Or, if pixelx & pixely + # are specified, draw to the pixel coordinates stored in + # pixelx & pixely (this is used for the "Next" piece). + if color == BLANK: + return + if pixelx == None and pixely == None: + pixelx, pixely = convertToPixelCoords(boxx, boxy) + pygame.draw.rect(DISPLAYSURF, COLORS[color], + (pixelx + 1, pixely + 1, BOXSIZE - 1, BOXSIZE - 1)) + pygame.draw.rect( + DISPLAYSURF, LIGHTCOLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 4, BOXSIZE - 4)) + + +def drawBoard(board): + # draw the border around the board + pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (XMARGIN - 3, TOPMARGIN - 7, + (BOARDWIDTH * BOXSIZE) + 8, (BOARDHEIGHT * BOXSIZE) + 8), 5) + + # fill the background of the board + pygame.draw.rect(DISPLAYSURF, BGCOLOR, (XMARGIN, TOPMARGIN, + BOXSIZE * BOARDWIDTH, BOXSIZE * BOARDHEIGHT)) + # draw the individual boxes on the board + for x in range(BOARDWIDTH): + for y in range(BOARDHEIGHT): + drawBox(x, y, board[x][y]) + + +def drawStatus(score, level): + # draw the score text + scoreSurf = BASICFONT.render('Score: %s' % score, True, TEXTCOLOR) + scoreRect = scoreSurf.get_rect() + scoreRect.topleft = (WINDOWWIDTH - 150, 20) + DISPLAYSURF.blit(scoreSurf, scoreRect) + + # draw the level text + levelSurf = BASICFONT.render('Level: %s' % level, True, TEXTCOLOR) + levelRect = levelSurf.get_rect() + levelRect.topleft = (WINDOWWIDTH - 150, 50) + DISPLAYSURF.blit(levelSurf, levelRect) + + +def drawPiece(piece, pixelx=None, pixely=None): + shapeToDraw = PIECES[piece['shape']][piece['rotation']] + if pixelx == None and pixely == None: + # if pixelx & pixely hasn't been specified, use the location stored in the piece data structure + pixelx, pixely = convertToPixelCoords(piece['x'], piece['y']) + + # draw each of the boxes that make up the piece + for x in range(TEMPLATEWIDTH): + for y in range(TEMPLATEHEIGHT): + if shapeToDraw[y][x] != BLANK: + drawBox(None, None, piece['color'], pixelx + + (x * BOXSIZE), pixely + (y * BOXSIZE)) + + +def drawNextPiece(piece): + # draw the "next" text + nextSurf = BASICFONT.render('Next:', True, TEXTCOLOR) + nextRect = nextSurf.get_rect() + nextRect.topleft = (WINDOWWIDTH - 120, 80) + DISPLAYSURF.blit(nextSurf, nextRect) + # draw the "next" piece + drawPiece(piece, pixelx=WINDOWWIDTH - 120, pixely=100) + + +if __name__ == '__main__': + main() diff --git a/tmp.py b/tmp.py new file mode 100644 index 0000000..a82b9ca --- /dev/null +++ b/tmp.py @@ -0,0 +1,41 @@ +import noise +import pygame + +# Initialize pygame +pygame.init() + +# Set up the drawing window +screen = pygame.display.set_mode([800, 600]) + +# Run until the user asks to quit +running = True +while running: + + # Did the user click the window close button? + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + # Fill the background with black + screen.fill((0, 0, 0)) + + # Draw stars + for i in range(2000): + x = int(noise.pnoise1(i / 10.0, octaves=4) * 800) + y = int(noise.pnoise1(i / 10.0 + 1000, octaves=4) * 600) + pygame.draw.circle(screen, (255, 255, 255), (x, y), 2) + + # Draw the moon + pygame.draw.circle(screen, (180, 180, 180), (400, 5600 - 200), 5000, 0) # moon + + # Draw craters on the surface of the moon (masked by the shape of the moon) + for i in range(20): + x = int(noise.pnoise1(i / 10.0, octaves=4) * 800) + y = int(noise.pnoise1(i / 10.0 + 1000, octaves=4) * 600) + pygame.draw.circle(screen, (100, 100, 100), (x, y), 20, 0) + + # Flip the display + pygame.display.flip() + +# Done! Time to quit. +pygame.quit() diff --git a/wall.png b/wall.png new file mode 100644 index 0000000..a81bb68 Binary files /dev/null and b/wall.png differ