Assignment 1: The “Meepo is You” Game

- Starter Code is included Assignment 1: The “Meepo is You” Game Ms. Meepo, a high school teacher, likes the game “Baba is You” a lot. In this game, rules are blocks you can interact with. By manipulating these blocks, you can change the rules and hence ✨ alter how the game works! ✨ To learn more about the original game, you can watch this video. Driven by her passion for the game, Ms. Meepo wants to make a similar game “Meepo is You” where the player (more precisely, one of the possible players) looks like her. Although Ms. Meepo wrote some code to the best of her ability, her programming knowledge is restricted to CSC108. Hence, she needs your help to implement the game so that it is similar to “Baba is you” but simplified. She wants you to read different game maps and build visuals accordingly. Any player in the game should be able to: Move up, down, left or right without going off-screen Push rule blocks to form/alter the game’s rules. Depending on how these rules are manipulated, other objects on the screen may behave differently when interacting with the player The code Ms. Meepo provided has some objects and some basic functionality, but she’s counting on you to make the whole game work. She also wants you to ensure you don’t delete the original classes, their attributes, and maintain the hierarchy (for example, the game class should create the interface). Furthermore, the classes you will implement may include some methods which are not used in the present application, and these decisions will be left to you. Note: although you will not be penalized for inefficient code, efficiency will make your code more usable in the future. Game Specifications Files Download the starter code here. Ms. Meepo has broken the game into the following components: game.py: the Game class the defines the main game application actor.py: the Actor class and all its subclasses settings.py: the Game’s settings stack.py: the Stack class Design You must read the given files carefully and fully before you proceed with writing the code! Remember, for all the classes, you may add extra attributes and methods if you deem it necessary, but you are NOT allowed to delete or modify the declarations of any of the given ones. Ms. Meepo is very particular about this. Game instructions: Maps in the game have objects on them. A player can move objects around. Rules are objects too, so players can move them around as well. Moving rules is special, because moving them makes other objects in the game interact differently. ? An example of moving rules is: if a rule states “Wall is Lose” then if the player walks into the wall, the player will lose. If the rule states “Wall is Push” then Ms. Meepo can push the walls she touches around. You can use the UNDO feature any time to move to a previous state. Even if you lose, you can simply UNDO (i.e. the screen does not get destroyed). The only static object in the game is the bush. Bushes cannot be pushed or moved. Everything else can be changed according to the rules in place. A newly formed rule surpasses an older one if they are contradictory. Watch the demo video here for a visual demonstration: Here is the YouTube link: https://youtu.be/hspL2ZM2kIs Code Layout Note: Below is just a summary of the structure of the code. Much the information about the code is provided in the docstring and comments inside the code files, so make sure to read the docs in the code files thoroughly! The Game class is the main game application and holds all the game objects (e.g. player, rules, map), handles the visualization, senses keyboard feed, and delivers the input to the appropriate objects. It also handles the undo feature. Game has several attributes. Some attributes hold lists while others hold single objects. The class also has some private attributes. Familiarize yourself with all the given attributes, but the main ones are: _actors –> the list of all actors in the game: player, walls, bushes, and all word blocks (attributes, subjects, is) _is –> the list of ‘IS’ blocks _rules –> the list of game rules currently formed in the game screen _running –> a boolean that indicates if the game is running _history –> the stack of the game state history player –> the main game player. Initially, it is the one and only Ms. Meepo, but during the game it can be changed to other characters as well such as a rock, a wall, or a flag. map_data –> a list of str. Each str is a line in the “map data” txt file keys_pressed –> a sequence from PyGame that indicates which key has been pressed Game has multiple methods that make the game run, the main ones are: __init__ –> create an empty game object load_map –> load the given map into the game.map_data new –> convert everything in the game.map_data into proper objects on the screen _draw –> update the game interface _events –> handled the keyboard input run –> keep the game running until the player wins. _update –> updates the game’s rules according to the word blocks in the game The Actor class and its children classes are where you will do the majority of your work. An Actor is any object on the screen, movable or not. Each actor has these attributes: x, y –> ints that store the position of the actor on the screen image –> an actor sprite _is_stop –> a boolean to indicate if the object can be moved through _is_push –> a boolean to indicate if the object can be pushed by other actors Blocks are Actors in the game that have words in them and can be part of a rule. Bushes are Actors that can never be pushed or moved through. Character are Actors that are non-Block/Bush, i.e., wall, rocks, flags, and Meepo. A Character can potentially be the player that is moved directly by the key presses depending on the “isYou” rule The Stack class, which you have learned, is an array of objects where you push objects to the top and pop from the top as well. The _history attribute of Game uses a stack. Do not modify this class. Just learn how to use it. It is useful for when you do the undo feature in the game. Finally, the settings file has the game setting as variables. You can change some of them for your own amusement, but Ms. Meepo will use her own settings file so any alteration you make here will not be seen by your client, i.e., you will not submit this file to MarkUs. Data To aid in the rapid progression of software development, Ms. Meepo has provided you with map data in which you will construct the game visualization from. We have provided a few maps under the maps folder. You may modify the MAP_PATH variable in settings.py to choose the map you want to use. By default, it uses map.txt which is a copy of one of the student maps. You should also feel free to create your own maps. Each character (except the dot) in each row corresponds to an object block. Namely: 1 –> bush 2 –> Meepo 3 –> wall 4 –> rock 5 –> flag I –> Is Attributes L –> “Lose” P –> “Push” V –> “Victor” Y –> “You” S –> “Stop” Subjects M –> “Meepo” W –> “Wall” R –> “Rock” F –> “Flag” NOTE: map data is assumed to be correct and complete. This means that there will never be errors in the txt files. The sprite folder has the objects’ avatars. You do not need to do anything in this folder. Note: The game is supposed to start with Meepo being the initial player, therefore, the map should always have the “Meepo isYou” ruled formed by the blocks initially; otherwise, you won’t be able to start playing the game (unless, of course, if you somehow hard-code the rule in your code for testing/debugging purposes, but that should be removed in the production version of the code that you submit). Tasks You are now ready to begin writing code! Remember, you must read the given files carefully and fully before you proceed with writing the code! A note about doctests: we have omitted doctests from most of the starter code, and you are not required to write doctests for this assignment. In this assignment, initializing objects for testing is more involved than usual, resulting in messy docstrings. However, you will be required to follow all other aspects of the class design recipe, and you are required to write a thorough test suite in a separate file (student_tests.py). Do not duplicate code! If you are given a method (either in the current class or the parent class you inherit from), use it! If you need to write a helper function because a piece of code is utilized over and over, do it. Remember to make helpers private, and to follow data encapsulation principles. Task 1: Complete the Initializers Your first code-writing task is to complete the initializers (this includes initializing the specified default parameters), implement simple methods and create the following classes (according to the docstring and type contract) in the order stated. Once you finish, you will be able to run the game and have the game components display on the screen (though you will not be able to play it yet): Game: ensure that you set any necessary attributes appropriately. Wall, Rock, and Flag: create these classes (in actor.py) separately and implement their initializers with setting up necessary attributes. Hint: refer to the settings file to know the proper object sprite/avatar. Wall, Rock, Flag, and Meepo: What other methods need to be implemented in these classes? Read the code carefully and add what’s necessary. Subject, Attribute, Is: Complete these subclasses of the Block class by adding their initializers and any other necessary method. Again, read the code and docstrings carefully to understand what needs to be done. Hint: If you’re not sure about what initial values to assign to the attributes, look for the the code where those attributes are used. Task 2: Implement the Moves Implement/complete the following methods (preferably in the order stated). Once you finish this task, the player should be able to move Ms. Meepo’s character around: Read _events in the Game class to understand which methods are called the games receives key-press events. move in the Actor class. Read the player_move method in Character to see how the move method is initially called. Read the docstring of move carefully to understand what needs be done in it. As part of the implementation of the move method. Check and use the is_stop and is_push flags correctly so that the pushable objects are actually pushable, and the move is properly stopped when it should not happen. Override the handle_key_presses method in the Meepo class so that we update the image of Ms. Meepo dynamically as she moves. Read the initializer of the Meepo class to see what images are used. Watch the video demo carefully to see how the images should change as Ms. Meepo moves in different directions. After this step, you may think you are now able to move the objects on the screen, but actually not yet! You need to also write the code that updates the rules in the game in order to be able to move the player. That’s we will do in the following task. (If you REALLY wanna see Meepo move now, you may manually set self.player to the Meepo object somewhere in your code, then you should be able to move Ms. Meepo on the screen, but make sure to replace this temporary hack with the proper rule updates later!) Task 3: Manipulate the Rules update in the IS class: this method detects any horizontal or vertical rule that is formed around the current IS block. Read the docstring carefully to understand what exactly you need to do. Make sure the colour of the IS block is correctly set as specified in the docstring. _update in the Game class. This method checks for all rules that are currently formed around the IS blocks, and apply/remove them from the list of rules stored in the Game object. You need to complete its implementation. You must complete this method for the player to move because the initial rule “Meepo isYou” is not in effect until you recognize and update it. You might need to update some of the methods that you wrote in Task 2 as well in order to make everything work correctly together. After this step, you should be able to move Ms. Meepo around with your keyboard as well as pushing objects around! Some caveats about the rules (check FAQ on Piazza for more info) As mentioned earlier, when there rules that are contradictory, e.g., if “Rock isWin” and “Rock isLose” both exist. A newly formed rule surpasses an older one. If all “isYou” rules are removed, nobody is the player therefore you cannot move anything on the screen with keys anymore. The only to continue playing is to undo the last move. The player can also be a wall, a rock, or a flag, if you manage to push the rule bocks to form, for example, “Wall isYou”. In this case, if there are multiple Wall objects on the screen, only one of them becomes the player and it can be any one of them – it depends on which is the last one that you called set_player on. Task 4: Implement the UNDO feature In the last task, you will implement the UNDO feature. When a player presses ctrl+z, the game should move to its previous last state. You can do multiple ctrl+z to go back as many times as you want. You will utilize the Stack class for this feature. To do so, for every game state, you want to create a copy of this state and push it to the stack such that when the UNDO is called, you can pop the last state and make the game looks like that previous state. Add and complete the necessary copy methods in various classes in actor.py wherever necessary. You should have done this in Task 1 already, but just to double check here in case you have missed any of them. Read the code of the Game class carefully to understand which attributes need to be saved when copying the state of the game. Complete the _copy method in the Game class (Hint: when you copy, remember how sometimes = means aliasing in python. Think of the Python memory model!) Complete the _undo method in the Game class. Dun dun done! Hopefully your code will be to Ms. Meepo’s liking (and hopefully it runs and passes our test cases) :) Task 5: Test Your Code The student_tests.py files contains some initial test cases that you can use to test your game. However, the test suite is very incomplete, and you need to add more test cases to it. You will be asked to submit your tester file, and it will be marked according to the quality of your tests. Correctness: 60% Quality of OO design: 30% Quality of student_tests.py: 10%

