예제 #1
0
    def __init__(self, screen):
        super().__init__(screen)
        self.rect = pg.Rect(0, 0, 0, 0)

        self.x1 = 50
        self.y1 = 50
        self.x2 = 50
        self.y2 = 85
        self.spacing = 30

        self.p1Text = TextLabel("P1", 30, "orange", self.x1 - 35, self.y1 + 4,
                                self.screen)
        self.p2Text = TextLabel("P2", 30, "navy_blue", self.x2 - 35,
                                self.y2 + 4, self.screen)

        self._p1HP = None
        self._p1MaxHP = None
        self._p1Lives = []
        self._p2HP = None
        self._p2MaxHP = None
        self._p2Lives = []

        self._audio = AudioComponent(self, isAutoPlay=False, isRepeat=True)
        self._audio.add("healthy", SFX_RESOURCES["menu_heartbeat_healthy"])
        self._audio.add("injured", SFX_RESOURCES["menu_heartbeat_injured"])
        self._audio.add("danger", SFX_RESOURCES["menu_heartbeat_danger"])
예제 #2
0
    def __init__(self, screen):
        super().__init__(screen)
        fontSize = 22
        fontColour = "white"
        x, y = 230, 155
        dx, dy = 0, 50

        self.backgroundSetting = _SettingsLabel("Orientación: ",
                                                ["Vertical", "Horizontal"],
                                                fontSize, fontColour, x, y,
                                                130, screen)
        self.fullscreenSetting = _SettingsLabel("Full Screen: ",
                                                ["Desactivar", "Activar"],
                                                fontSize, fontColour, x,
                                                y + dy, 130, screen)

        self.arrow = _Arrow(x - 40, y - 10, dx, dy, 2, screen)
        self.escapeImage = ImageLabel(MENU_RESOURCES["assets"]["esc"], 25, 440,
                                      screen)
        self.escapeText = TextLabel("Esc para volver", 14, fontColour, 50, 445,
                                    screen)

        self.effect = FadeEffect(self.screen)
        self.effect.timeStartDarken = float('inf')
        self.effect.timeEndDarken = float('inf')
        self.dt = 2

        background = MENU_RESOURCES["screens"]["options"][0]
        self.render = RenderComponent(self)
        self.render.add("background", background)
        self.render.state = "background"

        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("exit", SFX_RESOURCES["menu_exit"])
예제 #3
0
    def __init__(self, settingName, settingChoices, size, colour, x, y,
                 spacing, screen):
        """
        :param settingName: String, the name of the setting.
        :param settingChoices: List, containing string options choices.
        :param size: Integer, the size of the font.
        :param colour: 3-Tuple, containing the RGB values of the colour.
        :param x: Integer, the x-position of the text.
        :param y: Integer, the y-position of the text.
        :param spacing: Integer, the gap between the setting name and choice.
        :param screen: pygame.Surface, representing the screen.
        """
        self.rect = pg.Rect(x, y, 0, 0)
        self.screen = screen

        self.index = 0
        self.optionChosen = None
        self.name = TextLabel(settingName, size, colour, x, y, self.screen)

        self.options = [
            TextLabel(choice, size, colour, x + spacing, y, self.screen)
            for choice in settingChoices
        ]

        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("switch", SFX_RESOURCES["menu_option_switch"])
        self.audio.state = "switch"
예제 #4
0
 def __init__(self, scene):
     """
     :param scene: Scene Class, representing a level.
     """
     self.scene = scene
     self.audio = AudioComponent(self, isAutoPlay=False)
     self.audio.add("explosion", SFX_RESOURCES["cat_coop_jump"])
예제 #5
0
    def __init__(self, x, y, switchNum, screen, zoneArtwork=1):
        """
        :param x: Integer, the x-position of the wall.
        :param y: Integer, the y-position of the wall.
        :param switchNum: Integer, identifying the number of the button.
        :param screen: pygame.Surface, the screen to draw the wall onto.
        :param zoneArtwork: Integer, choosing the image based on zone.
        """
        self.screen = screen
        self.num = switchNum
        self.isOn = True

        # REFACTOR: Clumsy implementation to change image of the renderer
        # - Causes instantiating argument to be needlessly long.
        # - The code below does not scale well.
        if zoneArtwork == 1:
            button = ZONE1_RESOURCES["buttons"]
        if zoneArtwork == 2:
            button = ZONE2_RESOURCES["buttons"]
        self.render = RenderComponent(self, enableRepeat=False)
        self.render.add("on", [button["switch"][0]])
        self.render.add("off", button["switch"], 500)
        self.render.state = "on"
        self.rect = pg.Rect(x, y, 0, 0)

        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("click", SFX_RESOURCES["scene_switch"])
