diff --git a/images/megaball-prev00.gif b/images/megaball-prev00.gif deleted file mode 100644 index d26c305..0000000 Binary files a/images/megaball-prev00.gif and /dev/null differ diff --git a/megaball.pyxapp b/megaball.pyxapp new file mode 100644 index 0000000..0871e33 Binary files /dev/null and b/megaball.pyxapp differ diff --git a/megaball/assets/my_resource.pyxres b/megaball/assets/my_resource.pyxres index fddafb9..79bc9d2 100644 Binary files a/megaball/assets/my_resource.pyxres and b/megaball/assets/my_resource.pyxres differ diff --git a/megaball/audio.py b/megaball/audio.py index 1229365..39a95c8 100644 --- a/megaball/audio.py +++ b/megaball/audio.py @@ -1,4 +1,3 @@ - import pyxel import globals @@ -16,7 +15,7 @@ MUS_START, MUS_STAGE_COMPLETE, MUS_DEATH, - #MUS_GAME_OVER + # MUS_GAME_OVER ] SND_MENU_MOVE = 16 @@ -33,25 +32,27 @@ SND_USED_WEAPON, ] + def play_sound(snd, looping=False): if globals.g_sound_on == False: return - + if snd not in SOUNDS: return - + if pyxel.play_pos(3) != -1: return - + pyxel.play(3, snd, loop=looping) - + + def play_music(msc, looping=False): if globals.g_music_on == False: return - + if msc not in MUSIC: return - + pyxel.stop() - + pyxel.playm(msc, loop=looping) diff --git a/megaball/circle.py b/megaball/circle.py index 4bbb726..28cc9e1 100644 --- a/megaball/circle.py +++ b/megaball/circle.py @@ -1,27 +1,29 @@ - def overlap(x1, y1, r1, x2, y2, r2): dx = x1 - x2 dy = y1 - y2 dist = dx * dx + dy * dy radiusSum = r1 + r2 return dist < radiusSum * radiusSum - + + def contains_other(x1, y1, r1, x2, y2, r2): radiusDiff = r1 - r2 if radiusDiff < 0: return False - + dx = x1 - x2 dy = y1 - y2 dist = dx * dx + dy * dy radiusSum = r1 + r2 - return (not(radiusDiff * radiusDiff < dist) and (dist < radiusSum * radiusSum)) - + return not (radiusDiff * radiusDiff < dist) and (dist < radiusSum * radiusSum) + + def contains_point(x, y, radius, px, py): dx = x - px dy = y - py return dx * dx + dy * dy <= radius * radius + class Circle: def __init__(self, x, y, radius): self.x = x diff --git a/megaball/constants.py b/megaball/constants.py index 8d0e753..7a079e0 100644 --- a/megaball/constants.py +++ b/megaball/constants.py @@ -1,4 +1,3 @@ - GAME_TITLE = "MEGABALL" GAME_WIDTH = 160 GAME_HEIGHT = 144 @@ -56,18 +55,15 @@ COLLIDE_TOP_LEFT, COLLIDE_TOP_RIGHT, COLLIDE_BOTTOM_RIGHT, - COLLIDE_BOTTOM_LEFT + COLLIDE_BOTTOM_LEFT, ] + def is_colliding_matrix(x, y, matrix): if matrix not in COLLIDE_MATRIX_ALL: return False - + if x < 0 or x > 7 or y < 0 or y > 7: return False - + return matrix[y][x] - - - - \ No newline at end of file diff --git a/megaball/game.py b/megaball/game.py index 30d10fd..3a95e0c 100644 --- a/megaball/game.py +++ b/megaball/game.py @@ -1,4 +1,3 @@ - import pyxel import constants @@ -11,26 +10,27 @@ import globals import audio + class Game: def __init__(self): self.pal_control = palette.PaletteControl() - + self.screen_shake = screenshake.ScreenShake(self) - + self.main_menu = mainmenu.MainMenu(self) self.stage = stage.Stage(self, 0) self.hud = hud.Hud(self) - + self.pal_index = 0 - + audio.play_music(audio.MUS_TITLE, True) - + def restart_music(self): if self.main_menu.is_visible: audio.play_music(audio.MUS_TITLE) else: self.stage.restart_music() - + def quit_to_main_menu(self): del self.stage self.stage = stage.Stage(self, 0) @@ -38,66 +38,65 @@ def quit_to_main_menu(self): globals.reset() self.main_menu.reset() self.add_fade(palette.FADE_STEP_TICKS_DEFAULT, palette.FADE_LEVEL_3) - + def go_to_next_stage(self): globals.g_stage_num += 1 del self.stage self.stage = stage.Stage(self, globals.g_stage_num) self.add_fade(palette.FADE_STEP_TICKS_DEFAULT, palette.FADE_LEVEL_3) - + def go_to_game_complete_stage(self): del self.stage self.stage = stage.Stage(self, stage.MAX_STAGE_NUM + 1) self.add_fade(palette.FADE_STEP_TICKS_DEFAULT, palette.FADE_LEVEL_3) - + def restart_stage(self): del self.stage self.stage = stage.Stage(self, globals.g_stage_num) self.add_fade(palette.FADE_STEP_TICKS_DEFAULT, palette.FADE_LEVEL_3) - + def start_game(self): self.main_menu.hide() del self.stage self.stage = stage.Stage(self, globals.g_stage_num) self.add_fade(palette.FADE_STEP_TICKS_DEFAULT, palette.FADE_LEVEL_3) - + def add_screen_shake(self, ticks, magnitude, queue=False): self.screen_shake.add_event(ticks, magnitude, queue) - + def cycle_palette(self): self.pal_index += 1 if self.pal_index == len(palette.ALL): self.pal_index = 0 self.pal_control.add_palette_event(1, palette.ALL[self.pal_index]) self.add_fade(palette.FADE_STEP_TICKS_DEFAULT, palette.FADE_LEVEL_3) - + def add_fade(self, ticks_per_level, target_level, callback=None): self.pal_control.add_fade_event(ticks_per_level, target_level, callback) def update(self, last_inputs): if pyxel.btnp(pyxel.KEY_F1): globals.toggle_sound() - + if pyxel.btnp(pyxel.KEY_F2): globals.toggle_music(self) - + self.main_menu.update(last_inputs) - + self.stage.update(last_inputs) - + self.pal_control.update() self.screen_shake.update() - + def draw(self): for c in range(palette.NUM_COLOURS): pyxel.pal(palette.DEFAULT[c], self.pal_control.get_col(c)) - + pyxel.cls(self.pal_control.get_col(0)) - + self.stage.draw(self.screen_shake.x, self.screen_shake.y) self.hud.draw(self.screen_shake.x, self.screen_shake.y) - + self.main_menu.draw(self.screen_shake.x, self.screen_shake.y) - + pyxel.pal() - \ No newline at end of file diff --git a/megaball/globals.py b/megaball/globals.py index bc0bb19..39741ab 100644 --- a/megaball/globals.py +++ b/megaball/globals.py @@ -1,4 +1,3 @@ - import pyxel import constants @@ -21,46 +20,51 @@ g_sound_on = True g_music_on = True + def reset(): global g_lives global g_score global g_stage_num - + g_lives = STARTING_LIVES g_score = 0 g_stage_num = 1 - + + def toggle_sound(): global g_sound_on - + g_sound_on = not g_sound_on - + if g_sound_on == False: pyxel.stop() - + + def toggle_music(game_obj): global g_music_on - + g_music_on = not g_music_on - + if g_music_on == False: pyxel.stop() else: game_obj.restart_music() - + + def set_high_score(): global g_score global g_highscore - + g_highscore = max(g_score, g_highscore) - + + def add_lives(amt): global g_lives - + g_lives = max(0, min(g_lives + amt, MAX_LIVES)) - + + def add_score(amt): global g_score - + g_score = max(0, min(g_score + amt, MAX_SCORE)) - \ No newline at end of file diff --git a/megaball/hud.py b/megaball/hud.py index 51885d6..638e25e 100644 --- a/megaball/hud.py +++ b/megaball/hud.py @@ -1,4 +1,3 @@ - import pyxel import game @@ -7,13 +6,14 @@ import utils import stage + class Hud: def __init__(self, game): self.game = game - + def update(self): pass - + def draw(self, shake_x, shake_y): # top bar pyxel.blt(shake_x + 0, shake_y + 0, 0, 0, 0, constants.GAME_WIDTH, 16) @@ -23,9 +23,16 @@ def draw(self, shake_x, shake_y): pyxel.blt(shake_x + 0, shake_y + 16, 0, 0, 24, 8, 120) # right bar pyxel.blt(shake_x + 152, shake_y + 16, 0, 8, 24, 8, 120) - - utils.draw_number_shadowed(shake_x + 31, shake_y + 5, globals.g_lives, zeropad=2) - utils.draw_number_shadowed(shake_x + 57, shake_y + 5, globals.g_score, zeropad=6) - utils.draw_number_shadowed(shake_x + 113, shake_y + 5, globals.g_stage_num, zeropad=2) - utils.draw_number_shadowed(shake_x + 137, shake_y + 5, stage.MAX_STAGE_NUM, zeropad=2) - \ No newline at end of file + + utils.draw_number_shadowed( + shake_x + 31, shake_y + 5, globals.g_lives, zeropad=2 + ) + utils.draw_number_shadowed( + shake_x + 57, shake_y + 5, globals.g_score, zeropad=6 + ) + utils.draw_number_shadowed( + shake_x + 113, shake_y + 5, globals.g_stage_num, zeropad=2 + ) + utils.draw_number_shadowed( + shake_x + 137, shake_y + 5, stage.MAX_STAGE_NUM, zeropad=2 + ) diff --git a/megaball/input.py b/megaball/input.py index c156fbc..633defa 100644 --- a/megaball/input.py +++ b/megaball/input.py @@ -1,4 +1,3 @@ - import pyxel UP = 0 @@ -10,76 +9,102 @@ BUTTON_START = 6 BUTTON_SELECT = 7 -class Input: +class Input: def __init__(self): self.pressing = [] self.pressed = [] - + def get(self): self.pressing.clear() self.pressed.clear() # pressing - if pyxel.btn(pyxel.KEY_UP) or pyxel.btn(pyxel.KEY_W) or \ - pyxel.btn(pyxel.GAMEPAD_1_UP): + if ( + pyxel.btn(pyxel.KEY_UP) + or pyxel.btn(pyxel.KEY_W) + or pyxel.btn(pyxel.GAMEPAD1_BUTTON_DPAD_UP) + ): self.pressing.append(UP) - elif pyxel.btn(pyxel.KEY_DOWN) or pyxel.btn(pyxel.KEY_S) or \ - pyxel.btn(pyxel.GAMEPAD_1_DOWN): + elif ( + pyxel.btn(pyxel.KEY_DOWN) + or pyxel.btn(pyxel.KEY_S) + or pyxel.btn(pyxel.GAMEPAD1_BUTTON_DPAD_DOWN) + ): self.pressing.append(DOWN) - - if pyxel.btn(pyxel.KEY_LEFT) or pyxel.btn(pyxel.KEY_A) or \ - pyxel.btn(pyxel.GAMEPAD_1_LEFT): + + if ( + pyxel.btn(pyxel.KEY_LEFT) + or pyxel.btn(pyxel.KEY_A) + or pyxel.btn(pyxel.GAMEPAD1_BUTTON_DPAD_LEFT) + ): self.pressing.append(LEFT) - elif pyxel.btn(pyxel.KEY_RIGHT) or pyxel.btn(pyxel.KEY_D) or \ - pyxel.btn(pyxel.GAMEPAD_1_RIGHT): + elif ( + pyxel.btn(pyxel.KEY_RIGHT) + or pyxel.btn(pyxel.KEY_D) + or pyxel.btn(pyxel.GAMEPAD1_BUTTON_DPAD_RIGHT) + ): self.pressing.append(RIGHT) - - if pyxel.btn(pyxel.KEY_Z) or pyxel.btn(pyxel.KEY_K) or \ - pyxel.btn(pyxel.GAMEPAD_1_A): + + if ( + pyxel.btn(pyxel.KEY_Z) + or pyxel.btn(pyxel.KEY_K) + or pyxel.btn(pyxel.KEY_SPACE) + or pyxel.btn(pyxel.GAMEPAD1_BUTTON_A) + ): self.pressing.append(BUTTON_A) - - if pyxel.btn(pyxel.KEY_X) or pyxel.btn(pyxel.KEY_L) or \ - pyxel.btn(pyxel.GAMEPAD_1_B): + + if ( + pyxel.btn(pyxel.KEY_X) + or pyxel.btn(pyxel.KEY_L) + or pyxel.btn(pyxel.GAMEPAD1_BUTTON_B) + ): self.pressing.append(BUTTON_B) - - if pyxel.btn(pyxel.KEY_ENTER) or \ - pyxel.btn(pyxel.GAMEPAD_1_START): + + if pyxel.btn(pyxel.KEY_RETURN) or pyxel.btn(pyxel.GAMEPAD1_BUTTON_START): self.pressing.append(BUTTON_START) - - if pyxel.btn(pyxel.KEY_SPACE) or \ - pyxel.btn(pyxel.GAMEPAD_1_SELECT): - self.pressing.append(BUTTON_SELECT) - + # pressed - if pyxel.btnp(pyxel.KEY_UP) or pyxel.btnp(pyxel.KEY_W) or \ - pyxel.btnp(pyxel.GAMEPAD_1_UP): + if ( + pyxel.btnp(pyxel.KEY_UP) + or pyxel.btnp(pyxel.KEY_W) + or pyxel.btnp(pyxel.GAMEPAD1_BUTTON_DPAD_UP) + ): self.pressed.append(UP) - elif pyxel.btnp(pyxel.KEY_DOWN) or pyxel.btnp(pyxel.KEY_S) or \ - pyxel.btnp(pyxel.GAMEPAD_1_DOWN): + elif ( + pyxel.btnp(pyxel.KEY_DOWN) + or pyxel.btnp(pyxel.KEY_S) + or pyxel.btnp(pyxel.GAMEPAD1_BUTTON_DPAD_DOWN) + ): self.pressed.append(DOWN) - - if pyxel.btnp(pyxel.KEY_LEFT) or pyxel.btnp(pyxel.KEY_A) or \ - pyxel.btnp(pyxel.GAMEPAD_1_LEFT): + + if ( + pyxel.btnp(pyxel.KEY_LEFT) + or pyxel.btnp(pyxel.KEY_A) + or pyxel.btnp(pyxel.GAMEPAD1_BUTTON_DPAD_LEFT) + ): self.pressed.append(LEFT) - elif pyxel.btnp(pyxel.KEY_RIGHT) or pyxel.btnp(pyxel.KEY_D) or \ - pyxel.btnp(pyxel.GAMEPAD_1_RIGHT): + elif ( + pyxel.btnp(pyxel.KEY_RIGHT) + or pyxel.btnp(pyxel.KEY_D) + or pyxel.btnp(pyxel.GAMEPAD1_BUTTON_DPAD_RIGHT) + ): self.pressed.append(RIGHT) - - if pyxel.btnp(pyxel.KEY_Z) or pyxel.btnp(pyxel.KEY_K) or \ - pyxel.btnp(pyxel.GAMEPAD_1_A): + + if ( + pyxel.btnp(pyxel.KEY_Z) + or pyxel.btnp(pyxel.KEY_K) + or pyxel.btnp(pyxel.KEY_SPACE) + or pyxel.btnp(pyxel.GAMEPAD1_BUTTON_A) + ): self.pressed.append(BUTTON_A) - - if pyxel.btnp(pyxel.KEY_X) or pyxel.btnp(pyxel.KEY_L) or \ - pyxel.btnp(pyxel.GAMEPAD_1_B): + + if ( + pyxel.btnp(pyxel.KEY_X) + or pyxel.btnp(pyxel.KEY_L) + or pyxel.btnp(pyxel.GAMEPAD1_BUTTON_B) + ): self.pressed.append(BUTTON_B) - - if pyxel.btnp(pyxel.KEY_ENTER) or \ - pyxel.btnp(pyxel.GAMEPAD_1_START): + + if pyxel.btnp(pyxel.KEY_RETURN) or pyxel.btnp(pyxel.GAMEPAD1_BUTTON_START): self.pressed.append(BUTTON_START) - - if pyxel.btnp(pyxel.KEY_SPACE) or \ - pyxel.btnp(pyxel.GAMEPAD_1_SELECT): - self.pressed.append(BUTTON_SELECT) - - \ No newline at end of file diff --git a/megaball/light.py b/megaball/light.py index b48f659..0706102 100644 --- a/megaball/light.py +++ b/megaball/light.py @@ -1,4 +1,3 @@ - import pyxel import globals @@ -6,17 +5,18 @@ TICKS_PER_FRAME = 10 MAX_FRAMES = 5 + class Light: def __init__(self, x, y): self.x = x self.y = y - + self.frame = 0 self.frame_ticks = 0 self.anim_dir = 1 - + self.is_hit = False - + def got_hit(self): if self.is_hit == False: self.frame = 4 @@ -24,18 +24,17 @@ def got_hit(self): globals.add_score(globals.SCORE_HIT_LIGHT) return True return False - + def update(self, stage): if not self.is_hit: self.frame_ticks += 1 - + if self.frame_ticks == TICKS_PER_FRAME: self.frame_ticks = 0 self.frame += self.anim_dir - + if self.frame == 0 or self.frame == MAX_FRAMES - 1: self.anim_dir *= -1 - + def draw(self, shake_x, shake_y): - pyxel.blt(shake_x + self.x, shake_y + self.y, 0, 160 + self.frame*8, 0, 8, 8) - \ No newline at end of file + pyxel.blt(shake_x + self.x, shake_y + self.y, 0, 160 + self.frame * 8, 0, 8, 8) diff --git a/megaball/main.py b/megaball/main.py index c360385..36bc5b0 100644 --- a/megaball/main.py +++ b/megaball/main.py @@ -1,36 +1,41 @@ - -import pyxel +# title: Megaball +# author: Adam +# desc: An arcade ball physics game +# site: https://github.com/helpcomputer/megaball +# license: MIT +# version: 1.0 import constants -import input import game +import input +import pyxel + class App: def __init__(self): pyxel.init( - constants.GAME_WIDTH, - constants.GAME_HEIGHT, - caption=constants.GAME_TITLE, - fps=constants.GAME_FPS, - scale=constants.GAME_SCALE + constants.GAME_WIDTH, + constants.GAME_HEIGHT, + title=constants.GAME_TITLE, + fps=constants.GAME_FPS, ) - + pyxel.load(constants.RESOURCE_FILE) - pyxel.image(0).load(0, 0, constants.IMAGE_BANK_0_FILE) + pyxel.images[0].load(0, 0, constants.IMAGE_BANK_0_FILE) self.input = input.Input() self.game = game.Game() pyxel.mouse(False) - #pyxel.mouse(True) + # pyxel.mouse(True) pyxel.run(self.update, self.draw) def update(self): self.input.get() self.game.update(self.input) - + def draw(self): self.game.draw() + App() - \ No newline at end of file diff --git a/megaball/mainmenu.py b/megaball/mainmenu.py index 496a502..5be6d62 100644 --- a/megaball/mainmenu.py +++ b/megaball/mainmenu.py @@ -1,4 +1,3 @@ - import pyxel import utils @@ -13,43 +12,51 @@ SEL_EXIT_GAME = 2 SELECTIONS = { - SEL_START_GAME : [40,87,80,8], # [x, y, w, h] - SEL_PALETTE : [52,103,56,8], - SEL_EXIT_GAME : [44,119,72,8] + SEL_START_GAME: [40, 87, 80, 8], # [x, y, w, h] + SEL_PALETTE: [52, 103, 56, 8], + SEL_EXIT_GAME: [44, 119, 72, 8], } + class MainMenu: def __init__(self, game): self.game = game - + self.is_visible = True - + self.show_press_start = True self.press_start_flash_ticks = 0 self.sel_index = 0 - + def hide(self): self.is_visible = False - + def reset(self): self.is_visible = True self.show_press_start = True self.press_start_flash_ticks = 0 self.sel_index = 0 audio.play_music(audio.MUS_TITLE, True) - + def _pressed_select(self): audio.play_sound(audio.SND_MENU_SELECT) if self.sel_index == SEL_START_GAME: - self.game.add_fade(palette.FADE_STEP_TICKS_DEFAULT, - palette.FADE_LEVEL_6, self.game.start_game) + self.game.add_fade( + palette.FADE_STEP_TICKS_DEFAULT, + palette.FADE_LEVEL_6, + self.game.start_game, + ) elif self.sel_index == SEL_PALETTE: - self.game.add_fade(palette.FADE_STEP_TICKS_DEFAULT, - palette.FADE_LEVEL_6, self.game.cycle_palette) + self.game.add_fade( + palette.FADE_STEP_TICKS_DEFAULT, + palette.FADE_LEVEL_6, + self.game.cycle_palette, + ) elif self.sel_index == SEL_EXIT_GAME: - self.game.add_fade(palette.FADE_STEP_TICKS_DEFAULT, - palette.FADE_LEVEL_0, pyxel.quit) - + self.game.add_fade( + palette.FADE_STEP_TICKS_DEFAULT, palette.FADE_LEVEL_0, pyxel.quit + ) + def _change_selection(self, dir): audio.play_sound(audio.SND_MENU_MOVE) self.sel_index += dir @@ -57,62 +64,77 @@ def _change_selection(self, dir): self.sel_index = len(SELECTIONS) - 1 elif self.sel_index >= len(SELECTIONS): self.sel_index = 0 - + def update(self, last_inputs): if not self.is_visible: return - + if self.show_press_start: self.press_start_flash_ticks += 1 if self.press_start_flash_ticks == 50: self.press_start_flash_ticks = 0 - if input.BUTTON_START in last_inputs.pressed: + if ( + input.BUTTON_START in last_inputs.pressed + or input.BUTTON_A in last_inputs.pressed + ): self.show_press_start = False self.sel_index = 0 else: - if input.BUTTON_A in last_inputs.pressed: + if ( + input.BUTTON_START in last_inputs.pressed + or input.BUTTON_A in last_inputs.pressed + ): self._pressed_select() elif input.UP in last_inputs.pressed: self._change_selection(-1) elif input.DOWN in last_inputs.pressed: self._change_selection(1) - + def draw(self, shake_x, shake_y): if not self.is_visible: return - + if self.show_press_start: if self.press_start_flash_ticks < 30: - pyxel.blt(shake_x + 36, shake_y + 104, 0, 16, 72, 40, 8, 8) # press - pyxel.blt(shake_x + 84, shake_y + 104, 0, 56, 72, 40, 8, 8) # start + pyxel.blt(shake_x + 36, shake_y + 104, 0, 16, 72, 40, 8, 8) # press + pyxel.blt(shake_x + 84, shake_y + 104, 0, 56, 72, 40, 8, 8) # start else: - pyxel.blt(shake_x + 24, shake_y + 84, 0, 0, 144, 116, 52, 8) # panel bg - - pyxel.blt(shake_x + 40, shake_y + 88, 0, 56, 72, 40, 8, 8) # start - pyxel.blt(shake_x + 88, shake_y + 88, 0, 40, 80, 32, 8, 8) # game - - pyxel.blt(shake_x + 52, shake_y + 104, 0, 104, 80, 56, 8, 8) # palette - - pyxel.blt(shake_x + 44, shake_y + 120, 0, 96, 72, 32, 8, 8) # exit - pyxel.blt(shake_x + 84, shake_y + 120, 0, 40, 80, 32, 8, 8) # game - + pyxel.blt(shake_x + 24, shake_y + 84, 0, 0, 144, 116, 52, 8) # panel bg + + pyxel.blt(shake_x + 40, shake_y + 88, 0, 56, 72, 40, 8, 8) # start + pyxel.blt(shake_x + 88, shake_y + 88, 0, 40, 80, 32, 8, 8) # game + + pyxel.blt(shake_x + 52, shake_y + 104, 0, 104, 80, 56, 8, 8) # palette + + pyxel.blt(shake_x + 44, shake_y + 120, 0, 96, 72, 32, 8, 8) # exit + pyxel.blt(shake_x + 84, shake_y + 120, 0, 40, 80, 32, 8, 8) # game + pyxel.blt( - shake_x + SELECTIONS[self.sel_index][0]-12, - shake_y + SELECTIONS[self.sel_index][1], - 0, - 16, 33, 9, 9, 8 - ) # selection ball left + shake_x + SELECTIONS[self.sel_index][0] - 12, + shake_y + SELECTIONS[self.sel_index][1], + 0, + 16, + 33, + 9, + 9, + 8, + ) # selection ball left pyxel.blt( - shake_x + SELECTIONS[self.sel_index][0] + SELECTIONS[self.sel_index][2] + 2, - shake_y + SELECTIONS[self.sel_index][1], - 0, - 16, 33, 9, 9, 8 - ) # selection ball right - - pyxel.blt(shake_x + 44, shake_y + 20, 0, 16, 80, 24, 8, 8) # hi- - utils.draw_number_shadowed(shake_x + 68, shake_y + 20, - globals.g_highscore, zeropad=6) # highscore number - pyxel.blt(shake_x + 13, shake_y + 36, 0, 16, 88, 135, 44, 8) # logo - - - \ No newline at end of file + shake_x + + SELECTIONS[self.sel_index][0] + + SELECTIONS[self.sel_index][2] + + 2, + shake_y + SELECTIONS[self.sel_index][1], + 0, + 16, + 33, + 9, + 9, + 8, + ) # selection ball right + + pyxel.blt(shake_x + 44, shake_y + 20, 0, 16, 80, 24, 8, 8) # hi- + utils.draw_number_shadowed( + shake_x + 68, shake_y + 20, globals.g_highscore, zeropad=6 + ) # highscore number + pyxel.blt(shake_x + 13, shake_y + 36, 0, 16, 88, 135, 44, 8) # logo diff --git a/megaball/palette.py b/megaball/palette.py index 38292ae..d5ecede 100644 --- a/megaball/palette.py +++ b/megaball/palette.py @@ -1,29 +1,22 @@ - import pyxel NUM_COLOURS = 4 -DEFAULT = [ pyxel.COLOR_NAVY, pyxel.COLOR_GREEN, pyxel.COLOR_LIME, pyxel.COLOR_WHITE ] -RED = [ pyxel.COLOR_PURPLE, pyxel.COLOR_RED, pyxel.COLOR_PINK, pyxel.COLOR_WHITE ] -BLUE = [ pyxel.COLOR_NAVY, pyxel.COLOR_DARKBLUE, pyxel.COLOR_CYAN, pyxel.COLOR_WHITE ] -BROWN = [ pyxel.COLOR_BROWN, pyxel.COLOR_ORANGE, pyxel.COLOR_PEACH, pyxel.COLOR_WHITE ] -GREY = [ pyxel.COLOR_BLACK, pyxel.COLOR_DARKBLUE, pyxel.COLOR_GRAY, pyxel.COLOR_WHITE ] - -ALL = [ - DEFAULT, - RED, - BLUE, - BROWN, - GREY -] +DEFAULT = [pyxel.COLOR_NAVY, pyxel.COLOR_GREEN, pyxel.COLOR_LIME, pyxel.COLOR_WHITE] +RED = [pyxel.COLOR_PURPLE, pyxel.COLOR_RED, pyxel.COLOR_PINK, pyxel.COLOR_WHITE] +BLUE = [pyxel.COLOR_NAVY, pyxel.COLOR_DARK_BLUE, pyxel.COLOR_CYAN, pyxel.COLOR_WHITE] +BROWN = [pyxel.COLOR_BROWN, pyxel.COLOR_ORANGE, pyxel.COLOR_PEACH, pyxel.COLOR_WHITE] +GREY = [pyxel.COLOR_BLACK, pyxel.COLOR_DARK_BLUE, pyxel.COLOR_GRAY, pyxel.COLOR_WHITE] -FADE_LEVEL_0 = -3 # all colours to darkest colour. -FADE_LEVEL_1 = -2 # all but brightest to darkest colour. -FADE_LEVEL_2 = -1 # all but two brightest to darkest colour. -FADE_LEVEL_3 = 0 # no modification -FADE_LEVEL_4 = 1 # all but two darkest to brightest colour. -FADE_LEVEL_5 = 2 # all but darkest to brightest colour. -FADE_LEVEL_6 = 3 # all colours to brightest colour. +ALL = [DEFAULT, RED, BLUE, BROWN, GREY] + +FADE_LEVEL_0 = -3 # all colours to darkest colour. +FADE_LEVEL_1 = -2 # all but brightest to darkest colour. +FADE_LEVEL_2 = -1 # all but two brightest to darkest colour. +FADE_LEVEL_3 = 0 # no modification +FADE_LEVEL_4 = 1 # all but two darkest to brightest colour. +FADE_LEVEL_5 = 2 # all but darkest to brightest colour. +FADE_LEVEL_6 = 3 # all colours to brightest colour. FADE_LEVELS = [ FADE_LEVEL_0, @@ -32,51 +25,54 @@ FADE_LEVEL_3, FADE_LEVEL_4, FADE_LEVEL_5, - FADE_LEVEL_6 + FADE_LEVEL_6, ] - + FADE_STEP_TICKS_DEFAULT = 5 FADE_STEP_TICKS_SLOW = 10 - + + class FadeEvent: def __init__(self, ticks_per_level, new_level, callback=None): self.ticks_per_level = ticks_per_level self.ticks = 0 self.new_level = new_level self.callback = callback - + + class FadeControl: def __init__(self): self.current_level = FADE_LEVEL_3 - + self.events = [] - + def add_event(self, ticks_per_level, new_level, callback=None): if ticks_per_level <= 0 or new_level not in FADE_LEVELS: return - + self.events.append(FadeEvent(ticks_per_level, new_level, callback)) - + def get_level(self): return self.current_level - + def update(self): if len(self.events) > 0: e = self.events[0] e.ticks += 1 - + if e.ticks == e.ticks_per_level: e.ticks = 0 if self.current_level < e.new_level: self.current_level += 1 elif self.current_level > e.new_level: self.current_level -= 1 - + if self.current_level == e.new_level: if e.callback is not None: e.callback() self.events.pop(0) + class PaletteEvent: def __init__(self, ticks, new_pal, callback=None): self.ticks = ticks @@ -85,27 +81,28 @@ def __init__(self, ticks, new_pal, callback=None): if new_pal in ALL: self.new_pal = new_pal + class PaletteControl: def __init__(self): self.current_palette = DEFAULT - + self.events = [] - + self.fade_control = FadeControl() - - def add_fade_event(self, ticks_per_level, new_level, callback=None): + + def add_fade_event(self, ticks_per_level, new_level, callback=None): self.fade_control.add_event(ticks_per_level, new_level, callback) - + def add_palette_event(self, ticks, new_pal, callback=None): if ticks <= 0 or new_pal not in ALL: return - - #print("added palette event") + + # print("added palette event") self.events.append(PaletteEvent(ticks, new_pal, callback)) - + def update(self): self.fade_control.update() - + if len(self.events) > 0: e = self.events[0] e.ticks -= 1 @@ -114,22 +111,20 @@ def update(self): if e.callback is not None: e.callback() self.events.pop(0) - - #print("Removed pal event, queue size now: " + str(len(self.events))) - + + # print("Removed pal event, queue size now: " + str(len(self.events))) + def set_pal(self, pal): if pal in ALL: self.current_palette = pal - + def get_pal(self): return self.current_palette - + def get_col(self, index): if index < 0 or index >= NUM_COLOURS: return self.current_palette[0] - - index = max(0, min(NUM_COLOURS-1, index + self.fade_control.get_level())) - + + index = max(0, min(NUM_COLOURS - 1, index + self.fade_control.get_level())) + return self.current_palette[index] - - \ No newline at end of file diff --git a/megaball/player.py b/megaball/player.py index a7d95d5..7ddc63e 100644 --- a/megaball/player.py +++ b/megaball/player.py @@ -1,4 +1,3 @@ - import math import pyxel @@ -29,64 +28,67 @@ STATE_GAME_COMPLETE = 4 STATE_WEAPON = 5 + class Player: def __init__(self, x, y): self.x = x self.y = y - + self.vx = 0 self.vy = 0 - + self.radius = 4 - + self.state = STATE_INTRO - + self.intro_frame = 4 self.dead_frame = 0 - + self.anim_ticks = 0 - + self.weapon = weapon.Weapon() - + def _do_solid_collisions(self, stage): new_x = self.x + self.vx - + for b in stage.solid_rects: - if utils.circle_rect_overlap(new_x, self.y, self.radius, - b[0], b[1], b[2], b[3]): - if self.x > b[0] + b[2]: # was prev to right of border. + if utils.circle_rect_overlap( + new_x, self.y, self.radius, b[0], b[1], b[2], b[3] + ): + if self.x > b[0] + b[2]: # was prev to right of border. new_x = b[0] + b[2] + self.radius - elif self.x < b[0]: # was prev to left of border. + elif self.x < b[0]: # was prev to left of border. new_x = b[0] - self.radius - + self.vx *= -HIT_SOLID_DAMP stage.player_hit_solid() break - + new_y = self.y + self.vy - + for b in stage.solid_rects: - if utils.circle_rect_overlap(self.x, new_y, self.radius, - b[0], b[1], b[2], b[3]): - if self.y > b[1] + b[3]: # was prev below border. + if utils.circle_rect_overlap( + self.x, new_y, self.radius, b[0], b[1], b[2], b[3] + ): + if self.y > b[1] + b[3]: # was prev below border. new_y = b[1] + b[3] + self.radius - elif self.y < b[1]: # was prev above border. + elif self.y < b[1]: # was prev above border. new_y = b[1] - self.radius - + self.vy *= -HIT_SOLID_DAMP stage.player_hit_solid() break - + self.x = new_x self.y = new_y - + def _get_input_angle(self, last_inputs): press_angle = None if input.LEFT in last_inputs.pressing: press_angle = 180 elif input.RIGHT in last_inputs.pressing: press_angle = 0 - + if input.UP in last_inputs.pressing: if press_angle == 0: press_angle = 315 @@ -101,34 +103,36 @@ def _get_input_angle(self, last_inputs): press_angle = 135 else: press_angle = 90 - + return press_angle - + # a "force" is a list of lists: [[speed, angle]... etc]. def _apply_forces(self, forces): for f in forces: - self.vx = max(-MAX_SPEED, - min(MAX_SPEED, - self.vx + f[0] * math.cos(math.radians(f[1])))) - self.vy = max(-MAX_SPEED, - min(MAX_SPEED, - self.vy + f[0] * math.sin(math.radians(f[1])))) - #print("py after: " + str(self.y)) - + self.vx = max( + -MAX_SPEED, + min(MAX_SPEED, self.vx + f[0] * math.cos(math.radians(f[1]))), + ) + self.vy = max( + -MAX_SPEED, + min(MAX_SPEED, self.vy + f[0] * math.sin(math.radians(f[1]))), + ) + # print("py after: " + str(self.y)) + def _get_tile_force(self, stage, forces): angle = stage.get_tile_angle(self.x, self.y) if angle is not None: forces.append([SLOPE_ACCEL, angle]) - #print("Got tile force: spd:{a}, accl:{b}".format(a=SLOPE_ACCEL, b=angle)) - + # print("Got tile force: spd:{a}, accl:{b}".format(a=SLOPE_ACCEL, b=angle)) + def _is_stuck_in_pocket(self, stage): if abs(self.vx) > 0.01 or abs(self.vy) > 0.01: return False - + for p in stage.pockets: if rect.contains_point(p[0], p[1], p[2], p[3], self.x, self.y): return True - + def _do_enemy_collisions(self, stage): for s in stage.spinners: if s.is_dead: @@ -137,7 +141,7 @@ def _do_enemy_collisions(self, stage): self.state = STATE_DEAD stage.player_hit() return - + def _do_light_collisions(self, stage): for s in stage.lights: if rect.contains_point(s.x, s.y, 8, 8, self.x, self.y): @@ -147,21 +151,21 @@ def _do_light_collisions(self, stage): self.state = STATE_STAGE_COMPLETE globals.add_score(globals.SCORE_STAGE_COMPLETE) return - + def fire_weapon(self, stage): self.weapon.fire(self.x, self.y) self.state = STATE_WEAPON globals.g_lives -= 1 stage.player_used_weapon() globals.add_score(globals.SCORE_USE_WEAPON) - + def weapon_done(self): self.state = STATE_INTRO self.intro_frame = 4 self.anim_ticks = 0 self.vx = 0 self.vy = 0 - + def update(self, stage, last_inputs): if self.state == STATE_INTRO: self.anim_ticks += 1 @@ -169,7 +173,7 @@ def update(self, stage, last_inputs): self.anim_ticks = 0 if self.intro_frame > -1: self.intro_frame -= 1 - + if self.intro_frame == -1: self.intro_frame = 4 self.state = STATE_PLAY @@ -179,10 +183,10 @@ def update(self, stage, last_inputs): self.anim_ticks += 1 if self.anim_ticks == DEAD_TICKS_PER_FRAME: self.anim_ticks = 0 - + if self.dead_frame < 11: self.dead_frame += 1 - + if self.dead_frame == 11: stage.player_death_anim_done() return @@ -191,66 +195,90 @@ def update(self, stage, last_inputs): elif self.state == STATE_WEAPON: self.weapon.update(self, stage) return - + forces = [] - - #print("py after: " + str(self.y)) - + + # print("py after: " + str(self.y)) + input_angle = self._get_input_angle(last_inputs) if input_angle is not None: forces.append([ACCEL, input_angle]) - + if not self._is_stuck_in_pocket(stage): self._get_tile_force(stage, forces) - + self._apply_forces(forces) - + if self.vx > 0: self.vx = max(0, self.vx - DECEL) elif self.vx < 0: self.vx = min(0, self.vx + DECEL) - + if self.vy > 0: self.vy = max(0, self.vy - DECEL) elif self.vy < 0: self.vy = min(0, self.vy + DECEL) - - #print("vx,vy: {a},{b}".format(a=self.vx, b=self.vy)) - + + # print("vx,vy: {a},{b}".format(a=self.vx, b=self.vy)) + self._do_solid_collisions(stage) - + self._do_enemy_collisions(stage) - + if self.state != STATE_DEAD and self.state != STATE_GAME_COMPLETE: self._do_light_collisions(stage) - if input.BUTTON_A in last_inputs.pressed and \ - self.state != STATE_WEAPON and \ - globals.g_lives > 0: + if ( + input.BUTTON_A in last_inputs.pressed + and self.state != STATE_WEAPON + and globals.g_lives > 0 + ): self.fire_weapon(stage) - - #print("py after: " + str(self.y)) - - #if pyxel.mouse_x >= 8 and pyxel.mouse_x < 152 and \ + + # print("py after: " + str(self.y)) + + # if pyxel.mouse_x >= 8 and pyxel.mouse_x < 152 and \ # pyxel.mouse_y >= 16 and pyxel.mouse_y < 136: # ang = stage.get_tile_angle(pyxel.mouse_x, pyxel.mouse_y) - #if ang is not None: - # print("Hit slope angle {a},{b}: ".format(a=pyxel.mouse_x,b=pyxel.mouse_y)\ - # + str(ang) + ", " + str(pyxel.frame_count)) - - + # if ang is not None: + # print("Hit slope angle {a},{b}: ".format(a=pyxel.mouse_x,b=pyxel.mouse_y)\ + # + str(ang) + ", " + str(pyxel.frame_count)) + def draw(self, shake_x, shake_y): - if self.state == STATE_INTRO: - pyxel.blt(shake_x + self.x-10, shake_y + self.y-10, 0, - self.intro_frame*21, 231, 21, 21, 8) + if self.state == STATE_INTRO: + pyxel.blt( + shake_x + self.x - 10, + shake_y + self.y - 10, + 0, + self.intro_frame * 21, + 231, + 21, + 21, + 8, + ) elif self.state == STATE_DEAD: - pyxel.blt(shake_x + self.x-10, shake_y + self.y-10, 0, - self.dead_frame*21, 231, 21, 21, 8) + pyxel.blt( + shake_x + self.x - 10, + shake_y + self.y - 10, + 0, + self.dead_frame * 21, + 231, + 21, + 21, + 8, + ) elif self.state == STATE_WEAPON: self.weapon.draw(shake_x, shake_y) else: - pyxel.blt(shake_x + self.x-self.radius, shake_y + self.y-self.radius, 0, - 16, 33, 9, 9, 8) - - #pyxel.circb(self.x, self.y, self.radius, 8) - \ No newline at end of file + pyxel.blt( + shake_x + self.x - self.radius, + shake_y + self.y - self.radius, + 0, + 16, + 33, + 9, + 9, + 8, + ) + + # pyxel.circb(self.x, self.y, self.radius, 8) diff --git a/megaball/rect.py b/megaball/rect.py index e6c854e..3ec8213 100644 --- a/megaball/rect.py +++ b/megaball/rect.py @@ -1,15 +1,10 @@ - def overlap(x1, y1, w1, h1, x2, y2, w2, h2): - return x1 < x2 + w2 and \ - x1 + w1 > x2 and \ - y1 < y2 + h2 and \ - y1 + h1 > y2 - + return x1 < x2 + w2 and x1 + w1 > x2 and y1 < y2 + h2 and y1 + h1 > y2 + + def contains_point(x, y, w, h, px, py): - return x <= px and \ - x + w >= px and \ - y <= py and \ - y + h >= py + return x <= px and x + w >= px and y <= py and y + h >= py + class Rect: def __init__(self, x, y, w, h): @@ -17,16 +12,19 @@ def __init__(self, x, y, w, h): self.y = y self.w = w self.h = h - + def is_overlapping(self, x, y, w, h): - return self.x < x + w and \ - self.x + self.w > x and \ - self.y < y + h and \ - self.y + self.h > y - + return ( + self.x < x + w + and self.x + self.w > x + and self.y < y + h + and self.y + self.h > y + ) + def is_overlapping_other(self, other): - return self.x < other.x + other.w and \ - self.x + self.w > other.x and \ - self.y < other.y + other.h and \ - self.y + self.h > other.y - \ No newline at end of file + return ( + self.x < other.x + other.w + and self.x + self.w > other.x + and self.y < other.y + other.h + and self.y + self.h > other.y + ) diff --git a/megaball/screenshake.py b/megaball/screenshake.py index c741761..2e8d97e 100644 --- a/megaball/screenshake.py +++ b/megaball/screenshake.py @@ -1,29 +1,30 @@ - import random + class Event: def __init__(self, ticks, mag): self.ticks = ticks self.magnitude = mag + class ScreenShake: def __init__(self, game): self.game = game - + self.x = 0 self.y = 0 - + self.events = [] - + def add_event(self, ticks, magnitude, queue=False): if ticks < 0 or magnitude <= 0: return - + if len(self.events) > 0 and not queue: return self.events.append(Event(ticks, magnitude)) - + def update(self): if len(self.events) > 0: e = self.events[0] @@ -35,4 +36,3 @@ def update(self): else: self.x = random.randint(-e.magnitude, e.magnitude) self.y = random.randint(-e.magnitude, e.magnitude) - \ No newline at end of file diff --git a/megaball/spinner.py b/megaball/spinner.py index da7aa14..ae55110 100644 --- a/megaball/spinner.py +++ b/megaball/spinner.py @@ -1,4 +1,3 @@ - import random import pyxel @@ -11,18 +10,14 @@ TYPE_RANDOM_SLOW = 2 TYPE_RANDOM_FAST = 3 -TYPES = [ - TYPE_AGGRESSIVE, - TYPE_MILD, - TYPE_RANDOM_SLOW, - TYPE_RANDOM_FAST -] +TYPES = [TYPE_AGGRESSIVE, TYPE_MILD, TYPE_RANDOM_SLOW, TYPE_RANDOM_FAST] TICKS_PER_FRAME = 10 MAX_FRAME = 4 MAX_SPEED = 0.4 -MAX_RESPAWN_TICKS = 300 # 5 secs +MAX_RESPAWN_TICKS = 300 # 5 secs + class Spinner: def __init__(self, x, y, type): @@ -31,19 +26,19 @@ def __init__(self, x, y, type): self.type = 2 if type in TYPES: self.type = type - + self.vx = random.choice([-MAX_SPEED, MAX_SPEED]) self.vy = random.choice([-MAX_SPEED, MAX_SPEED]) - + self.radius = 4 - + self.frame = 0 self.frame_ticks = 0 - + self.is_dead = False - + self.respawn_ticks = MAX_RESPAWN_TICKS - + def _set_new_position(self, stageObj): px = stageObj.player.x py = stageObj.player.y @@ -52,7 +47,7 @@ def _set_new_position(self, stageObj): stage.SPAWN_SECTOR_TOPLEFT, stage.SPAWN_SECTOR_BOTTOMLEFT, stage.SPAWN_SECTOR_TOPRIGHT, - stage.SPAWN_SECTOR_BOTTOMRIGHT + stage.SPAWN_SECTOR_BOTTOMRIGHT, ] if px < 80: if py < 75: @@ -64,48 +59,50 @@ def _set_new_position(self, stageObj): loclist.remove(stage.SPAWN_SECTOR_TOPRIGHT) else: loclist.remove(stage.SPAWN_SECTOR_BOTTOMRIGHT) - + loc = stageObj.get_random_spawn_loc(random.choice(loclist)) self.x = loc[0] self.y = loc[1] - + def kill(self): self.is_dead = True self.respawn_ticks = MAX_RESPAWN_TICKS - + def _do_collisions(self, stage): new_x = self.x + self.vx - + for b in stage.solid_rects: - if utils.circle_rect_overlap(new_x, self.y, self.radius, - b[0], b[1], b[2], b[3]): - if self.x > b[0] + b[2]: # was prev to right of border. + if utils.circle_rect_overlap( + new_x, self.y, self.radius, b[0], b[1], b[2], b[3] + ): + if self.x > b[0] + b[2]: # was prev to right of border. new_x = b[0] + b[2] + self.radius - elif self.x < b[0]: # was prev to left of border. + elif self.x < b[0]: # was prev to left of border. new_x = b[0] - self.radius - + self.vx *= -1 break - + new_y = self.y + self.vy - + for b in stage.solid_rects: - if utils.circle_rect_overlap(self.x, new_y, self.radius, - b[0], b[1], b[2], b[3]): - if self.y > b[1] + b[3]: # was prev below border. + if utils.circle_rect_overlap( + self.x, new_y, self.radius, b[0], b[1], b[2], b[3] + ): + if self.y > b[1] + b[3]: # was prev below border. new_y = b[1] + b[3] + self.radius - elif self.y < b[1]: # was prev above border. + elif self.y < b[1]: # was prev above border. new_y = b[1] - self.radius - + self.vy *= -1 break - + self.x = new_x self.y = new_y - + def respawn(self): self.is_dead = False - + def update(self, stage): if self.is_dead: self.respawn_ticks -= 1 @@ -115,14 +112,14 @@ def update(self, stage): self._set_new_position(stage) else: self._do_collisions(stage) - + self.frame_ticks += 1 if self.frame_ticks == TICKS_PER_FRAME: self.frame_ticks = 0 self.frame += 1 if self.frame == MAX_FRAME: self.frame = 0 - + def draw(self, shake_x, shake_y): if self.is_dead: framex = None @@ -134,23 +131,23 @@ def draw(self, shake_x, shake_y): framex = 84 if framex is not None: pyxel.blt( - self.x + shake_x - 10, - self.y + shake_y - 10, - 0, - framex, - 231, - 21, 21, - 8 + self.x + shake_x - 10, + self.y + shake_y - 10, + 0, + framex, + 231, + 21, + 21, + 8, ) else: pyxel.blt( - self.x + shake_x - 4, - self.y + shake_y - 4, - 0, - 160 + self.frame*9, - 8, - 9, 9, - 8 + self.x + shake_x - 4, + self.y + shake_y - 4, + 0, + 160 + self.frame * 9, + 8, + 9, + 9, + 8, ) - - \ No newline at end of file diff --git a/megaball/stage.py b/megaball/stage.py index 40debf3..bc6de7a 100644 --- a/megaball/stage.py +++ b/megaball/stage.py @@ -1,21 +1,19 @@ - import math import random -import pyxel - -import player -import utils +import audio import constants -import stage -import light -import input import game +import globals +import input +import light import palette +import player +import pyxel import spinner -import globals +import stage import stagedata -import audio +import utils MAX_STAGE_NUM = 15 @@ -26,102 +24,119 @@ # tile_index : [angle, collision matrix if triangle] SLOPE_TILES = { - utils.get_tile_index(56,32): [225, constants.COLLIDE_BOTTOM_RIGHT], # top-left - utils.get_tile_index(64,32): [270, None], # top - utils.get_tile_index(72,32): [315, constants.COLLIDE_BOTTOM_LEFT], # top-right - utils.get_tile_index(56,40): [180, None], # left - utils.get_tile_index(72,40): [0, None], # right - utils.get_tile_index(56,48): [135, constants.COLLIDE_TOP_RIGHT], # bottom-left - utils.get_tile_index(64,48): [90, None], # bottom - utils.get_tile_index(72,48): [45, constants.COLLIDE_TOP_LEFT], # bottom-right - utils.get_tile_index(80,32): [225, constants.COLLIDE_TOP_LEFT], # top-left 2 - utils.get_tile_index(88,32): [135, constants.COLLIDE_BOTTOM_LEFT], # bottom-left 2 - utils.get_tile_index(80,40): [45, constants.COLLIDE_BOTTOM_RIGHT], # bottom-right 2 - utils.get_tile_index(88,40): [315, constants.COLLIDE_TOP_RIGHT] # top-right 2 - #utils.get_tile_index(), + utils.get_tile_index(56, 32): [225, constants.COLLIDE_BOTTOM_RIGHT], # top-left + utils.get_tile_index(64, 32): [270, None], # top + utils.get_tile_index(72, 32): [315, constants.COLLIDE_BOTTOM_LEFT], # top-right + utils.get_tile_index(56, 40): [180, None], # left + utils.get_tile_index(72, 40): [0, None], # right + utils.get_tile_index(56, 48): [135, constants.COLLIDE_TOP_RIGHT], # bottom-left + utils.get_tile_index(64, 48): [90, None], # bottom + utils.get_tile_index(72, 48): [45, constants.COLLIDE_TOP_LEFT], # bottom-right + utils.get_tile_index(80, 32): [225, constants.COLLIDE_TOP_LEFT], # top-left 2 + utils.get_tile_index(88, 32): [135, constants.COLLIDE_BOTTOM_LEFT], # bottom-left 2 + utils.get_tile_index(80, 40): [ + 45, + constants.COLLIDE_BOTTOM_RIGHT, + ], # bottom-right 2 + utils.get_tile_index(88, 40): [315, constants.COLLIDE_TOP_RIGHT], # top-right 2 + # utils.get_tile_index(), } -POCKET_TILE_NW = utils.get_tile_index(80,40) -POCKET_TILE_NE = utils.get_tile_index(88,32) -POCKET_TILE_SE = utils.get_tile_index(80,32) -POCKET_TILE_SW = utils.get_tile_index(88,40) +POCKET_TILE_NW = utils.get_tile_index(80, 40) +POCKET_TILE_NE = utils.get_tile_index(88, 32) +POCKET_TILE_SE = utils.get_tile_index(80, 32) +POCKET_TILE_SW = utils.get_tile_index(88, 40) -LIGHT_TILE = utils.get_tile_index(160,0) -BLANK_TILE = utils.get_tile_index(32,24) +LIGHT_TILE = utils.get_tile_index(160, 0) +BLANK_TILE = utils.get_tile_index(32, 24) -class PauseMenu: +class PauseMenu: SEL_RESUME = 0 SEL_PALETTE = 1 SEL_QUIT = 2 - + SELECTIONS = { - SEL_RESUME : [56,55,48,8], - SEL_PALETTE : [52,71,56,8], - SEL_QUIT : [64,87,32,8] + SEL_RESUME: [56, 55, 48, 8], + SEL_PALETTE: [52, 71, 56, 8], + SEL_QUIT: [64, 87, 32, 8], } def __init__(self, stage): self.stage = stage - + self.is_visible = False - + self.sel_index = 0 - + self.quitting = False - + def _pressed_select(self): if self.sel_index == self.SEL_RESUME: self.is_visible = False elif self.sel_index == self.SEL_PALETTE: - self.stage.game.add_fade(5, palette.FADE_LEVEL_6, self.stage.game.cycle_palette) + self.stage.game.add_fade( + 5, palette.FADE_LEVEL_6, self.stage.game.cycle_palette + ) elif self.sel_index == self.SEL_QUIT: self.quitting = True self.stage.quit() - + def _change_selection(self, dir): self.sel_index += dir if self.sel_index < 0: self.sel_index = len(self.SELECTIONS) - 1 elif self.sel_index >= len(self.SELECTIONS): self.sel_index = 0 - + def update(self, last_inputs): if not self.is_visible or self.quitting: return - - if input.BUTTON_START in last_inputs.pressed: - self.is_visible = False - self.sel_index = 0 - elif input.BUTTON_A in last_inputs.pressed: + + if ( + input.BUTTON_START in last_inputs.pressed + or input.BUTTON_A in last_inputs.pressed + ): self._pressed_select() elif input.UP in last_inputs.pressed: self._change_selection(-1) elif input.DOWN in last_inputs.pressed: - self._change_selection(1) - + self._change_selection(1) + def draw(self, shake_x, shake_y): if not self.is_visible: return - - pyxel.blt(shake_x + 24, shake_y + 52, 0, 0, 144, 116, 52, 8) # panel bg - - pyxel.blt(shake_x + 56, shake_y + 56, 0, 128, 72, 48, 8, 8) # resume - pyxel.blt(shake_x + 52, shake_y + 72, 0, 104, 80, 56, 8, 8) # palette - pyxel.blt(shake_x + 64, shake_y + 88, 0, 96, 64, 32, 8, 8) # quit - + + pyxel.blt(shake_x + 24, shake_y + 52, 0, 0, 144, 116, 52, 8) # panel bg + + pyxel.blt(shake_x + 56, shake_y + 56, 0, 128, 72, 48, 8, 8) # resume + pyxel.blt(shake_x + 52, shake_y + 72, 0, 104, 80, 56, 8, 8) # palette + pyxel.blt(shake_x + 64, shake_y + 88, 0, 96, 64, 32, 8, 8) # quit + pyxel.blt( - shake_x + self.SELECTIONS[self.sel_index][0]-12, - shake_y + self.SELECTIONS[self.sel_index][1], - 0, - 16, 33, 9, 9, 8 - ) # selection ball left + shake_x + self.SELECTIONS[self.sel_index][0] - 12, + shake_y + self.SELECTIONS[self.sel_index][1], + 0, + 16, + 33, + 9, + 9, + 8, + ) # selection ball left pyxel.blt( - shake_x + self.SELECTIONS[self.sel_index][0] + self.SELECTIONS[self.sel_index][2] + 2, - shake_y + self.SELECTIONS[self.sel_index][1], - 0, - 16, 33, 9, 9, 8 - ) # selection ball right + shake_x + + self.SELECTIONS[self.sel_index][0] + + self.SELECTIONS[self.sel_index][2] + + 2, + shake_y + self.SELECTIONS[self.sel_index][1], + 0, + 16, + 33, + 9, + 9, + 8, + ) # selection ball right + STATE_INTRO = 0 STATE_PLAY = 1 @@ -132,14 +147,15 @@ def draw(self, shake_x, shake_y): STATE_GAME_COMPLETE = 6 STATE_PLAYER_WEAPON = 7 -MAX_SHOW_GAME_OVER_TICKS = 300 # 5 secs -MAX_SHOW_GAME_COMPLETE_TICKS = 300 # 5 secs +MAX_SHOW_GAME_OVER_TICKS = 300 # 5 secs +MAX_SHOW_GAME_COMPLETE_TICKS = 300 # 5 secs SPAWN_SECTOR_TOPLEFT = 0 SPAWN_SECTOR_TOPRIGHT = 1 SPAWN_SECTOR_BOTTOMLEFT = 2 SPAWN_SECTOR_BOTTOMRIGHT = 3 + class Stage: def __init__(self, game, num): self.game = game @@ -147,7 +163,7 @@ def __init__(self, game, num): self.tm = 0 self.tmu = 0 self.tmv = num * 16 - + self.state = STATE_INTRO if self.num <= 0: self.state = STATE_DEMO @@ -156,54 +172,62 @@ def __init__(self, game, num): self.tmu = 0 self.tmv = 0 self.state = STATE_GAME_COMPLETE - + self.solid_rects = [ - [0, 0, 160, 16], # [x, y, w, h] + [0, 0, 160, 16], # [x, y, w, h] [0, 16, 8, 128], [152, 16, 8, 128], - [0, 136, 160, 8] + [0, 136, 160, 8], ] - - self.slopes = [] # [x, y] - self.pockets = [] # [x, y, w, h] - self.lights = [] # Light objects - self.spinners = [] # Spinner objects - - self.en_spawn_locs_topleft = [] # [[x,y],[x,y],[x,y]...] - self.en_spawn_locs_topright = [] # [[x,y],[x,y],[x,y]...] - self.en_spawn_locs_bottomleft = [] # [[x,y],[x,y],[x,y]...] - self.en_spawn_locs_bottomright = [] # [[x,y],[x,y],[x,y]...] - + + self.slopes = [] # [x, y] + self.pockets = [] # [x, y, w, h] + self.lights = [] # Light objects + self.spinners = [] # Spinner objects + + self.en_spawn_locs_topleft = [] # [[x,y],[x,y],[x,y]...] + self.en_spawn_locs_topright = [] # [[x,y],[x,y],[x,y]...] + self.en_spawn_locs_bottomleft = [] # [[x,y],[x,y],[x,y]...] + self.en_spawn_locs_bottomright = [] # [[x,y],[x,y],[x,y]...] + if self.state != STATE_GAME_COMPLETE: for yc in range(HEIGHT_TILES): y = self.tmv + yc for xc in range(WIDTH_TILES): x = self.tmu + xc - tile = pyxel.tilemap(self.tm).get(x, y) + tile = pyxel.tilemaps[self.tm].pget(x, y) if tile == POST_TILE: - self.solid_rects.append([xc*8 + 8, yc*8 + 16, 8, 8]) + self.solid_rects.append([xc * 8 + 8, yc * 8 + 16, 8, 8]) elif tile in SLOPE_TILES: - self.slopes.append([xc*8 + 8, yc*8 + 16]) + self.slopes.append([xc * 8 + 8, yc * 8 + 16]) elif tile == LIGHT_TILE: - self.lights.append(light.Light(xc*8 + 8, yc*8 + 16)) - + self.lights.append(light.Light(xc * 8 + 8, yc * 8 + 16)) + if tile == POCKET_TILE_NW: - if x < self.tmu + WIDTH_TILES-1 and y < self.tmv + HEIGHT_TILES-1: - if pyxel.tilemap(self.tm).get(x+1, y) == POCKET_TILE_NE and\ - pyxel.tilemap(self.tm).get(x+1, y+1) == POCKET_TILE_SE and\ - pyxel.tilemap(self.tm).get(x, y+1) == POCKET_TILE_SW: - self.pockets.append([xc*8 + 8, yc*8 + 16, 16, 16]) - - if tile != POST_TILE and \ - xc > 0 and \ - xc < WIDTH_TILES-1 and \ - yc > 0 and \ - yc < HEIGHT_TILES-1 and \ - (xc < 5 or xc > WIDTH_TILES-6) and \ - (yc < 5 or yc > HEIGHT_TILES-6): - - loc = [xc*8 + 8 + 4, yc*8 + 16 + 4] - + if ( + x < self.tmu + WIDTH_TILES - 1 + and y < self.tmv + HEIGHT_TILES - 1 + ): + if ( + pyxel.tilemaps[self.tm].pget(x + 1, y) == POCKET_TILE_NE + and pyxel.tilemaps[self.tm].pget(x + 1, y + 1) + == POCKET_TILE_SE + and pyxel.tilemaps[self.tm].pget(x, y + 1) + == POCKET_TILE_SW + ): + self.pockets.append([xc * 8 + 8, yc * 8 + 16, 16, 16]) + + if ( + tile != POST_TILE + and xc > 0 + and xc < WIDTH_TILES - 1 + and yc > 0 + and yc < HEIGHT_TILES - 1 + and (xc < 5 or xc > WIDTH_TILES - 6) + and (yc < 5 or yc > HEIGHT_TILES - 6) + ): + loc = [xc * 8 + 8 + 4, yc * 8 + 16 + 4] + if xc < 9: if yc < 7: self.en_spawn_locs_topleft.append(loc) @@ -215,7 +239,7 @@ def __init__(self, game, num): else: self.en_spawn_locs_bottomright.append(loc) - #print(self.pockets) + # print(self.pockets) num_spinners = 0 stage_diff_name = stagedata.STAGE_DIFFICULTY[self.num] for i in range(len(spinner.TYPES)): @@ -223,25 +247,25 @@ def __init__(self, game, num): for sq in range(en_qty): loc = self.get_random_spawn_loc(-1) self.spinners.append(spinner.Spinner(loc[0], loc[1], i)) - - self.player = player.Player(75,75)#(12, 20) + + self.player = player.Player(75, 75) # (12, 20) if self.state == STATE_GAME_COMPLETE: self.player.state = player.STATE_GAME_COMPLETE audio.play_music(audio.MUS_IN_GAME, True) else: if self.state != STATE_DEMO: audio.play_music(audio.MUS_START, False) - + self.pause_menu = PauseMenu(self) - + self.stage_over_ticks = 0 - + self.next_stage_flash_num = 0 - + def restart_music(self): if self.state == STATE_PLAY: audio.play_music(audio.MUS_IN_GAME) - + def get_random_spawn_loc(self, sector): if sector == SPAWN_SECTOR_TOPLEFT: return random.choice(self.en_spawn_locs_topleft) @@ -252,133 +276,154 @@ def get_random_spawn_loc(self, sector): elif sector == SPAWN_SECTOR_BOTTOMRIGHT: return random.choice(self.en_spawn_locs_bottomright) else: - ranlist = random.choice([ - self.en_spawn_locs_topleft, - self.en_spawn_locs_topright, - self.en_spawn_locs_bottomleft, - self.en_spawn_locs_bottomright - ]) + ranlist = random.choice( + [ + self.en_spawn_locs_topleft, + self.en_spawn_locs_topright, + self.en_spawn_locs_bottomleft, + self.en_spawn_locs_bottomright, + ] + ) return random.choice(ranlist) - + def player_used_weapon(self): audio.play_sound(audio.SND_USED_WEAPON) self.state = STATE_PLAYER_WEAPON - + def player_intro_done(self): if self.state != STATE_PLAYER_WEAPON: audio.play_music(audio.MUS_IN_GAME, True) - + self.state = STATE_PLAY - + def player_hit(self): self.state = STATE_DIED audio.play_music(audio.MUS_DEATH, False) - + def is_complete(self): for i in self.lights: if i.is_hit == False: return False - + audio.play_music(audio.MUS_STAGE_COMPLETE, False) self._check_next_stage() - + return True - + def player_death_anim_done(self): if globals.g_lives >= 1: globals.g_lives -= 1 - self.game.add_fade(palette.FADE_STEP_TICKS_DEFAULT, - palette.FADE_LEVEL_6, self.game.restart_stage) + self.game.add_fade( + palette.FADE_STEP_TICKS_DEFAULT, + palette.FADE_LEVEL_6, + self.game.restart_stage, + ) else: self.state = STATE_GAME_OVER audio.play_music(audio.MUS_GAME_OVER, False) - + def _check_next_stage(self): - #if self.num < MAX_STAGE_NUM: + # if self.num < MAX_STAGE_NUM: self.state = STATE_STAGE_COMPLETE - self.game.add_fade(palette.FADE_STEP_TICKS_DEFAULT, - palette.FADE_LEVEL_0, self.go_to_next_stage) - #else: + self.game.add_fade( + palette.FADE_STEP_TICKS_DEFAULT, palette.FADE_LEVEL_0, self.go_to_next_stage + ) + # else: # self.state = STATE_GAME_COMPLETE - + def go_to_next_stage(self): if self.next_stage_flash_num == 0: - self.game.add_fade(palette.FADE_STEP_TICKS_SLOW, - palette.FADE_LEVEL_3, self.go_to_next_stage) + self.game.add_fade( + palette.FADE_STEP_TICKS_SLOW, + palette.FADE_LEVEL_3, + self.go_to_next_stage, + ) elif self.next_stage_flash_num == 1: - self.game.add_fade(palette.FADE_STEP_TICKS_SLOW, - palette.FADE_LEVEL_0, self.go_to_next_stage) - #elif self.next_stage_flash_num == 2: - # self.game.add_fade(palette.FADE_STEP_TICKS_SLOW, + self.game.add_fade( + palette.FADE_STEP_TICKS_SLOW, + palette.FADE_LEVEL_0, + self.go_to_next_stage, + ) + # elif self.next_stage_flash_num == 2: + # self.game.add_fade(palette.FADE_STEP_TICKS_SLOW, # palette.FADE_LEVEL_3, self.go_to_next_stage) - #elif self.next_stage_flash_num == 3: - # self.game.add_fade(palette.FADE_STEP_TICKS_SLOW, + # elif self.next_stage_flash_num == 3: + # self.game.add_fade(palette.FADE_STEP_TICKS_SLOW, # palette.FADE_LEVEL_0, self.go_to_next_stage) else: if self.num == stage.MAX_STAGE_NUM: - self.game.add_fade(palette.FADE_STEP_TICKS_SLOW, - palette.FADE_LEVEL_6, self.game.go_to_game_complete_stage) + self.game.add_fade( + palette.FADE_STEP_TICKS_SLOW, + palette.FADE_LEVEL_6, + self.game.go_to_game_complete_stage, + ) else: globals.add_lives(1) - self.game.add_fade(palette.FADE_STEP_TICKS_SLOW, - palette.FADE_LEVEL_6, self.game.go_to_next_stage) - + self.game.add_fade( + palette.FADE_STEP_TICKS_SLOW, + palette.FADE_LEVEL_6, + self.game.go_to_next_stage, + ) + self.next_stage_flash_num += 1 - + def quit(self): - self.game.add_fade(palette.FADE_STEP_TICKS_DEFAULT, - palette.FADE_LEVEL_6, self.game.quit_to_main_menu) - + self.game.add_fade( + palette.FADE_STEP_TICKS_DEFAULT, + palette.FADE_LEVEL_6, + self.game.quit_to_main_menu, + ) + def player_hit_solid(self): audio.play_sound(audio.SND_HIT_WALL) self.game.add_screen_shake(5, 1, queue=False) - + # returns None or angle - def get_tile_angle(self, x, y): # x,y is screen pixels. - tile = pyxel.tilemap(self.tm).get( - self.tmu + math.floor((x-8)/8), - self.tmv + math.floor((y-16)/8) + def get_tile_angle(self, x, y): # x,y is screen pixels. + tile = pyxel.tilemaps[self.tm].pget( + self.tmu + math.floor((x - 8) / 8), self.tmv + math.floor((y - 16) / 8) ) - + if tile in SLOPE_TILES: # check if triangle matrix collision check needed. if SLOPE_TILES[tile][1] is not None: t = SLOPE_TILES[tile] - - tx = math.floor(abs(x - math.floor(x/8)*8)) - ty = math.floor(abs(y - math.floor(y/8)*8)) - - #print("Checking matrix x,y: {a},{b} ...".format(a=tx, b=ty)) - + + tx = math.floor(abs(x - math.floor(x / 8) * 8)) + ty = math.floor(abs(y - math.floor(y / 8) * 8)) + + # print("Checking matrix x,y: {a},{b} ...".format(a=tx, b=ty)) + if constants.is_colliding_matrix(tx, ty, t[1]): - #print("{a}, {b} hit triangle".format(a=x, b=y)) - #print("... collides.") + # print("{a}, {b} hit triangle".format(a=x, b=y)) + # print("... collides.") return t[0] else: - #print("... no collision.") + # print("... no collision.") return None else: return SLOPE_TILES[tile][0] else: return None - + def update(self, last_inputs): - if self.num > 0: # dont allow inputs on demo/main menu stage 0. + if self.num > 0: # dont allow inputs on demo/main menu stage 0. if self.pause_menu.is_visible: self.pause_menu.update(last_inputs) else: - if input.BUTTON_START in last_inputs.pressed: - if self.state == STATE_PLAY or \ - self.state == STATE_PLAYER_WEAPON: + if ( + input.BUTTON_START in last_inputs.pressed + or input.BUTTON_B in last_inputs.pressed + ): + if self.state == STATE_PLAY or self.state == STATE_PLAYER_WEAPON: self.pause_menu.is_visible = True else: self.player.update(self, last_inputs) - - if self.state == STATE_PLAY or\ - self.state == STATE_DEMO: + + if self.state == STATE_PLAY or self.state == STATE_DEMO: for s in self.spinners: s.update(self) - + if self.state == STATE_GAME_OVER: self.stage_over_ticks += 1 if self.stage_over_ticks == MAX_SHOW_GAME_OVER_TICKS: @@ -388,34 +433,39 @@ def update(self, last_inputs): if self.stage_over_ticks >= MAX_SHOW_GAME_COMPLETE_TICKS: if input.BUTTON_A in last_inputs.pressed: self.quit() - - if self.state == STATE_PLAY or\ - self.state == STATE_DEMO: + + if self.state == STATE_PLAY or self.state == STATE_DEMO: for i in self.lights: i.update(self) - + def draw(self, shake_x, shake_y): - pyxel.bltm(shake_x + 8, shake_y + 16, self.tm, self.tmu, self.tmv, - WIDTH_TILES, HEIGHT_TILES, 8) - + pyxel.bltm( + shake_x + 8, + shake_y + 16, + self.tm, + self.tmu * 8, + self.tmv * 8, + WIDTH_TILES * 8, + HEIGHT_TILES * 8, + 8, + ) + for i in self.lights: i.draw(shake_x, shake_y) - + if self.state == STATE_GAME_COMPLETE: pyxel.blt(24 + shake_x, 32 + shake_y, 0, 136, 136, 112, 88) - + if self.num > 0: self.player.draw(shake_x, shake_y) - + for s in self.spinners: s.draw(shake_x, shake_y) - + if self.num > 0: self.pause_menu.draw(shake_x, shake_y) - - if self.state == STATE_GAME_OVER and self.stage_over_ticks > 30: - pyxel.blt(32 + shake_x, 66 + shake_y, 0, 0, 196, 100, 26, 8) # game over bg - pyxel.blt(44 + shake_x, 72 + shake_y, 0, 40, 80, 32, 8, 8) # "game" - pyxel.blt(84 + shake_x, 72 + shake_y, 0, 72, 80, 32, 8, 8) # "over" - \ No newline at end of file + if self.state == STATE_GAME_OVER and self.stage_over_ticks > 30: + pyxel.blt(32 + shake_x, 66 + shake_y, 0, 0, 196, 100, 26, 8) # game over bg + pyxel.blt(44 + shake_x, 72 + shake_y, 0, 40, 80, 32, 8, 8) # "game" + pyxel.blt(84 + shake_x, 72 + shake_y, 0, 72, 80, 32, 8, 8) # "over" diff --git a/megaball/stagedata.py b/megaball/stagedata.py index c93848b..119f44d 100644 --- a/megaball/stagedata.py +++ b/megaball/stagedata.py @@ -1,5 +1,4 @@ - -''' +""" Each difficulty has a dictionary: easy : { ... @@ -8,7 +7,7 @@ With that dictionary is another dictionary of quantity of each object type: "spinners" : [personalityA, personalityB, ... etc] -''' +""" SPINNER_KEY = "spinners" DIFF_NONE_KEY = "none" @@ -18,52 +17,42 @@ DIFF_HARD_KEY = "hard" DIFF_VERY_HARD_KEY = "very hard" -#[aggressive, mildly aggressive, slow random, fast random] +# [aggressive, mildly aggressive, slow random, fast random] ENEMIES = { - - DIFF_NONE_KEY : { - SPINNER_KEY : [0,0,0,0] + DIFF_NONE_KEY: {SPINNER_KEY: [0, 0, 0, 0]}, + DIFF_VERY_EASY_KEY: { + SPINNER_KEY: [2, 1, 1, 0] # [1,1,1,0] }, - - DIFF_VERY_EASY_KEY : { - SPINNER_KEY : [2,1,1,0]#[1,1,1,0] + DIFF_EASY_KEY: { + SPINNER_KEY: [2, 1, 2, 0] # [1,1,2,0] }, - - DIFF_EASY_KEY : { - SPINNER_KEY : [2,1,2,0]#[1,1,2,0] + DIFF_MEDIUM_KEY: { + SPINNER_KEY: [3, 1, 1, 1] # [2,1,1,1] }, - - DIFF_MEDIUM_KEY : { - SPINNER_KEY : [3,1,1,1]#[2,1,1,1] + DIFF_HARD_KEY: { + SPINNER_KEY: [3, 1, 1, 2] # [2,1,1,2] }, - - DIFF_HARD_KEY : { - SPINNER_KEY : [3,1,1,2]#[2,1,1,2] + DIFF_VERY_HARD_KEY: { + SPINNER_KEY: [3, 2, 1, 1] # [2,2,1,1] }, - - DIFF_VERY_HARD_KEY : { - SPINNER_KEY : [3,2,1,1]#[2,2,1,1] - } - } STAGE_DIFFICULTY = [ - DIFF_NONE_KEY, # 0 - DIFF_VERY_EASY_KEY, # 1 - DIFF_EASY_KEY, # 2 - DIFF_EASY_KEY, # 3 - DIFF_EASY_KEY, # 4 - DIFF_EASY_KEY, # 5 - DIFF_MEDIUM_KEY, # 6 - DIFF_EASY_KEY, # 7 - DIFF_MEDIUM_KEY, # 8 - DIFF_VERY_EASY_KEY, # 9 - DIFF_VERY_HARD_KEY, # 10 - DIFF_HARD_KEY, # 11 - DIFF_VERY_HARD_KEY, # 12 - DIFF_EASY_KEY, # 13 - DIFF_VERY_HARD_KEY, # 14 - DIFF_VERY_HARD_KEY # 15 + DIFF_NONE_KEY, # 0 + DIFF_VERY_EASY_KEY, # 1 + DIFF_EASY_KEY, # 2 + DIFF_EASY_KEY, # 3 + DIFF_EASY_KEY, # 4 + DIFF_EASY_KEY, # 5 + DIFF_MEDIUM_KEY, # 6 + DIFF_EASY_KEY, # 7 + DIFF_MEDIUM_KEY, # 8 + DIFF_VERY_EASY_KEY, # 9 + DIFF_VERY_HARD_KEY, # 10 + DIFF_HARD_KEY, # 11 + DIFF_VERY_HARD_KEY, # 12 + DIFF_EASY_KEY, # 13 + DIFF_VERY_HARD_KEY, # 14 + DIFF_VERY_HARD_KEY, # 15 ] - diff --git a/megaball/utils.py b/megaball/utils.py index aa91ba6..24a5c79 100644 --- a/megaball/utils.py +++ b/megaball/utils.py @@ -1,87 +1,93 @@ - import math import pyxel + def angle_reflect(incidenceAngle, surfaceAngle): a = surfaceAngle * 2 - incidenceAngle return (a + 360) % 360 + def sign_triangle(p1, p2, p3): return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]) + def is_point_in_triangle(px, py, ax, ay, bx, by, cx, cy): - #print("Checking point [{a},{b}] in tri [{c}][{d}], [{e}][{f}], [{g}][{h}] ({i})".format( + # print("Checking point [{a},{b}] in tri [{c}][{d}], [{e}][{f}], [{g}][{h}] ({i})".format( # a=px, b=py, c=ax, d=ay, e=bx, f=by, g=cx, h=cy, i=pyxel.frame_count - #)) - d1 = sign_triangle([px, py], [ax,ay], [bx,by]) - d2 = sign_triangle([px, py], [bx,by], [cx,cy]) - d3 = sign_triangle([px, py], [cx,cy], [ax,ay]) + # )) + d1 = sign_triangle([px, py], [ax, ay], [bx, by]) + d2 = sign_triangle([px, py], [bx, by], [cx, cy]) + d3 = sign_triangle([px, py], [cx, cy], [ax, ay]) has_neg = (d1 < 0) or (d2 < 0) or (d3 < 0) has_pos = (d1 > 0) or (d2 > 0) or (d3 > 0) - - #print("return: " + str(not(has_neg and has_pos))) - return not(has_neg and has_pos) + # print("return: " + str(not(has_neg and has_pos))) + + return not (has_neg and has_pos) + def circle_rect_overlap(cx, cy, cr, rx, ry, rw, rh): closestX = cx closestY = cy - + if cx < rx: closestX = rx elif cx > rx + rw: closestX = rx + rw - + if cy < ry: closestY = ry elif cy > ry + rh: closestY = ry + rh - + closestX = closestX - cx closestX *= closestX closestY = closestY - cy closestY *= closestY - + return closestX + closestY < cr * cr + def get_angle_deg(x1, y1, x2, y2): degs = math.degrees(math.atan2(y2 - y1, x2 - x1)) return (degs + 360) % 360 + def get_tile_x(index): - return math.floor(index % 32) * 8 - + return index[0] * 8 # math.floor(index % 32) * 8 + + def get_tile_y(index): - return math.floor(index / 32) * 8 + return index[1] * 8 # math.floor(index / 32) * 8 + def get_tile_index(x, y): - return x/8 + (y / 8) * 32 - + return (x // 8, y // 8) # x/8 + (y / 8) * 32 + + def lerp(v, d): - #print("delta: " + str(d) + ", v: " + str(v[0]) + "," + str(v[1])) - #print() + # print("delta: " + str(d) + ", v: " + str(v[0]) + "," + str(v[1])) + # print() return (v[0] * (1.0 - d)) + (v[1] * d) - + + def ease_out_expo(x): if x == 1: return 1 - + return 1 - math.pow(2, -10 * x) - + + def ease_out_cubic(x): return 1 - math.pow(1 - x, 3) - + + def draw_number_shadowed(x, y, num, zeropad=0): strnum = str(num) if zeropad > 0: strnum = strnum.zfill(zeropad) for i in range(len(strnum)): - pyxel.blt(x + i*8, y, 0, 16 + int(strnum[i])*8, 56, 8, 8, 8) - - - - - \ No newline at end of file + pyxel.blt(x + i * 8, y, 0, 16 + int(strnum[i]) * 8, 56, 8, 8, 8) diff --git a/megaball/weapon.py b/megaball/weapon.py index df2f43b..591e3fe 100644 --- a/megaball/weapon.py +++ b/megaball/weapon.py @@ -1,4 +1,3 @@ - import math import pyxel @@ -19,63 +18,59 @@ for i in range(MAX_SHOTS): VEL.append( [ - SHOT_SPEED * math.cos(math.radians(i*36)), - SHOT_SPEED * math.sin(math.radians(i*36)), + SHOT_SPEED * math.cos(math.radians(i * 36)), + SHOT_SPEED * math.sin(math.radians(i * 36)), ] ) + class Weapon: def __init__(self): self.active = False - + self.shots = [] for i in range(MAX_SHOTS): - self.shots.append([0,0]) - + self.shots.append([0, 0]) + def fire(self, from_x, from_y): self.active = True for s in self.shots: s[0] = from_x s[1] = from_y - + def update(self, player, stage): if not self.active: return - + done = True - + for i, s in enumerate(self.shots): s[0] += VEL[i][0] s[1] += VEL[i][1] - - if done != False and\ - rect.contains_point(0, 0, - constants.GAME_WIDTH, constants.GAME_HEIGHT, - s[0], s[1]): + + if done != False and rect.contains_point( + 0, 0, constants.GAME_WIDTH, constants.GAME_HEIGHT, s[0], s[1] + ): done = False - + for spin in stage.spinners: if not spin.is_dead: if circle.overlap( - s[0], s[1], SHOT_RADIUS, - spin.x, spin.y, spin.radius): + s[0], s[1], SHOT_RADIUS, spin.x, spin.y, spin.radius + ): globals.add_score(globals.SCORE_KILLED_SPINNER) spin.kill() - + if done: spinners_killed = sum(s.is_dead == True for s in stage.spinners) if spinners_killed == len(stage.spinners): globals.add_score(globals.SCORE_KILLED_ALL_SPINNERS) self.active = False player.weapon_done() - + def draw(self, shake_x, shake_y): if not self.active: return - + for s in self.shots: - pyxel.blt(shake_x + s[0] - 10, - shake_y + s[1] - 10, - 0, 21, 231, 21, 21, 8) - - \ No newline at end of file + pyxel.blt(shake_x + s[0] - 10, shake_y + s[1] - 10, 0, 21, 231, 21, 21, 8)