From: Skullheadx <94652084+Skullheadx@users.noreply.github.com> Date: Tue, 4 Jul 2023 21:18:10 +0000 (-0400) Subject: fixed performance on checking if split is good X-Git-Tag: game~6 X-Git-Url: http://git.skullheadx.com/nixos/static/tech/index.html?a=commitdiff_plain;h=6112423938dffd60aae0a9fae7a0cbc60d745eca;p=fruit-ninja.git fixed performance on checking if split is good --- diff --git a/README.md b/README.md index a9bee68..7db37d0 100644 --- a/README.md +++ b/README.md @@ -22,4 +22,8 @@ https://pixabay.com/sound-effects/sub-bass-4-secondsssss-6241/ ## Game background image made with help from https://www.deviantart.com/sadfacerl/art/WoodTexture-748548579 -## Blood Splatter Effect https://bluerosesonata.itch.io/free-blood-splatter-cgsfx \ No newline at end of file +## Blood Splatter Effect https://bluerosesonata.itch.io/free-blood-splatter-cgsfx + + +Bomb https://www.rawpixel.com/image/6287121/png-public-domain-black +Knife https://wandering-ghost.itch.io/horror-knifes-sprites \ No newline at end of file diff --git a/assets/bomb.png b/assets/bomb.png index 5418bee..5d873bb 100644 Binary files a/assets/bomb.png and b/assets/bomb.png differ diff --git a/assets/knife.png b/assets/knife.png new file mode 100644 index 0000000..832c934 Binary files /dev/null and b/assets/knife.png differ diff --git a/bomb.py b/bomb.py index 9fae48f..133934e 100644 --- a/bomb.py +++ b/bomb.py @@ -1,5 +1,4 @@ from fruit import Fruit -from effect import SplitEffect from setup import * @@ -12,6 +11,8 @@ class Bomb(Fruit): BOMB_IMAGE = pygame.image.load("assets/bomb.png").convert_alpha() BOMB_TXT = Texture.from_surface(renderer, BOMB_IMAGE) + RADIUS_FACTOR = 1.75 + EXPLOSIONS = [ [ Texture.from_surface(renderer, pygame.image.load(f"assets/explosion/Punch1/File1.png")), @@ -57,6 +58,10 @@ class Bomb(Fruit): self.explosion_txt = random.choice(self.EXPLOSIONS) + circle = pygame.Surface((self.radius * 2, self.radius * 2), pygame.SRCALPHA) + pygame.draw.circle(circle, (255, 255, 255, 255), (self.radius, self.radius), self.radius) + self.circle = Texture.from_surface(renderer, circle) + def update(self, delta): super().update(delta) if self.exploded: @@ -93,7 +98,11 @@ class Bomb(Fruit): self.EXPLOSION_RADIUS * 2, self.EXPLOSION_RADIUS * 2)) else: - if self.position.y - self.radius <= HEIGHT: - self.BOMB_TXT.draw(None, pygame.Rect(self.position.x - self.radius, self.position.y - self.radius, - self.radius * 2, self.radius * 2), self.angle, - (self.radius, self.radius)) + # self.circle.draw(None, pygame.Rect(self.position.x - self.RADIUS, self.position.y - self.RADIUS, + # self.RADIUS * 2, self.RADIUS * 2)) + + self.BOMB_TXT.draw(None, pygame.Rect(self.position.x - self.radius * self.RADIUS_FACTOR, + self.position.y - self.radius * self.RADIUS_FACTOR, + self.radius * 2 * self.RADIUS_FACTOR, + self.radius * 2 * self.RADIUS_FACTOR), + self.angle, (self.radius * self.RADIUS_FACTOR, self.radius * self.RADIUS_FACTOR)) diff --git a/effect.py b/effect.py index 4b6462e..368e90b 100644 --- a/effect.py +++ b/effect.py @@ -119,11 +119,12 @@ class SplitEffect: random.random()) / 100 + pygame.Vector2(normal_velocity) self.acceleration = pygame.Vector2(0, self.gravity) - self.angle = 0 + self.angle = frame.angle self.direction = random.choice([-1, 1]) - self.frame = Texture.from_surface(renderer, frame) - self.width, self.height = self.frame.width, self.frame.height + + self.frame = frame + self.width, self.height = self.frame.get_rect().width, self.frame.get_rect().height def update(self, delta): self.velocity += self.acceleration * delta / 1000 @@ -135,83 +136,95 @@ class SplitEffect: return True def draw(self): + self.frame.angle = self.angle + # print(self.position) self.frame.draw(None, pygame.Rect(self.position.x - self.width / 2, self.position.y - self.height / 2, - self.width, self.height), - self.angle, origin=(self.width / 2, self.height / 2)) - self.width, self.height = self.frame.width, self.frame.height + self.width, self.height)) + self.width, self.height = self.frame.get_rect().width, self.frame.get_rect().height @staticmethod def find_normals(v): return pygame.Vector2(-v.y, v.x), pygame.Vector2(v.y, -v.x) @staticmethod - def should_split(image, angle, image_position, mouse_position, mouse_direction, radius): - img, img_pos = rotate_center(pygame.transform.scale(image.copy(), (radius * 2, radius * 2)), angle, - image_position) - img_pos += pygame.Vector2(img.get_size()) / 2 + def should_split(texture, angle, image_position, mouse_position, mouse_direction, radius): if mouse_direction.x == 0: mouse_direction.x += 0.0001 + a = math.degrees(math.atan(mouse_direction.y / mouse_direction.x)) - img = rotate_center(img, a, pygame.Vector2(0, 0))[0] + diagonal = math.sqrt(2 * ((radius * 2) ** 2)) + txt = Texture(renderer, (diagonal, diagonal), target=True) + txt.blend_mode = pygame.BLEND_ADD + renderer.target = txt + texture.draw(None, pygame.Rect((diagonal - radius * 2) / 2, (diagonal - radius * 2) / 2, radius * 2, + radius * 2), angle - a, origin=(radius, radius)) + renderer.target = None + + img_size = pygame.Vector2(diagonal, diagonal) + center = img_size / 2 + + # finding end and start points of the splitting line + # [x,y] = mouse_position + t * mouse_direction # vector equation + # x = mouse_position.x + t * mouse_direction.x + # y = mouse_position.y + t * mouse_direction.y - top_left = pygame.Vector2(image_position) - pygame.Vector2(img.get_width() / 2, img.get_height() / 2) - rot_center = pygame.Vector2(image_position) - top_left - mp = mouse_position - top_left + mp = mouse_position - image_position + center t1 = (- mp.x) / mouse_direction.x p1 = mp + t1 * mouse_direction - p3 = (p1 - rot_center).rotate(-a) + rot_center + p3 = (p1 - center).rotate(-a) + center MIN_SPLIT = 0.25 - slice_percent = clamp(p3.y, 0, img.get_height()) / img.get_height() + slice_percent = clamp(p3.y, 0, img_size.y) / img_size.y if MIN_SPLIT < slice_percent < 1 - MIN_SPLIT: return True return False @staticmethod - def split_image(image, angle, image_position, mouse_position, mouse_direction, radius): - img, img_pos = rotate_center(pygame.transform.scale(image.copy(), (radius * 2, radius * 2)), angle, - image_position) - - - img_pos += pygame.Vector2(img.get_size()) / 2 + def split_image(texture, angle, image_position, mouse_position, mouse_direction, radius): if mouse_direction.x == 0: mouse_direction.x += 0.0001 a = math.degrees(math.atan(mouse_direction.y / mouse_direction.x)) - img = rotate_center(img, a, pygame.Vector2(0, 0))[0] + diagonal = math.sqrt(2 * ((radius * 2) ** 2)) + txt = Texture(renderer, (diagonal, diagonal), target=True) + txt.blend_mode = pygame.BLEND_ADD + renderer.target = txt + texture.draw(None, pygame.Rect((diagonal - radius * 2) / 2, (diagonal - radius * 2) / 2, radius * 2, + radius * 2), angle - a, origin=(radius, radius)) + renderer.target = None - top_left = pygame.Vector2(img_pos) - pygame.Vector2(img.get_width() / 2, img.get_height() / 2) - rot_center = pygame.Vector2(img_pos) - top_left + img_size = pygame.Vector2(diagonal, diagonal) + center = img_size / 2 # finding end and start points of the splitting line # [x,y] = mouse_position + t * mouse_direction # vector equation # x = mouse_position.x + t * mouse_direction.x # y = mouse_position.y + t * mouse_direction.y - mp = mouse_position - top_left + mp = mouse_position - image_position + center t1 = (- mp.x) / mouse_direction.x p1 = mp + t1 * mouse_direction - p3 = (p1 - rot_center).rotate(-a) + rot_center + p3 = (p1 - center).rotate(-a) + center - half1 = img.subsurface(pygame.Rect(0, 0, img.get_width(), clamp(p3.y, 0, img.get_height()))) - half2 = img.subsurface(pygame.Rect(0, clamp(p3.y, 0, img.get_height()), img.get_width(), - clamp(img.get_height() - p3.y, 0, img.get_height()))) + half1 = Image(txt, pygame.Rect(0, 0, img_size.x, clamp(p3.y, 0, img_size.y))) + half2 = Image(txt, + pygame.Rect(0, clamp(p3.y, 0, img_size.y), img_size.x, clamp(img_size.y - p3.y, 0, img_size.y))) - p5 = half1.get_rect().center - rot_center - pos1 = p5.rotate(a) + img_pos + p5 = half1.get_rect().center - center + pos1 = p5.rotate(a) + image_position - p6 = half2.get_rect().center - rot_center + pygame.Vector2(0, clamp(p3.y, 0, img.get_height())) - pos2 = p6.rotate(a) + img_pos + p6 = half2.get_rect().center - center + pos2 = p6.rotate(a) + image_position - r_half1 = pygame.transform.rotate(half1, -a) - r_half2 = pygame.transform.rotate(half2, -a) + half1.angle = a + half2.angle = a - return r_half1, r_half2, pos1, pos2 + return half1, half2, pos1, pos2 class SlashEffect: diff --git a/fruit.py b/fruit.py index aed62a3..37a9df3 100644 --- a/fruit.py +++ b/fruit.py @@ -50,4 +50,4 @@ class Fruit: if self.position.y - self.radius <= HEIGHT: self.fruit_txt.draw(None, pygame.Rect(self.position - pygame.Vector2(self.radius, self.radius), (self.radius * 2, self.radius * 2)), - angle=-self.angle, origin=(self.radius, self.radius)) + angle=self.angle, origin=(self.radius, self.radius)) diff --git a/game.py b/game.py index 9680b40..d863598 100644 --- a/game.py +++ b/game.py @@ -8,7 +8,7 @@ from setup import * class Game: - BOMB_CHANCE = 0 + BOMB_CHANCE = 0.1 COMBO_TIME = 250 GAME_OVER_TIME = 2000 @@ -59,7 +59,7 @@ class Game: self.time_since_last_hit = 0 self.current_combo = 0 - self.wave = 100 + self.wave = 1 self.cleared_wave = True self.wave_cooldown_timer = 0 @@ -83,7 +83,7 @@ class Game: self.score_surf = font.render(f"SCORE {self.score}", True, WHITE) self.score_txt = Texture.from_surface(renderer, self.score_surf) - self.combo_surf = font.render(f"COMBO x{self.current_combo}", True, WHITE) + self.combo_surf = font.render(f"COMBO x{max(1,self.current_combo)}", True, WHITE) self.combo_txt = Texture.from_surface(renderer, self.combo_surf) self.high_score_surf = font.render(f"BEST {self.high_score}", True, WHITE) @@ -139,7 +139,7 @@ class Game: fruit.update(delta) hit_status = self.player.hits(fruit) - if hit_status and SplitEffect.should_split(fruit.image, fruit.angle, fruit.position, + if hit_status and SplitEffect.should_split(fruit.fruit_txt, fruit.angle, fruit.position, self.player.previous_mouse_pos, self.player.mouse_direction, fruit.radius): hits.append((fruit, self.player.mouse_direction, self.player.previous_mouse_pos)) @@ -159,7 +159,7 @@ class Game: self.high_score_txt = Texture.from_surface(renderer, self.high_score_surf) else: self.current_combo = 0 - self.combo_surf = font.render(f"COMBO x{self.current_combo}", True, WHITE) + self.combo_surf = font.render(f"COMBO x{max(1,self.current_combo)}", True, WHITE) self.combo_txt = Texture.from_surface(renderer, self.combo_surf) for hit, mouse_direction, mouse_position in hits: @@ -169,7 +169,7 @@ class Game: color)) self.effects[1].append(BloodEffect(hit.position, hit.radius, lighten(color, 0.15))) - half1, half2, pos1, pos2 = SplitEffect.split_image(hit.image, hit.angle, hit.position, mouse_position, + half1, half2, pos1, pos2 = SplitEffect.split_image(hit.fruit_txt, hit.angle, hit.position, mouse_position, mouse_direction, hit.radius) n1, n2 = SplitEffect.find_normals(mouse_direction.normalize() * 5) @@ -186,7 +186,7 @@ class Game: if self.time_since_last_hit < self.COMBO_TIME: self.current_combo += 1 - self.combo_surf = font.render(f"COMBO x{self.current_combo}", True, WHITE) + self.combo_surf = font.render(f"COMBO x{max(1,self.current_combo)}", True, WHITE) self.combo_txt = Texture.from_surface(renderer, self.combo_surf) if self.current_combo > 1: self.combo_counters.append(ComboCounter(hit.position, self.current_combo + 1)) @@ -218,7 +218,7 @@ class Game: self.bombs.remove(bomb) continue if (((not -bomb.radius * 2 < bomb.position.x < WIDTH + bomb.radius * 2) or - bomb.position.y - bomb.radius * 2 > HEIGHT) and bomb.velocity.y > 0): + bomb.position.y - bomb.radius * 2 * bomb.RADIUS_FACTOR > HEIGHT) and bomb.velocity.y > 0): self.bombs.remove(bomb) if len(self.fruits) == 0 and len(self.bombs) == 0 and not self.game_over: @@ -269,7 +269,6 @@ class Game: effect.draw() for combo in self.combo_counters: combo.draw() - self.player.draw() for effect in self.effects[4]: effect.draw() @@ -278,3 +277,4 @@ class Game: self.r2.draw() self.game_over_txt.draw(None, ( WIDTH / 2 - self.game_over_txt.width / 2, HEIGHT / 2 - self.game_over_txt.height / 2)) + self.player.draw() diff --git a/high_score.txt b/high_score.txt index d23ee5c..c227083 100644 --- a/high_score.txt +++ b/high_score.txt @@ -1 +1 @@ -3850 \ No newline at end of file +0 \ No newline at end of file diff --git a/image.png b/image.png deleted file mode 100644 index 73e6ada..0000000 Binary files a/image.png and /dev/null differ diff --git a/main.py b/main.py index b3d22be..2053bfe 100644 --- a/main.py +++ b/main.py @@ -15,9 +15,9 @@ while is_running: status = scene.update(delta) scene.draw() - fps_text = font_small.render(f"FPS: {clock.get_fps():.0f}", True, DARK_GRAY) - fps_txt = Texture.from_surface(renderer, fps_text) - fps_txt.draw(None, pygame.Vector2(10, 75)) + # fps_text = font_small.render(f"FPS: {clock.get_fps():.0f}", True, DARK_GRAY) + # fps_txt = Texture.from_surface(renderer, fps_text) + # fps_txt.draw(None, pygame.Vector2(10, 75)) renderer.present() diff --git a/menu.py b/menu.py index 2dcf1bf..21ac97b 100644 --- a/menu.py +++ b/menu.py @@ -88,7 +88,7 @@ class Menu: if not self.blacked_out: hit_status = self.player.hits(self.fruit) # Check if player hits fruit # Check if fruit should split - if hit_status and SplitEffect.should_split(self.fruit.image, self.fruit.angle, self.fruit.position, + if hit_status and SplitEffect.should_split(self.fruit.fruit_txt, self.fruit.angle, self.fruit.position, self.player.previous_mouse_pos, self.player.mouse_direction, self.fruit.radius): # Split fruit @@ -100,7 +100,7 @@ class Menu: self.fruit.position + self.player.mouse_direction), color)) self.effects.append(BloodEffect(self.fruit.position, self.fruit.radius, lighten(color, 0.15))) - half1, half2, pos1, pos2 = SplitEffect.split_image(self.fruit.image, self.fruit.angle, + half1, half2, pos1, pos2 = SplitEffect.split_image(self.fruit.fruit_txt, self.fruit.angle, self.fruit.position, self.player.previous_mouse_pos, self.player.mouse_direction, self.fruit.radius) @@ -143,7 +143,7 @@ class Menu: self.controls_txt.draw(None, self.controls_surface.get_rect(bottomleft=(10, HEIGHT - 10))) self.credit_txt.draw(None, self.credit_surface.get_rect(bottomright=(WIDTH - 10, HEIGHT - 10))) - self.player.draw() for effect in self.effects: effect.draw() + self.player.draw() diff --git a/player.py b/player.py index fe66ea8..ba3f230 100644 --- a/player.py +++ b/player.py @@ -1,11 +1,15 @@ +import pygame.mouse + from setup import * class Player: LIFE_TIME = 100 - INFLATE_SCALE = 20 - IMAGE = pygame.image.load("assets/effects/sword_slashes/White_Slash_Thin/File2.png").convert_alpha() + image = pygame.image.load("assets/knife.png").convert_alpha() + txt = Texture.from_surface(renderer, image) + + SIZE = pygame.Vector2(50* SCALE, 50* SCALE) def __init__(self): self.sliced_points = [] @@ -13,10 +17,9 @@ class Player: self.previous_mouse_pos = pygame.Vector2(pygame.mouse.get_pos()) self.mouse_direction = pygame.Vector2(0, 0) - self.angle = 0 self.slicing = False - self.display_image = self.IMAGE.copy() - self.position = pygame.Vector2(0, 0) + + self.angle = 0 def update(self, delta): pressed = pygame.mouse.get_pressed() @@ -25,21 +28,13 @@ class Player: self.sliced_points.append((pygame.Vector2(pos), pygame.time.get_ticks())) self.mouse_direction = pygame.Vector2(pos) - self.previous_mouse_pos self.previous_mouse_pos = pygame.Vector2(pos) - if self.mouse_direction.x == 0: - x_direction = self.mouse_direction.x + 0.0001 - else: - x_direction = self.mouse_direction.x - self.angle = math.degrees(math.atan(self.mouse_direction.y / x_direction)) - self.display_image, self.position = rotate_center(self.IMAGE, self.angle, - pygame.Vector2(pos) + pygame.Vector2( - self.IMAGE.get_width() / 2, 0)) self.slicing = True else: self.mouse_direction = pygame.Vector2(0, 0) self.previous_mouse_pos = pygame.Vector2(pygame.mouse.get_pos()) - self.angle = 0 self.slicing = False + self.lines.clear() if len(self.sliced_points) > 1: for i in range(len(self.sliced_points) - 1): @@ -78,3 +73,5 @@ class Player: for i in range(len(self.sliced_points) - 1): renderer.draw_line(self.sliced_points[i][0], self.sliced_points[i + 1][0]) renderer.draw_line(self.previous_mouse_pos, self.previous_mouse_pos - self.mouse_direction) + self.txt.draw(None, pygame.Rect(pygame.mouse.get_pos(), self.SIZE)) + diff --git a/setup.py b/setup.py index 7897215..08ad0f1 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ import pygame -from pygame._sdl2 import Window, Renderer, Texture +from pygame._sdl2 import Window, Renderer, Texture, Image import random import os import math @@ -10,6 +10,7 @@ WIDTH, HEIGHT = pygame.display.Info().current_w, pygame.display.Info().current_h display = pygame.display.set_mode((WIDTH, HEIGHT)) window = Window.from_display_module() renderer = Renderer(window) +pygame.mouse.set_visible(False) SCALE = pygame.Vector2(WIDTH / 1536, HEIGHT / 864) @@ -93,19 +94,6 @@ def lerp(start, end, weight): def clamp(value, minimum, maximum): return min(maximum, max(minimum, value)) - -@cache -def rotate(image, angle): - return pygame.transform.rotate(image, angle) - - -def rotate_center(image, angle, position): - rotated_image = rotate(image, round(angle)) - new_rect = rotated_image.get_rect(center=image.get_rect(topleft=(position.x - image.get_rect().width / 2, - position.y - image.get_rect().height / 2)).center) - return rotated_image, new_rect.topleft - - def determine_angle(pos1, pos2): pos1 = pygame.Vector2(pos1) pos2 = pygame.Vector2(pos2)