예제 #6
0
    def __init__(self, x, y, num, screen, zoneArtwork=1):
        """
        :param x: Integer, the x-position of the wall.
        :param y: Integer, the y-position of the wall.
        :param num: Integer, identifying the number of the button.
        :param screen: pygame.Surface, the screen to draw the wall onto.
        :param zoneArtwork: Integer, choosing the image based on zone.
        """
        self.screen = screen
        self.num = num
        self.switchesWaiting = []
        self.isClosed = True

        # REFACTOR: Clumsy implementation to change image of the renderer.
        # - Causes instantiating argument to be needlessly long.
        # - The code below does not scale well.
        if zoneArtwork == 1:
            door = ZONE1_RESOURCES["doors"]
        if zoneArtwork == 2:
            door = ZONE2_RESOURCES["doors"]

        self.render = RenderComponent(self, enableRepeat=False)
        self.render.add("open", door["open"])
        self.render.add("closed", door["close"])
        self.render.state = "closed"
        self.rect = pg.Rect(x, y, 0, 0)

        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("open", SFX_RESOURCES["scene_door"])
예제 #7
0
    def __init__(self, screen):
        super().__init__(screen)
        self.fontSize = 50
        self.fontColour = "orange"
        self.x = 270
        self.y = 225

        self.pauseText = TextLabel("Pause",
                                   self.fontSize,
                                   self.fontColour,
                                   self.x,
                                   self.y,
                                   self.screen,
                                   isItalic=True)

        image = MENU_RESOURCES["screens"]["fade"][0]
        self.render = RenderComponent(self)
        self.render.add("background", image)
        self.render.state = "background"

        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("pause", SFX_RESOURCES["menu_pause"])
        self.audio.state = "pause"

        # Need to draw once only otherwise it overrides what is already drawn
        # by the Scene Engine
        self.render.update()
        self.pauseText.update()
        self.pauseText.draw()
        self.render.draw()
예제 #8
0
    def __init__(self, screen):
        super().__init__(screen)
        self.totalOptions = 4
        self.fontSize = 22
        self.fontColour = "white"
        self.x = 250
        self.y = 155
        self.dx = 0
        self.dy = 38

        self.option1 = TextLabel("1 Jugador", self.fontSize, self.fontColour,
                                 self.x, self.y + 1 * self.dy, self.screen)
        self.option2 = TextLabel("2 Jugadores", self.fontSize, self.fontColour,
                                 self.x, self.y + 2 * self.dy, self.screen)
        self.option3 = TextLabel("Opciones", self.fontSize, self.fontColour,
                                 self.x, self.y + 3 * self.dy, self.screen)
        self.option4 = TextLabel("Salir", self.fontSize, self.fontColour,
                                 self.x, self.y + 4 * self.dy, self.screen)
        self.title = ImageLabel(MENU_RESOURCES["assets"]["title"][0], 60, 55,
                                self.screen)
        self.arrow = _Arrow(self.x - 40, self.y + 28, self.dx, self.dy,
                            self.totalOptions, self.screen)

        background = MENU_RESOURCES["screens"]["main"][0]
        self.render = RenderComponent(self)
        self.render.add("background", background)
        self.render.state = "background"

        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("enter", SFX_RESOURCES["menu_enter"])
예제 #9
0
class IntroMenu(BaseMenu):
    """
    The intro screen of the game after the splash screen.
    """
    def __init__(self, screen):
        super().__init__(screen)
        self.effect = FadeEffect(screen)
        self.effect.timeEndDarken += 1.0

        ICONS = ICON_RESOURCES["assets"]
        self.render = RenderComponent(self)
        self.render.add("red", ICONS["red"][0])
        self.render.add("black", ICONS["black"][0])
        self.render.state = "black"

        w, h = ICONS["red"][0].get_size()
        offsetX = (settings.WIDTH - w) / 2
        offsetY = (settings.HEIGHT - h) / 2
        self.rect.center = (offsetX, offsetY)

        self.audio = AudioComponent(self, isRepeat=True, isAutoPlay=True)
        self.audio.add("intro_1", SFX_RESOURCES["menu_intro_1"])
        self.audio.add("intro_2", SFX_RESOURCES["menu_intro_2"])
        self.audio.state = "intro_1"

    def __str__(self):
        return "intro_menu"

    def handleEvent(self, event):
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_RETURN:
                self._sendMessage()

    def update(self):
        self.audio.update()
        self.render.update()

        if not self.effect.isComplete:
            self.effect.update()
            if self.effect.time > self.effect.timeStartDarken + 2.0:
                self.render.state = "red"
                self.audio.state = "intro_2"
        else:
            self._sendMessage()

    def draw(self, camera=None):
        self.render.draw(camera)
        self.effect.draw()

    def _sendMessage(self):
        """
        Sends a message to start the next menu.
        """
        self.messageMenu("transition", "main_menu")
        pg.mixer.stop()