Get Help With a similar task to - Assignment 1: The “Meepo is You” Game

Login to view and/or buy answers.. or post an answer
Additional Instructions:

a1starter/maps/map.txt 11111111111111111111111111 1........................1 1....2...................1 1........................1 1....4...................1 1.........W.IL.....5.....1 1.........F..............1 1........................1 1.......333....3333......1 1.......3.........3......1 ..................3......1 1...I.P.....I.....3......1 1..R.......V......3......1 1.......3.........3......1 1.......33333333333......1 1......MIY...............1 11111.......I.S......11111 1...1................1RIS1 11111111111111111111111111 a1starter/maps/student_map5.txt 11111111111111111111111111 1........................1 1....2...................1 1........................1 1....4...................1 1.........W.IL.....5.....1 1.........F..............1 1........................1 1.......333....3333......1 1.......3.........3......1 ..................3......1 1...I.P.....I.....3......1 1..R.......V......3......1 1.......3.........3......1 1.......33333333333......1 1......MIY...............1 11111.......I.S......11111 1...1................1RIS1 11111111111111111111111111 a1starter/maps/student_map4.txt 111111111 124.R.IP1 1MIY1...1 111111111 a1starter/maps/student_map3.txt 11111111 123.WIP1 1MIY1..1 11111111 a1starter/maps/student_map2.txt 11111111 1.2W.IP1 1MIY1..1 11111111 a1starter/maps/student_map1.txt 11111111 1......1 1MIY1.21 11111111 a1starter/game.py """ Assignment 1: Meepo is You === CSC148 Winter 2021 === Department of Mathematical and Computational Sciences, University of Toronto Mississauga === Module Description === This module contains the Game class and the main game application. """ from typing import Any, Type, Tuple, List, Sequence, Optional import pygame from settings import * from stack import Stack import actor class Game: """ Class representing the game. """ size: Tuple[int, int] width: int height: int screen: Optional[pygame.Surface] x_tiles: int y_tiles: int tiles_number: Tuple[int, int] background: Optional[pygame.Surface] _actors: List[actor.Actor] _is: List[actor.Is] _running: bool _rules: List[str] _history: Stack player: Optional[actor.Actor] map_data: List[str] keys_pressed: Optional[Sequence[bool]] def __init__(self) -> None: """ Initialize variables for this Class. """ self.width, self.height = 0, 0 self.size = (self.width, self.height) self.screen = None self.x_tiles, self.y_tiles = (0, 0) self.tiles_number = (self.x_tiles, self.y_tiles) self.background = None # TODO Task 1: complete the initializer of the Game class pass def load_map(self, path: str) -> None: """ Reads a .txt file representing the map """ with open(path, 'rt') as f: for line in f: self.map_data.append(line.strip()) self.width = (len(self.map_data[0])) * TILESIZE self.height = len(self.map_data) * TILESIZE self.size = (self.width, self.height) self.x_tiles, self.y_tiles = len(self.map_data[0]), len(self.map_data) # center the window on the screen os.environ['SDL_VIDEO_CENTERED'] = '1' def new(self) -> None: """ Initialize variables to be object on screen. """ self.screen = pygame.display.set_mode(self.size) self.background = pygame.image.load( "{}/backgroundBig.png".format(SPRITES_DIR)).convert_alpha() for col, tiles in enumerate(self.map_data): for row, tile in enumerate(tiles): if tile.isnumeric(): self._actors.append( Game.get_character(CHARACTERS[tile])(row, col)) elif tile in SUBJECTS: self._actors.append( actor.Subject(row, col, SUBJECTS[tile])) elif tile in ATTRIBUTES: self._actors.append( actor.Attribute(row, col, ATTRIBUTES[tile])) elif tile == 'I': is_tile = actor.Is(row, col) self._is.append(is_tile) self._actors.append(is_tile) def get_actors(self) -> List[actor.Actor]: """ Getter for the list of actors """ return self._actors def get_running(self) -> bool: """ Getter for _running """ return self._running def get_rules(self) -> List[str]: """ Getter for _rules """ return self._rules def _draw(self) -> None: """ Draws the screen, grid, and objects/players on the screen """ self.screen.blit(self.background, (((0.5 * self.width) - (0.5 * 1920), (0.5 * self.height) - (0.5 * 1080)))) for actor_ in self._actors: rect = pygame.Rect(actor_.x * TILESIZE, actor_.y * TILESIZE, TILESIZE, TILESIZE) self.screen.blit(actor_.image, rect) # Blit the player at the end to make it above all other objects if self.player: rect = pygame.Rect(self.player.x * TILESIZE, self.player.y * TILESIZE, TILESIZE, TILESIZE) self.screen.blit(self.player.image, rect) pygame.display.flip() def _events(self) -> None: """ Event handling of the game window """ for event in pygame.event.get(): if event.type == pygame.QUIT: self._running = False # Allows us to make each press count as 1 movement. elif event.type == pygame.KEYDOWN: self.keys_pressed = pygame.key.get_pressed() ctrl_held = self.keys_pressed[pygame.K_LCTRL] # handle undo button and player movement here if event.key == pygame.K_z and ctrl_held: # Ctrl-Z self._undo() else: if self.player is not None: assert isinstance(self.player, actor.Character) save = self._copy() if self.player.player_move(self) \ and not self.win_or_lose(): self._history.push(save) return def win_or_lose(self) -> bool: """ Check if the game has won or lost Returns True if the game is won or lost; otherwise return False """ assert isinstance(self.player, actor.Character) for ac in self._actors: if isinstance(ac, actor.Character) \ and ac.x == self.player.x and ac.y == self.player.y: if ac.is_win(): self.win() return True elif ac.is_lose(): self.lose(self.player) return True return False def run(self) -> None: """ Run the Game until it ends or player quits. """ while self._running: pygame.time.wait(1000 // FPS) self._events() self._update() self._draw() def set_player(self, actor_: Optional[actor.Actor]) -> None: """ Takes an actor and sets that actor to be the player """ self.player = actor_ def remove_player(self, actor_: actor.Actor) -> None: """ Remove the given <actor> from the game's list of actors. """ self._actors.remove(actor_) self.player = None def _update(self) -> None: """ Check each "Is" tile to find what rules are added and which are removed if any, and handle them accordingly. """ # TODO Task 3: Add code here to complete this method # What you need to do in this method: # - Get the lists of rules that need to be added to and remove from the # current list of rules. Hint: use the update() method of the Is # class. # - Apply the additional and removal of the rules. When applying the # rules of a type of character, make sure all characters of that type # have their flags correctly updated. Hint: take a look at the # get_character() method -- it can be useful. # - The player may change if the "isYou" rule is updated. Make sure set # self.player correctly after you update the rules. Note that # self.player could be None in some cases. # - Update self._rules to the new list of rules. return @staticmethod def get_character(subject: str) -> Optional[Type[Any]]: """ Takes a string, returns appropriate class representing that string """ if subject == "Meepo": return actor.Meepo elif subject == "Wall": return actor.Wall elif subject == "Rock": return actor.Rock elif subject == "Flag": return actor.Flag elif subject == "Bush": return actor.Bush return None def _undo(self) -> None: """ Returns the game to a previous state based on what is at the top of the _history stack. """ # TODO Task 4: Implement this undo method. # You'll need to restore the previous state the game using the # self._history stack # Find the code that pushed onto the stack to understand better what # is in the stack. pass return def _copy(self) -> 'Game': """ Copies relevant attributes of the game onto a new instance of Game. Return new instance of game """ game_copy = Game() # TODO Task 4: Complete this method to create a proper copy of the # current state of the game pass return game_copy def get_actor(self, x: int, y: int) -> Optional[actor.Actor]: """ Return the actor at the position x,y. If the slot is empty, Return None """ for ac in self._actors: if ac.x == x and ac.y == y: return ac return None def win(self) -> None: """ End the game and print win message. """ self._running = False print("Congratulations, you won!") def lose(self, char: actor.Character) -> None: """ Lose the game and print lose message """ self.remove_player(char) print("You lost! But you can have it undone if undo is done :)") if __name__ == "__main__": game = Game() # load_map public function game.load_map(MAP_PATH) game.new() game.run() # import python_ta # python_ta.check_all(config={ # 'extra-imports': ['settings', 'stack', 'actor', 'pygame'] # }) a1starter/__pycache__/stack.cpython-38.pyc a1starter/__pycache__/settings.cpython-38.pyc a1starter/__pycache__/actor.cpython-38.pyc a1starter/student_tests.py from game import * from actor import * import pytest import pygame import os # USE PYGAME VARIABLES INSTEAD keys_pressed = [0] * 323 # Setting key constants because of issue on devices pygame.K_RIGHT = 1 pygame.K_DOWN = 2 pygame.K_LEFT = 3 pygame.K_UP = 4 pygame.K_LCTRIL = 5 pygame.K_z = 6 RIGHT = pygame.K_RIGHT DOWN = pygame.K_DOWN LEFT = pygame.K_LEFT UP = pygame.K_UP CTRL = pygame.K_LCTRL Z = pygame.K_z def setup_map(map: str) -> 'Game': """Returns a game with map1""" game = Game() game.new() game.load_map(os.path.abspath(os.getcwd()) + '/maps/' + map) game.new() game._update() game.keys_pressed = keys_pressed return game def set_keys(up, down, left, right, CTRL=0, Z=0): keys_pressed[pygame.K_UP] = up keys_pressed[pygame.K_DOWN] = down keys_pressed[pygame.K_LEFT] = left keys_pressed[pygame.K_RIGHT] = right def test1_move_player_up(): """ Check if player is moved up correctly """ game = setup_map("student_map1.txt") set_keys(1, 0, 0, 0) result = game.player.player_move(game) assert result == True assert game.player.y == 1 def test2_push_block(): """ Check if player pushes block correctly """ game = setup_map("student_map2.txt") set_keys(0, 0, 0, 1) wall = \ [i for i in game._actors if isinstance(i, Block) and i.word == "Wall"][0] result = game.player.player_move(game) assert result == True assert game.player.x == 3 assert wall.x == 4 def test3_create_rule_wall_is_push(): """ Check if player creates wall is push rule correctly """ game = setup_map("student_map2.txt") set_keys(0, 0, 0, 1) wall = \ [i for i in game._actors if isinstance(i, Block) and i.word == "Wall"][0] result = game.player.player_move(game) game._update() assert game._rules[0] == "Wall isPush" assert game.player.x == 3 assert wall.x == 4 def test_4_follow_rule_wall_is_push(): """ Check if player follows rules correctly """ game = setup_map("student_map3.txt") set_keys(0, 0, 0, 1) wall_object = game._actors[game._actors.index(game.player) + 1] result = game.player.player_move(game) assert game.player.x == 2 assert wall_object.x == 3 def test_5_no_push(): """ Check if player is not able to push because of rule not existing """ game = setup_map("student_map4.txt") set_keys(0, 0, 0, 1) wall_object = game._actors[game._actors.index(game.player) + 1] result = game.player.player_move(game) assert game.player.x == 2 assert wall_object.x == 2 if __name__ == "__main__": import pytest pytest.main(['student_tests.py']) a1starter/stack.py from typing import Any, List class Stack: """A last-in-first-out (LIFO) stack of items. Stores data in a last-in, first-out order. When removing an item from the stack, the most recently-added item is the one that is removed. """ # === Private Attributes === # _items: # The items stored in this stack. The end of the list represents # the top of the stack. _items: List def __init__(self) -> None: """Initialize a new empty stack.""" self._items = [] def is_empty(self) -> bool: """Return whether this stack contains no items. >>> s = Stack() >>> s.is_empty() True >>> s.push('hello') >>> s.is_empty() False """ return self._items == [] def push(self, item: Any) -> None: """Add a new element to the top of this stack.""" self._items.append(item) def pop(self) -> Any: """Remove and return the element at the top of this stack. Raise an EmptyStackError if this stack is empty. >>> s = Stack() >>> s.push('hello') >>> s.push('goodbye') >>> s.pop() 'goodbye' """ if self.is_empty(): raise EmptyStackError else: return self._items.pop() class EmptyStackError(Exception): """Exception raised when an error occurs.""" pass a1starter/settings.py import os ########################################################## # COLOURS # ########################################################## WHITE = (255, 255, 255) BLACK = (0, 0, 0) DARKGREY = (40, 40, 40) LIGHTGREY = (100, 100, 100) ORANGE = (255, 165, 0) GREEN = (0, 128, 0) RED = (100, 0, 0) BLUE = (30, 144, 255) DARKBLUE = (0, 0, 205) PURPLE = (102, 0, 204) YELLOW = (255, 255, 0) ########################################################## # SPECIFICATION # ########################################################## FPS = 10 TITLE = "Base Game" TILESIZE = 35 SUBJECTS = {"W": "Wall", "R": "Rock", "F": "Flag", "M": "Meepo"} ATTRIBUTES = {"P": "Push", "S": "Stop", "V": "Victory", "L": "Lose", "Y": "You"} CHARACTERS = {"1": "Bush", "2": "Meepo", "3": "Wall", "4": "Rock", "5": "Flag"} BASE_DIR = "." SPRITES_DIR = "{}/sprites".format(BASE_DIR) MAP_PATH = "{}/maps/map.txt".format(BASE_DIR) # Actors' sprites PLAYER_SPRITE_R1 = "{}/playerR1.png".format(SPRITES_DIR) PLAYER_SPRITE_R2 = "{}/playerR2.png".format(SPRITES_DIR) PLAYER_SPRITE_U1 = "{}/playerU1.png".format(SPRITES_DIR) PLAYER_SPRITE_U2 = "{}/playerU2.png".format(SPRITES_DIR) PLAYER_SPRITE_B1 = "{}/playerB1.png".format(SPRITES_DIR) PLAYER_SPRITE_B2 = "{}/playerB2.png".format(SPRITES_DIR) BUSH_SPRITE = "{}/bush.png".format(SPRITES_DIR) WALL_SPRITE = "{}/wallS.png".format(SPRITES_DIR) ROCK_SPRITE = "{}/rockS.png".format(SPRITES_DIR) FLAG_SPRITE = "{}/flagS.png".format(SPRITES_DIR) IS_PURPLE = "{}/isPurple.png".format(SPRITES_DIR) IS_DARK_BLUE = "{}/isDarkBlue.png".format(SPRITES_DIR) IS_LIGHT_BLUE = "{}/isLightBlue.png".format(SPRITES_DIR) WORDS_SPRITES = {} for word in (list(SUBJECTS.values()) + list(ATTRIBUTES.values())): filepath = "{}/{}.png".format(SPRITES_DIR, word.lower()) if os.path.exists(filepath): WORDS_SPRITES[word.lower()] = filepath a1starter/sprites/stop.png a1starter/sprites/you.png a1starter/sprites/flag.png a1starter/sprites/backgroundBig.png a1starter/sprites/isDarkBlue.png a1starter/sprites/isPurple.png a1starter/sprites/victory.png a1starter/sprites/playerB1.png a1starter/sprites/rockS.png a1starter/sprites/playerB2.png a1starter/sprites/wallS.png a1starter/sprites/rock.png a1starter/sprites/lose.png a1starter/sprites/meepo.png a1starter/sprites/playerU1.png a1starter/sprites/isLightBlue.png a1starter/sprites/playerU2.png a1starter/sprites/wall.png a1starter/sprites/push.png a1starter/sprites/flagS.png a1starter/sprites/bush.png a1starter/sprites/playerR1.png a1starter/sprites/playerR2.png a1starter/actor.py """ Assignment 1: Meepo is You === CSC148 Winter 2021 === Department of Mathematical and Computational Sciences, University of Toronto Mississauga === Module Description === This module contains the Actor class and all its subclasses that represent different types of elements in the game. """ import pygame from typing import Tuple, Optional from settings import * class Actor: """ A class that represents all the actors in the game. This class includes any attributes/methods that are common between the actors === Public Attributes === x: x coordinate of this actor's location on the stage y: y coordinate of this actor's location on the stage image: the image of the actor === Private Attributes === _is_stop: Flag to keep track of whether this object cannot be moved through _is_push: Flag to keep track of whether this object is pushable Representation Invariant: x,y must be greater or equal to 0 """ x: int y: int _is_stop: bool _is_push: bool image: pygame.Surface def __init__(self, x: int, y: int) -> None: self.x, self.y = x, y self._is_stop = False self._is_push = False self.image = pygame.Surface((TILESIZE, TILESIZE)) def is_stop(self) -> bool: """ Getter for _is_stop """ return self._is_stop def is_push(self) -> bool: """ Getter for _is_push """ return self._is_push def copy(self) -> 'Actor': """ Creates an identical copy of self and returns the new copy To be implemented in the subclasses """ raise NotImplementedError def move(self, game_: 'Game', dx: int, dy: int) -> bool: """ Function to move an Actor on the screen, to the direction indicated by dx and dy game_: the Game object dx: the offset in the x coordinate dx: the offset in the y coordinate Returns whether <self> actually moves. Note: this method is different from the "player_move" method in the Character class. A "player_move" is trigger by key pressed directly. This more general "move" can be a move caused by a push. In fact, this "move" method is used in the implementation of "player_move". Things to think about in this method: - The object cannot go off the screen boundaries - The move may push other objects to move as well. - The move might not happen because it's blocked by an unmovable object, in which case this method should return False - Recall how push works: you may push and move a line of multiple objects as long as the move is not blocked by something. """ # TODO Task 2: Complete this method return True class Character(Actor): """ A class that represents non-Blocks/Bushes on the screen i.e., Meepo, Wall, Rock, Flag A Character could potentially be the player that is controlled by the key presses === Additional Private Attributes === _is_player: Whether the character is the player, i.e., "<Character> isYou" _is_lose: Whether the rules contains "<Character> isLose" _is_win: Whether the rules contains "<Character> isWin" """ _is_player: bool _is_lose: bool _is_win: bool def __init__(self, x: int, y: int) -> None: """ Initializes the Character """ super().__init__(x, y) self._is_player = False self._is_lose = False self._is_win = False def is_win(self) -> bool: """ Getter for _is_win """ return self._is_win def is_lose(self) -> bool: """ Getter for _is_lose """ return self._is_lose def is_player(self) -> bool: """ Getter for _is_player """ return self._is_player def set_player(self) -> None: """ Sets flag to make this actor the player. """ self._is_player = True self._is_stop = False self._is_push = False def unset_player(self) -> None: """ Unsets the flag to make the actor not the player. """ self._is_player = False def set_stop(self) -> None: """ Sets flag to make actor incapable of being moved through or pushed. """ self._is_stop = True self._is_push = False self._is_player = False def unset_stop(self) -> None: """ Unsets the flag that prevents actor from being moved through or pushed. """ self._is_stop = False def set_push(self) -> None: """ Sets the flag that allows the actor to be pushable """ self._is_push = True self._is_stop = False self._is_player = False def unset_push(self) -> None: """ Unsets the flag that allows the actor to be pushable """ self._is_push = False def set_win(self) -> None: """ Sets this actor to be the win Condition. """ self._is_win = True self._is_lose = False def unset_win(self) -> None: """ Unsets this actor from being the win Condition. """ self._is_win = False def set_lose(self) -> None: """ Sets this flag to be the lose condition. """ self._is_lose = True self._is_win = False def unset_lose(self) -> None: """ Unsets this flag from being the lose condition. """ self._is_lose = False def copy_flags(self, other: "Character") -> None: """ Copy the boolean flags to the <other> object This is a helper method that should be used by the copy methods implemented in the subclasses. """ other._is_player = self._is_player other._is_push = self._is_push other._is_stop = self._is_stop other._is_lose = self._is_lose other._is_win = self._is_win def copy(self) -> 'Character': """ Returns a copy of this object itself. Need to be implemented in the subclasses """ raise NotImplementedError def handle_key_press(self, game_: 'Game') -> Tuple[int, int]: """ Process the key press input and return (dx, dy), the offsets on the x and y directions. """ key_pressed = game_.keys_pressed dx, dy = 0, 0 if key_pressed[pygame.K_LEFT]: dx -= 1 elif key_pressed[pygame.K_RIGHT]: dx += 1 elif key_pressed[pygame.K_UP]: dy -= 1 elif key_pressed[pygame.K_DOWN]: dy += 1 return dx, dy def player_move(self, game_: 'Game') -> bool: """ Detects input from the keyboard and moves the Player on the game stage based on directional key presses. Also, after the move, check if we have won or lost the game, and call the win() and lose() methods in Game accordingly """ dx, dy = self.handle_key_press(game_) if dx == 0 and dy == 0: return False return self.move(game_, dx, dy) class Meepo(Character): """ Class representing Ms. Meepo in the game. Meepo is a special Character because we want to change her image as she moves in different directions. We also want to see the movement of her "arms" as she moves. === Additional Public Attributes === walk_right: Image for walking right walk_left: Image for walking left walk_up: Image for walking up walk_down: Image for walking down """ walk_left: list walk_right: list walk_down: list walk_up: list def __init__(self, x: int, y: int) -> None: """ Initializes the Meepo Class Load the images for displaying Ms. Meepo's movement. """ super().__init__(x, y) # Add motion images self.walk_right = [load_image(PLAYER_SPRITE_R1), load_image(PLAYER_SPRITE_R2)] self.walk_left = [ pygame.transform.flip(load_image(PLAYER_SPRITE_R1), True, False), pygame.transform.flip(load_image(PLAYER_SPRITE_R2), True, False) ] self.walk_up = [load_image(PLAYER_SPRITE_U1), load_image(PLAYER_SPRITE_U2)] self.walk_down = [load_image(PLAYER_SPRITE_B1), load_image(PLAYER_SPRITE_B2)] self.image = self.walk_down[1] # TODO Task 1: Add any missing method that's necessary here. # You may also leave this for now and revisit it when you work on Task 4 # missing method def handle_key_press(self, game_: 'Game') -> Tuple[int, int]: """ Overriding the same method in the base class, adding the modification of the image depending on the direction of the move. """ # TODO Task 2: Override this method for Meepo # We want to update the image of Meepo as she moves in different # directions. Check the __init__ method to see the images that are # available for use. # Watch the video demo carefully too see how Meepo moves. Note the # movement of her "arms" and "tail". return (0, 0) # TODO Task 1: add the Wall, Rock, and Flag classes # Keep the amount of code your write to a minimal for each class (it is # supposed to be quite short), i.e., inherit and use existing classes/methods # when appropriate, write ONLY what's special about the new class. # # Hint: use the load_image() function to load the image of the character # # class Wall(...): # # class Rock(...): # # class Flag(...): # class Bush(Actor): """ Class representing the edges and unmovable objects in the game. """ def __init__(self, x: int, y: int) -> None: super().__init__(x, y) self.image = load_image(BUSH_SPRITE) # Bush is always unmovable and cannot be moved through self._is_stop = True self._is_push = False def copy(self) -> 'Bush': """ Returns a copy of the Bush object """ return Bush(self.x, self.y) class Block(Actor): """ Class for words in the game such as "Meepo", "you", "is", "rock", "lose", "victor", "flag", "push", and "stop". Blocks are used for indicating rules in the game. ================ Additional public attribute: word: the word on this block """ word: str def __init__(self, x: int, y: int, word_: str) -> None: super().__init__(x, y) self.word = word_ # Blocks are always pushable and cannot be moved through. self._is_push = True self._is_stop = True def copy(self) -> 'Block': """ Creates an identical copy of self and returns the new copy. To be implemented in the subclasses """ raise NotImplementedError # TODO Task 1: Implement the Subject and Attribute classes # Keep the amount of code your write to a minimal for each class (it is # supposed to be quite short), i.e., inherit and use existing classes/methods # when appropriate, write ONLY what's special about the new class. # # Hint: use the load_image() function to load the image of the character # class Subject(Block): """ Class representing the Subject blocks in the game, e.g., "Meepo", "Wall", "Flag", "Rock" (see SUBJECTS in settings.py) """ # TODO Task 1: Add the initializer and any other necessary method pass class Attribute(Block): """ Class representing the Attribute blocks in the game, e.g., "Push", "Stop", "Victory", "Lose", "You" """ # TODO Task 1: Add the initializer and any other necessary method pass class Is(Block): """ Class representing the Is blocks in the game. """ def __init__(self, x: int, y: int) -> None: super().__init__(x, y, " is") # Note the space in " is" self.image = load_image(IS_PURPLE) # TODO Task 1: Add any missing methods that is necessary # You may also leave this for now and revisit it when you work on Task 4 # missing method def update(self, up: Optional[Actor], down: Optional[Actor], left: Optional[Actor], right: Optional[Actor]) -> Tuple[str, str]: """ Detect horizontally and vertically if a new rule has been created in the format of a string "Subject isAttribute". up, down, left, right: the Actors that are adjacent (in the four directions) to this IS block Return a tuple of (horizontal, vertical) rules if a rule is detected in either direction, otherwise put an empty string at the tuple index. Some example return values: - ("Wall isPush", "Flag isWin)" - ("", "Rock isYou") - ("", "") Also, use IS images with different colours: - if no rule is detected on this IS block, use IS_PURPLE - if one rule is detected on this IS block, use IS_LIGHT_BLUE - if two rules are detected on this IS block, use IS_DARK_BLUE Note: We always read the rule left-to-right or up-to-down, e.g., if it reads "Push is Wall" from left to right, or from bottom to top, it is NOT a valid rule. Hint: you may use the built-in method isinstance() to check the class type of an object. """ # TODO Task 3: Complete this method. return "", "" def load_image(img_name: str, width: int = TILESIZE, height: int = TILESIZE) -> pygame.image: """ Return a pygame img of the PNG img_name that has been scaled according to the given width and size """ img = pygame.image.load(img_name).convert_alpha() return pygame.transform.scale(img, (width, height)) if __name__ == "__main__": import python_ta python_ta.check_all(config={ 'extra-imports': ['settings', 'stack', 'actor', 'pygame'] })

Related Questions

Similar orders to Assignment 1: The “Meepo is You” Game
9
Views
0
Answers
Send an email, with the current weather information from the target zip code with the weather information.
Create a web form to capture an email address and zip code along with a submit button Create a code behind to consume API from weatherapi.com Send an email, captured from the ‘email to’ textbox, with the current weather information from the t...
12
Views
0
Answers
JAVA project/paper/UML diagram
Java code (150 lines) paper(500 words) UML diagram In addition to the correctness of your code, part of your grade will be based on how organized your code is – how easy is it to read and understand. Proper spacing will aid you in this regard....
31
Views
0
Answers
Project for CS1302 using JavaFX
THE DEADLINE IS TODAY(4/21) AT 11:00!! It's not updating for some reason. I have done some of this project but it's not working and I need someone to complete it. There is a project description file, as well as my current java files. According to the desc...
13
Views
0
Answers
unity programming assignment help
Look at pdf, I can't explain well Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...