예제 #10
0
class Switch(GameObject):
    """
    A switch entity that the player can turn on and off.
    """

    def __init__(self, x, y, switchNum, screen, zoneArtwork=1):
        """
        :param x: Integer, the x-position of the wall.
        :param y: Integer, the y-position of the wall.
        :param switchNum: Integer, identifying the number of the button.
        :param screen: pygame.Surface, the screen to draw the wall onto.
        :param zoneArtwork: Integer, choosing the image based on zone.
        """
        self.screen = screen
        self.num = switchNum
        self.isOn = True

        # REFACTOR: Clumsy implementation to change image of the renderer
        # - Causes instantiating argument to be needlessly long.
        # - The code below does not scale well.
        if zoneArtwork == 1:
            button = ZONE1_RESOURCES["buttons"]
        if zoneArtwork == 2:
            button = ZONE2_RESOURCES["buttons"]
        self.render = RenderComponent(self, enableRepeat=False)
        self.render.add("on", [button["switch"][0]])
        self.render.add("off", button["switch"], 500)
        self.render.state = "on"
        self.rect = pg.Rect(x, y, 0, 0)

        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("click", SFX_RESOURCES["scene_switch"])

    def __str__(self):
        return "switch " + str(self.num)

    def update(self):
        self.render.update()
        self.audio.update()

    def draw(self, camera=None):
        self.render.draw(camera)

    def turnOff(self):
        """
        Changes the state of the button to off and sends out an event.
        """
        self.isOn = False
        self.render.state = "off"
        self.audio.state = "click"
        self.messageScene("switch", (self.num, self.isOn))
예제 #11
0
class PauseMenu(BaseMenu):
    """
    The pause menu of the game.
    """
    def __init__(self, screen):
        super().__init__(screen)
        self.fontSize = 50
        self.fontColour = "orange"
        self.x = 270
        self.y = 225

        self.pauseText = TextLabel("Pause",
                                   self.fontSize,
                                   self.fontColour,
                                   self.x,
                                   self.y,
                                   self.screen,
                                   isItalic=True)

        image = MENU_RESOURCES["screens"]["fade"][0]
        self.render = RenderComponent(self)
        self.render.add("background", image)
        self.render.state = "background"

        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("pause", SFX_RESOURCES["menu_pause"])
        self.audio.state = "pause"

        # Need to draw once only otherwise it overrides what is already drawn
        # by the Scene Engine
        self.render.update()
        self.pauseText.update()
        self.pauseText.draw()
        self.render.draw()

    def __str__(self):
        return "pause_menu"

    def handleEvent(self, event):
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_ESCAPE:
                self.audio.state = "pause"

    def update(self):
        self.audio.update()

    def draw(self, camera=None):
        pass
예제 #12
0
    def __init__(self, screen):
        super().__init__(screen)
        self.rect = pg.Rect(0, 0, 0, 0)

        self.x = 50
        self.y = 50
        self.dx = 30

        self._HP = None
        self._maxHP = None
        self._lives = []

        self._audio = AudioComponent(self, isAutoPlay=False, isRepeat=True)
        self._audio.add("healthy", SFX_RESOURCES["menu_heartbeat_healthy"])
        self._audio.add("injured", SFX_RESOURCES["menu_heartbeat_injured"])
        self._audio.add("danger", SFX_RESOURCES["menu_heartbeat_danger"])
예제 #13
0
    def __init__(self, screen):
        super().__init__(screen)
        self.rect = pg.Rect(0, 0, 0, 0)
        telephone = CUTSCENE_RESOURCES["telephone"]

        self.origin = pg.time.get_ticks()  # milliseconds
        self.elapsed = 0  # milliseconds
        self._isComplete = False
        self._isReversed = False

        self.render = RenderComponent(self, enableRepeat=False)
        self.render.add("telephone_none", telephone["none"])
        self.render.add("telephone_pick", telephone["pick"], 1100)
        self.render.add("telephone_hold", telephone["hold"])
        self.render.add("telephone_put", telephone["put"], 1100)

        self.audio = AudioComponent(self)

        self.dialogue = Dialogue(self.screen)
        self.dialogue.add(dialogue.TELEPHONE_1, 350, 150, "left")
        self.dialogue.add(dialogue.TELEPHONE_2, 350, 150, "left")

        speed = 1
        ts = [2000, 2800, 3300, 6300, 10300, 11300, 12100, 14000]
        self.timings = [speed * t for t in ts]
예제 #14
0
    def __init__(self, screen):
        super().__init__(screen)
        self.rect = pg.Rect(0, 0, 0, 0)
        office = CUTSCENE_RESOURCES["office"]

        self.origin = pg.time.get_ticks()  # milliseconds
        self.elapsed = 0  # milliseconds
        self._isSentMessage = False

        self.render = RenderComponent(self)
        self.render.add("office_dog", office["dog"], 1500)
        self.render.add("office_cat", office["cat"], 1500)

        self.audio = AudioComponent(self, isAutoPlay=False)
        # self.audio.add("meow", SFX_RESOURCES["meow_1"])

        self.dialogue = Dialogue(self.screen)
        self.dialogue.add(dialogue.OFFICE_1, 240, 50, "left")
        self.dialogue.add(dialogue.OFFICE_2, 370, 100)
        self.dialogue.add(dialogue.OFFICE_3, 240, 50, "left")
        self.dialogue.add(dialogue.OFFICE_4, 370, 100)

        speed = 1
        ts = [0, 4000, 8000, 12000, 16000]
        self.timings = [speed * t for t in ts]
예제 #15
0
class WinMenu(BaseMenu):
    """
    The win menu of the game.
    """
    def __init__(self, screen):
        super().__init__(screen)
        self.screen = screen
        self.fontSize = 18
        self.fontColour = "white"
        self.x = 150
        self.y = 320

        self.enterText = TextLabel("Enter para salir", self.fontSize,
                                   self.fontColour, self.x, self.y,
                                   self.screen)
        self.Text2 = TextLabel("NIVEL 3 COMING SOON...", 32, self.fontColour,
                               100, 100, self.screen)

        image = MENU_RESOURCES["screens"]["fade"][0]
        self.render = RenderComponent(self)
        self.render.add("idle", image)
        self.render.state = "idle"

        self.audio = AudioComponent(self, isAutoPlay=False, isRepeat=True)
        self.audio.add("win", SFX_RESOURCES["scene_win"])
        self.audio.state = "win"

    def __str__(self):
        return "win_menu"

    def handleEvent(self, event):
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_RETURN:
                self.messageMenu("transition", "main_menu")
                self.messageScene("no_mode")

    def update(self):
        self.render.update()
        self.audio.update()
        self.enterText.update()
        self.Text2.update()

    def draw(self, camera=None):
        self.render.draw(camera)
        self.enterText.draw()
        self.Text2.draw()
예제 #16
0
    def __init__(self, screen):
        super().__init__(screen)

        self.effect = FadeEffect(screen)
        self.effect.timeStartLighten = 0.0
        self.effect.timeEndLighten = 1.0
        self.effect.timeStartDarken = 1.0
        self.effect.timeEndDarken = 1.5

        image = pg.Surface((settings.WIDTH, settings.HEIGHT))
        image.fill(settings.COLOURS["dark_red"])
        image = image.convert()
        self.render = RenderComponent(self)
        self.render.add("idle", image)
        self.render.state = "idle"

        self.audio = AudioComponent(self, isAutoPlay=True, isRepeat=False)
        self.audio.add("death", SFX_RESOURCES["menu_death"])
        self.audio.state = "death"
예제 #17
0
    def __init__(self, screen):
        super().__init__(screen)
        self.fontSize = 18
        self.fontColour = "white"
        self.x = 150
        self.y = 320

        self.enterText = TextLabel("Enter para salir", self.fontSize,
                                   self.fontColour, self.x, self.y,
                                   self.screen)

        image = MENU_RESOURCES["screens"]["lose"][0]
        self.render = RenderComponent(self)
        self.render.add("idle", image)
        self.render.state = "idle"

        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("meow", SFX_RESOURCES["menu_lose"])
        self.audio.state = "meow"
예제 #18
0
    def __init__(self, screen):
        super().__init__(screen)
        self.effect = FadeEffect(screen)

        background = MENU_RESOURCES["screens"]["splash"][0]
        background = addBackground(background)
        self.render = RenderComponent(self)
        self.render.add("background", background)
        self.render.state = "background"

        self.audio = AudioComponent(self)
        self.audio.add("door_knock", SFX_RESOURCES["splash_door_knock"])
        self.audio.add("door_open", SFX_RESOURCES["splash_door_open"])
        self.audio.add("door_close", SFX_RESOURCES["splash_door_close"])
        self.audio.add("meow", SFX_RESOURCES["splash_meow"])
        self.audio.link("door_knock", "door_open", delay=1000)
        self.audio.link("door_open", "meow")
        self.audio.link("meow", "door_close")
        self.audio.state = "door_knock"
예제 #19
0
    def __init__(self, screen):
        super().__init__(screen)
        self.effect = FadeEffect(screen)
        self.effect.timeEndDarken += 1.0

        ICONS = ICON_RESOURCES["assets"]
        self.render = RenderComponent(self)
        self.render.add("red", ICONS["red"][0])
        self.render.add("black", ICONS["black"][0])
        self.render.state = "black"

        w, h = ICONS["red"][0].get_size()
        offsetX = (settings.WIDTH - w) / 2
        offsetY = (settings.HEIGHT - h) / 2
        self.rect.center = (offsetX, offsetY)

        self.audio = AudioComponent(self, isRepeat=True, isAutoPlay=True)
        self.audio.add("intro_1", SFX_RESOURCES["menu_intro_1"])
        self.audio.add("intro_2", SFX_RESOURCES["menu_intro_2"])
        self.audio.state = "intro_1"
예제 #20
0
    def __init__(self, screen):
        """
        :param screen: pygame.Surface, representing the screen.
        """
        super().__init__()
        self.screen = screen
        self.rect = pg.Rect(0, 0, 0, 0)
        self.num = 0
        self.lives = 5

        self.isOnGround = False
        self.jumpSpeed = -12
        self.moveSpeed = 9

        self.physics = PhysicsComponent(self)
        self.render = RenderComponent(self, enableOrientation=True)
        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("jump", SFX_RESOURCES["cat_jump"])

        self.keybinds = None
예제 #21
0
class DeathMenu(BaseMenu):
    """
    The death screen of the game.
    """
    def __init__(self, screen):
        super().__init__(screen)

        self.effect = FadeEffect(screen)
        self.effect.timeStartLighten = 0.0
        self.effect.timeEndLighten = 1.0
        self.effect.timeStartDarken = 1.0
        self.effect.timeEndDarken = 1.5

        image = pg.Surface((settings.WIDTH, settings.HEIGHT))
        image.fill(settings.COLOURS["dark_red"])
        image = image.convert()
        self.render = RenderComponent(self)
        self.render.add("idle", image)
        self.render.state = "idle"

        self.audio = AudioComponent(self, isAutoPlay=True, isRepeat=False)
        self.audio.add("death", SFX_RESOURCES["menu_death"])
        self.audio.state = "death"

    def __str__(self):
        return "death_menu"

    def handleEvent(self, event):
        print("'{}' safely ignored event {}".format(self.__str__(), event))

    def update(self):
        self.render.update()
        self.audio.update()
        self.effect.update()

        if self.effect.isComplete:
            self.messageScene("revive")

    def draw(self, camera=None):
        self.render.draw()
        self.effect.draw()
예제 #22
0
class LoseMenu(BaseMenu):
    """
    The game over menu of the game.
    """
    def __init__(self, screen):
        super().__init__(screen)
        self.fontSize = 18
        self.fontColour = "white"
        self.x = 150
        self.y = 320

        self.enterText = TextLabel("Enter para salir", self.fontSize,
                                   self.fontColour, self.x, self.y,
                                   self.screen)

        image = MENU_RESOURCES["screens"]["lose"][0]
        self.render = RenderComponent(self)
        self.render.add("idle", image)
        self.render.state = "idle"

        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("meow", SFX_RESOURCES["menu_lose"])
        self.audio.state = "meow"

    def __str__(self):
        return "lose_menu"

    def handleEvent(self, event):
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_RETURN:
                self.messageMenu("transition", "splash_menu")
                self.messageScene("no_mode")

    def update(self):
        self.render.update()
        self.audio.update()
        self.enterText.update()

    def draw(self, camera=None):
        self.render.draw()
        self.enterText.draw()
예제 #23
0
    def __init__(self, screen):
        super().__init__(screen)
        self.screen = screen
        self.fontSize = 18
        self.fontColour = "white"
        self.x = 150
        self.y = 320

        self.enterText = TextLabel("Enter para salir", self.fontSize,
                                   self.fontColour, self.x, self.y,
                                   self.screen)
        self.Text2 = TextLabel("NIVEL 3 COMING SOON...", 32, self.fontColour,
                               100, 100, self.screen)

        image = MENU_RESOURCES["screens"]["fade"][0]
        self.render = RenderComponent(self)
        self.render.add("idle", image)
        self.render.state = "idle"

        self.audio = AudioComponent(self, isAutoPlay=False, isRepeat=True)
        self.audio.add("win", SFX_RESOURCES["scene_win"])
        self.audio.state = "win"
예제 #24
0
    def __init__(self, screen):
        super().__init__(screen)
        self.rect = pg.Rect(0, 0, 0, 0)
        pig = CUTSCENE_RESOURCES["pig"]["appear"]
        pig = [addBackground(p) for p in pig]

        self.origin = pg.time.get_ticks()  # milliseconds
        self.elapsed = 0  # milliseconds
        self._isComplete = False

        self.render = RenderComponent(self, enableRepeat=False)
        self.render.add("appear", pig, 3000)

        self.audio = AudioComponent(self)
        self.audio.add("machine", SFX_RESOURCES["pig_machine"])
        self.audio.state = "machine"

        self.dialogue = Dialogue(self.screen)

        speed = 1
        ts = [3000]
        self.timings = [speed * t for t in ts]
예제 #25
0
    def __init__(self, x, y, dx, dy, totalOptions, screen):
        """
        :param x: Integer, the x-position of the arrow.
        :param y: Integer, the y-position of the arrow.
        :param dx: Integer, the change in x-position per movement.
        :param dy: Integer, the change in y-position per moevement.
        :param totalOptions: Integer, the total number of options.
        :param screen: pygame.Surface, representing the screen.
        """
        self.rect = pg.Rect(x, y, 0, 0)
        self.dx = dx
        self.dy = dy
        self.totalOptions = totalOptions
        self.screen = screen
        self.index = 0

        self.render = RenderComponent(self)
        self.render.add("spin", MENU_RESOURCES["assets"]["coin"], 350)
        self.render.state = "spin"

        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("move", SFX_RESOURCES["menu_arrow"])
        self.audio.state = "move"
예제 #26
0
    def __init__(self, screen):
        super().__init__(screen)
        self.rect = pg.Rect(0, 0, 0, 0)
        jail = CUTSCENE_RESOURCES["jail"]

        self.origin = pg.time.get_ticks()  # milliseconds
        self.elapsed = 0  # milliseconds
        self._isComplete = False

        self.render = RenderComponent(self, enableRepeat=False)
        self.render.add("fence_show", jail["fence_show"], 2000)
        self.render.add("fence_static", jail["fence_static"])
        self.render.add("fence_hide", jail["fence_hide"], 2000)
        self.render.add("cat_static", jail["cat_static"])
        self.render.add("cat_close", jail["cat_close"], 3500)

        self.audio = AudioComponent(self)

        self.dialogue = Dialogue(self.screen)
        self.dialogue.add(dialogue.JAIL_1, 19, 25, "caption")

        speed = 1
        ts = [2000, 4000, 6000, 9500, 11500]
        self.timings = [speed * t for t in ts]
예제 #27
0
class PigCutscene(BaseCutscene):
    """
    The cutscene where the pig boss appears.
    """
    def __init__(self, screen):
        super().__init__(screen)
        self.rect = pg.Rect(0, 0, 0, 0)
        pig = CUTSCENE_RESOURCES["pig"]["appear"]
        pig = [addBackground(p) for p in pig]

        self.origin = pg.time.get_ticks()  # milliseconds
        self.elapsed = 0  # milliseconds
        self._isComplete = False

        self.render = RenderComponent(self, enableRepeat=False)
        self.render.add("appear", pig, 3000)

        self.audio = AudioComponent(self)
        self.audio.add("machine", SFX_RESOURCES["pig_machine"])
        self.audio.state = "machine"

        self.dialogue = Dialogue(self.screen)

        speed = 1
        ts = [3000]
        self.timings = [speed * t for t in ts]

    def __str__(self):
        return "pig_cutscene"

    def handleEvent(self, event):
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_RETURN:
                self._messageStart()

    def update(self):
        self.elapsed = pg.time.get_ticks() - self.origin

        if self.timings[0] > self.elapsed:
            self.render.state = "appear"
            self.dialogue.index = None
        else:
            if not self._isComplete:
                self._isComplete = True
                self._messageStart()

        self.dialogue.update()
        self.render.update()
        self.audio.update()

    def draw(self, camera=None):
        self.render.draw(camera)
        self.render.draw()
        self.dialogue.draw()

    def _messageStart(self):
        """
        Sends out events to end the cutscene and start playing the game.
        """
        self.messageCutScene("transition", "blank_cutscene")
        self.messageScene("unpause")
        pg.mixer.stop()
예제 #28
0
class PlayerBase(GameObject, pg.sprite.Sprite):
    """
    The controllable character to be played.
    """

    def __init__(self, screen):
        """
        :param screen: pygame.Surface, representing the screen.
        """
        super().__init__()
        self.screen = screen
        self.rect = pg.Rect(0, 0, 0, 0)
        self.num = 0
        self.lives = 5

        self.isOnGround = False
        self.jumpSpeed = -12
        self.moveSpeed = 9

        self.physics = PhysicsComponent(self)
        self.render = RenderComponent(self, enableOrientation=True)
        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("jump", SFX_RESOURCES["cat_jump"])

        self.keybinds = None

    def update(self):
        self.render.update()
        self.audio.update()
        self.physics.update()

        # Hacky solution to fix hit box sizes without tampering with the
        # animation images directly (too much effort at this point)
        w, h = self.rect.size
        self.rect.size = (w-10, h)

        pressed = pg.key.get_pressed()
        left = self.keybinds["move_left"]
        right = self.keybinds["move_right"]

        if pressed[left] and not pressed[right]:
            self.moveLeft()
        if pressed[right] and not pressed[left]:
            self.moveRight()

    def handleEvent(self, event):
        if event.type == pg.KEYDOWN:
            if event.key == self.keybinds["jump"]:
                self.jump()

        if event.type == pg.KEYUP:
            if event.key == self.keybinds["move_left"]:
                self.stop()
            if event.key == self.keybinds["move_right"]:
                self.stop()

    def draw(self, camera=None):
        self.render.draw(camera)

    def jump(self):
        """
        Makes the character jump.
        """
        if self.isOnGround:
            self.physics.velocity.y = self.jumpSpeed
            self.physics.addVelocityY("jump", self.jumpSpeed)
            self.isOnGround = False
            self.audio.state = "jump"

    def moveLeft(self):
        """
        Moves the character left.
        """
        self.render.state = "running"
        self.render.orientation = "left"
        self.physics.addDisplacementX("move", -self.moveSpeed)

    def moveRight(self):
        """
        Moves the character right.
        """
        self.render.state = "running"
        self.render.orientation = "right"
        self.physics.addDisplacementX("move", self.moveSpeed)

    def stop(self):
        """
        Stops the character.
        """
        self.render.state = "idle"
        self.physics.velocity.x = 0
예제 #29
0
class Door(GameObject):
    """
    A door entity that the player can enter.
    """

    def __init__(self, x, y, num, screen, zoneArtwork=1):
        """
        :param x: Integer, the x-position of the wall.
        :param y: Integer, the y-position of the wall.
        :param num: Integer, identifying the number of the button.
        :param screen: pygame.Surface, the screen to draw the wall onto.
        :param zoneArtwork: Integer, choosing the image based on zone.
        """
        self.screen = screen
        self.num = num
        self.switchesWaiting = []
        self.isClosed = True

        # REFACTOR: Clumsy implementation to change image of the renderer.
        # - Causes instantiating argument to be needlessly long.
        # - The code below does not scale well.
        if zoneArtwork == 1:
            door = ZONE1_RESOURCES["doors"]
        if zoneArtwork == 2:
            door = ZONE2_RESOURCES["doors"]

        self.render = RenderComponent(self, enableRepeat=False)
        self.render.add("open", door["open"])
        self.render.add("closed", door["close"])
        self.render.state = "closed"
        self.rect = pg.Rect(x, y, 0, 0)

        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("open", SFX_RESOURCES["scene_door"])

    def __str__(self):
        return "door_{}".format(self.num)

    def handleEvent(self, event):
        if event.type == self.SCENE_EVENT:
            if event.category == "switch":

                try:
                    switchNum, isOn = event.data
                    self.switchesWaiting.remove(switchNum)
                    if not self.switchesWaiting:
                        self.openDoor()
                except ValueError:
                    print("'{}' is safely ignoring switch number {}"
                          .format(self.__str__(), switchNum))
                except AttributeError:
                    print("'{}' is not a valid switch number!".format(switchNum))

    def update(self):
        self.render.update()
        self.audio.update()

    def draw(self, camera=None):
        self.render.draw(camera)

    def openDoor(self):
        """
        Changes the state of the door to open and sends out an event.
        """
        self.isClosed = False
        self.render.state = "open"
        self.audio.state = "open"
        self.messageScene("door", (self.num, self.isClosed))
예제 #30
0
class CollisionEngine(GameObject):
    """
    A specialised (non-scalable) collision engine that handles collisions
    between all entities in a scene.
    """
    def __init__(self, scene):
        """
        :param scene: Scene Class, representing a level.
        """
        self.scene = scene
        self.audio = AudioComponent(self, isAutoPlay=False)
        self.audio.add("explosion", SFX_RESOURCES["cat_coop_jump"])

    def __str__(self):
        return "collision_engine"

    def eventHandler(self, event):
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_RETURN:
                self.resolveDoorCollisions()

            try:
                p1, p2 = self.scene.players
                p1Jump = p1.keybinds["coop_jump"]
                p2Jump = p2.keybinds["coop_jump"]
                if event.key == p1Jump or event.key == p2Jump:
                    self.resolvePlayerCollisions(30)
                    self.audio.state = "explosion"
            except ValueError:
                pass

    def update(self):
        self.resolveWallCollisions()
        self.resolveSwitchCollisions()

        self.resolveSPlatformCollisions()
        self.resolveDPlatformCollisions()
        self.resolveMPlatformCollisions()

        self.resolveSpikeCollisions()
        self.resolveBossCollisions()
        self.resolveBoundaryCollision()

        self.audio.update()

    def resolvePlayerCollisions(self, explosionSpeed):
        """
        Resolves any collisions between players.

        :param explosionSpeed: Integer, the speed at which both players fly
        away from each other in the x-axis and y-axis respectively.
        """
        try:
            p1, p2 = self.scene.players
            if pg.sprite.collide_rect(p1, p2):
                p1.physics.addVelocityY("collision", -explosionSpeed)
                p2.physics.addVelocityY("collision", -explosionSpeed)

                if p2.rect.x > p1.rect.x:
                    p1.physics.addVelocityX("collision", -explosionSpeed)
                    p2.physics.addVelocityX("collision", explosionSpeed)

                else:
                    p1.physics.addVelocityX("collision", explosionSpeed)
                    p2.physics.addVelocityX("collision", -explosionSpeed)

        except ValueError:
            pass

    def resolveWallCollisions(self):
        """
        Resolves any wall collisions.
        """
        for player in self.scene.players:
            self._resolveBasicCollision(player, self.scene.walls)

    def resolveSPlatformCollisions(self):
        """
        Resolves any static platform collisions.
        """
        for player in self.scene.players:
            self._resolveBasicCollision(player, self.scene.sPlatforms)

    def resolveDPlatformCollisions(self):
        """
        Resolves any directional platform collisions.
        """
        for player in self.scene.players:

            hits = pg.sprite.spritecollide(player, self.scene.dPlatforms,
                                           False)
            for platform in hits:
                direction = self._checkCollisionDirection(player, platform)

                if direction == "bottom":
                    tol = abs(player.rect.bottom - platform.rect.top)
                    if tol < 30:
                        player.rect.bottom = platform.rect.top
                        player.isOnGround = True

                        # Allows conversation of velocity if the player jumps through
                        if player.physics.velocity.y > 0:
                            player.physics.velocity.y = 0

    def resolveMPlatformCollisions(self):
        """
        Resolves any moving platform collisions.
        """
        for player in self.scene.players:
            hits = pg.sprite.spritecollide(player, self.scene.mPlatforms,
                                           False)
            self._resolveBasicCollision(player, self.scene.mPlatforms)

            for platform in hits:
                player.physics.addDisplacementX("platform", platform.dx)
                player.physics.addDisplacementY("platform", platform.dy)

    def resolveSwitchCollisions(self):
        """
        Resolves any switch collisions.
        """
        switchesOn = [s for s in self.scene.switches if s.isOn]
        for s in switchesOn:

            for player in self.scene.players:
                if pg.sprite.collide_rect(player, s):
                    if (player.physics.velocity.x != 0
                            or player.physics.velocity.y != 0):
                        s.turnOff()

    def resolveDoorCollisions(self):
        """
        Resolves any door collisions.
        """
        for player in self.scene.players:

            hits = pg.sprite.spritecollide(player, self.scene.doors, False)
            doorsClosed = [d for d in self.scene.doors if d.isClosed]
            if hits and not doorsClosed:
                self.messageScene("complete")

    def resolveSpikeCollisions(self):
        """
        Resolves any spike collisions.
        """
        for player in self.scene.players:

            hits = pg.sprite.spritecollide(player, self.scene.spikes, False)
            if hits:
                self.messageScene("death", player.num)

    def resolveBossCollisions(self):
        """
        Resolves any boss collisions.
        """
        for player in self.scene.players:

            hits = pg.sprite.spritecollide(player, self.scene.bosses, False)
            if hits:
                self.messageScene("death", player.num)

    def resolveBoundaryCollision(self):
        """
        Checks if the players have 'fallen' out of the level.
        """
        w, h = self.scene.rect.size
        boundary = pg.Rect(-1000, -1000, w + 2000, h + 2000)

        for player in self.scene.players:
            if not pg.Rect.contains(boundary, player):
                self.messageScene("death", player.num)

    def _resolveBasicCollision(self, moving, group):
        """
        Resolves any collisions between a moving object and a group of
        objects such that the moving object cannot pass through such objects.

        :param moving: GameObject instance, representing a moving scene entity.
        :param group: List, containing GameObject instance in a scene.
        :return:
        """
        hits = pg.sprite.spritecollide(moving, group, False)

        for wall in hits:
            direction = self._checkCollisionDirection(moving, wall)

            if direction == "bottom":
                moving.rect.bottom = wall.rect.top
                moving.physics.velocity.y = 0
                moving.isOnGround = True

            elif direction == "left":
                moving.rect.left = wall.rect.right
                moving.physics.velocity.x = 0

            elif direction == "top":
                moving.rect.top = wall.rect.bottom
                moving.physics.velocity.y = 0

            elif direction == "right":
                moving.rect.right = wall.rect.left
                moving.physics.velocity.x = 0

    def _checkCollisionDirection(self, moving, static):
        """
        Checks if the moving game object has collided with the static game
        object, and determines the direciton of collision.

        :param moving: GameObject instance, representing a moving game object.
        :param static: GameObject instance, representing a static game object.
        :return: String, whether 'bottom', 'left', 'top', or 'right'.
        """
        if pg.sprite.collide_rect(moving, static):
            # Defining points on the static game object
            x, y = static.rect.center
            S00 = static.rect.topleft
            S10 = static.rect.topright
            S11 = static.rect.bottomright
            S01 = static.rect.bottomleft

            # Defining points on the moving game object
            u, v = moving.rect.center
            M00 = moving.rect.topleft
            M10 = moving.rect.topright
            M11 = moving.rect.bottomright
            M01 = moving.rect.bottomleft

            # Defining vectors on the static game object which will be used in
            # accurate collision handling. The vectors are from the center of
            # the game object to its corners.
            vec_M00 = Vector2(x - S00[0], y - S00[1])
            vec_M10 = Vector2(x - S10[0], y - S10[1])
            vec_M11 = Vector2(x - S11[0], y - S11[1])
            vec_M01 = Vector2(x - S01[0], y - S01[1])

            # Defining variables for our new coordinate system based on angles
            # (which is mathematically equivalent to bearings)
            FULL_ROTATION = 360
            origin = vec_M00

            # Calculating angles of the static game object vectors
            angle_00 = origin.angle_to(vec_M00) % FULL_ROTATION
            angle_10 = origin.angle_to(vec_M10) % FULL_ROTATION
            angle_11 = origin.angle_to(vec_M11) % FULL_ROTATION
            angle_01 = origin.angle_to(vec_M01) % FULL_ROTATION

            # Calculating the displacement angle between the moving and
            # static game objects
            displacement = Vector2(x - u, y - v)
            angle = origin.angle_to(displacement) % FULL_ROTATION

            # Calculating direction of the collision
            isCollideBottom = angle_00 < angle < angle_10
            isCollideLeft = angle_10 < angle < angle_11
            isCollideTop = angle_11 < angle < angle_01
            isCollideRight = angle_01 < angle

            if isCollideBottom:
                return "bottom"
            elif isCollideLeft:
                return "left"
            elif isCollideTop:
                return "top"
            elif isCollideRight:
                return "right"