Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Starter code for an adventure type game.
- # University of Utah, David Johnson, 2017.
- # This code, or code derived from this code, may not be shared without permission.
- # Current implementations:
- # Right now this game has most of the elements that the fully fleshed out version will have.
- # We have 5 items in the game at the moment that the character can add to their inventory.
- # When an item is added to the inventory the player can press the tab key to bring the inventory up.
- # When the player receives the scanner item they can press caps lock to use the scanner and receive a hint.
- # If the player touches the flames from the fire then the player gets sent to a different location on the map.
- # After receiving the scanner the player can receive a message to avoid the fire character.
- import sys, pygame, math, random
- # This function loads a series of sprite images stored in a folder with a
- # consistent naming pattern: sprite_# or sprite_##. It returns a list of the images.
- def load_piskell_sprite(sprite_folder_name, number_of_frames):
- frame_counts = []
- padding = math.ceil(math.log(number_of_frames, 10))
- for frame in range(number_of_frames):
- folder_and_file_name = sprite_folder_name + "/sprite_" + str(frame).rjust(padding, '0') + ".png"
- frame_counts.append(pygame.image.load(folder_and_file_name).convert_alpha())
- return frame_counts
- #This version of the game has no tiles and works directly off a png->pixel background. There
- # are two 'coordinate systems' in use: a map coordinate system that is static, such that the player moves one map
- # map unit per frame and all items have fixed map coordinates, and a pixel coordinate system that remains oriented
- #on the player. The ration between these two coordinate systems is the 'pixelscale', defined below.
- # loc_init takes in coordinates on a fixed map scale and outputs the pixel coordinates.
- # The '350' and '250' are because the player is at the center of the screen, at (350,250).
- def loc_init(x,y,pixelscale):
- return (x*pixelscale[0] +350,y*pixelscale[1]+250)
- # The main loop handles most of the game
- def main():
- # Initialize pygame
- pygame.init()
- screen_size = width, height = (700, 500)
- screen = pygame.display.set_mode(screen_size)
- #this determines the number of pixels in one 'map unit', effectively setting
- # a scale size for the game. Previously this would have corresponded to tile_rect.width and tile_rect.height
- pixelscale = (16,16)
- # create the hero character
- hero = load_piskell_sprite("hero", 11)
- hero_rect = hero[0].get_rect()
- hero_rect.center = (350, 250)
- # create the aliem character
- aliem = load_piskell_sprite("aliem", 15)
- aliem_rect = hero[0].get_rect()
- aliem_rect.center = (750, 150)
- # create the fire "character"
- fire = load_piskell_sprite("flame", 13)
- fire_rect = fire[0].get_rect()
- fire_rect.center = loc_init(191,102,pixelscale)
- fire2 = load_piskell_sprite("flame", 13)
- fire2_rect = fire[0].get_rect()
- fire2_rect.center = loc_init(90,120,pixelscale)
- # this defines the start and end points of the fire bouncing loop.
- # by making these rectangles, they transform as the player moves just like
- # all other background sprites, allowing the bouncing to occur in the map
- # reference frame, not the player reference frame.
- firestart_rect = fire_rect.copy()
- firestart_rect.center = loc_init(191,102,pixelscale)
- fireend_rect = fire_rect.copy()
- fireend_rect.center = loc_init(106,101,pixelscale)
- fire2start_rect = fire2_rect.copy()
- fire2start_rect.center = loc_init(90,120,pixelscale)
- fire2end_rect = fire2_rect.copy()
- fire2end_rect.center = loc_init(133,120,pixelscale)
- frame_count = 0;
- # add a maintenance card
- maintenance = pygame.image.load("maintenance.png").convert_alpha()
- maintenance_rect = maintenance.get_rect()
- maintenance_rect.center = loc_init(66,60,pixelscale)
- # add some fuel
- fuel = pygame.image.load("fuel.png").convert_alpha()
- fuel_rect = fuel.get_rect()
- fuel_rect.center = loc_init(40,133,pixelscale)
- # add a gun
- gun = pygame.image.load("gun.png").convert_alpha()
- gun_rect = gun.get_rect()
- # gun_rect.center = 750, 400
- gun_rect.center = loc_init(85,93,pixelscale)
- # add a blow torch
- torch = pygame.image.load("blow_torch.png").convert_alpha()
- torch_rect = torch.get_rect()
- torch_rect.center = loc_init(107,169,pixelscale)
- # add a scanner
- scanner = pygame.image.load("scanner.png").convert_alpha()
- scanner_rect = scanner.get_rect()
- scanner_rect.center = loc_init(125,46,pixelscale)
- #The starting position of the human character
- HumanMaploc = 100,100
- (mapx, mapy) = HumanMaploc
- map = pygame.image.load("map/Map.png").convert()
- map_rect = map.get_rect()
- map_rect.center = 3540,1930
- # Load a minimap
- world = pygame.image.load("map/Map.png").convert()
- world_rect = world.get_rect()
- # Set the offset into the map
- minimap = world.copy()
- minimap_rect = minimap.get_rect()
- # The clock helps us manage the frames per second of the animation
- clock = pygame.time.Clock()
- # Mostly used to cycle the animation of sprites
- frame_count = 0;
- Hero_anim_count=0
- # variable to show if we are still playing the game
- playing = True
- # variable for hero direction
- is_facing_left = True
- # Variable to track text on the screen. If you set the dialog string to something and set the position and the
- # counter, the text will show on the screen for dialog_counter number of frames.
- dialog_counter = 0
- dialog = ''
- dialog_position = (0, 0)
- dialog2_counter = 0
- dialog2 = ''
- dialog2_position = (0, 0)
- # Load font
- pygame.font.init() # you have to call this at the start,
- # if you want to use this module.
- myfont = pygame.font.SysFont('Comic Sans MS', 13)
- invfont = pygame.font.SysFont('Helvetica', 20)
- # create the inventory and make it empty
- inventory = {}
- # This list should hold all the sprite rectangles that get shifted with a key press.
- rect_list = [aliem_rect, fire_rect, gun_rect, fuel_rect, maintenance_rect, torch_rect, scanner_rect, map_rect, firestart_rect,
- fireend_rect,fire2_rect,fire2start_rect,fire2end_rect]
- for rect in rect_list:
- rect.move_ip(-HumanMaploc[0]*pixelscale[0], -HumanMaploc[1]*pixelscale[1])
- just_used_scanner = False
- RoadSlow = False
- # This function checks to see if a pixel color corresponds to a hard boundary that the player
- # should not be able to pass through.
- def hitting_obstacle_query(PixelColor):
- hitting_obstacle = False
- # blue walls of the facility
- if (153 < PixelColor[0] < 160) and (195 < PixelColor[1] < 200) and (215 < PixelColor[2] < 220):
- hitting_obstacle = True
- # green doors of the facility
- if (16 <= PixelColor[0] <= 16) and (45 <= PixelColor[1] <= 45) and (
- 14 <= PixelColor[2] <= 14) and "torch" and "fuel" not in inventory:
- hitting_obstacle = True
- # red doors of the facility
- if (62 <= PixelColor[0] <= 62) and (15 <= PixelColor[1] <= 15) and (
- 13 <= PixelColor[2] <= 13) and "maintenance" not in inventory:
- hitting_obstacle = True
- return (hitting_obstacle)
- # Loop while the player is still active
- while playing:
- # start the next frame
- screen.fill((170, 190, 190))
- # Check events by looping over the list of events
- for event in pygame.event.get():
- if event.type == pygame.QUIT:
- playing = False
- # diagnostics - outputs location on the map grid
- print(mapx)
- print(mapy)
- movement_x = 0
- movement_y = 0
- keys = pygame.key.get_pressed()
- # RoadSlow is a boolean that says whether you're being slowed by being on the road or not.
- # Being slowed slows the animation time for the walking animation and reduces character speed
- # by allowing motion/animation only every other frame.
- # if you're being slowed, spend one frame doing nothing
- if (RoadSlow):
- RoadSlow = False
- Hero_anim_count -=1
- else:
- # if you're not being slowed, or if this is in the half of the slowed frames that do allow motion, proceed here
- # deltamapx/y determine movement in the map coordinate system and move by one unit per frame of motion.
- #deltamovement_x/y determine movement in the pixel coordinate system and move by one pixelscale unit per
- # frame of motion.
- deltamapx=0
- deltamapy=0
- deltamovement_x=0
- deltamovement_y=0
- # 'is_facing_left' is a boolean that determines which direction the player sprite should be facing.
- if keys[pygame.K_LEFT]:
- is_facing_left = False
- deltamovement_x += -pixelscale[0]
- deltamapx += -1
- if keys[pygame.K_RIGHT]:
- is_facing_left = True
- deltamovement_x += pixelscale[0]
- deltamapx += 1
- if keys[pygame.K_UP]:
- deltamovement_y += -pixelscale[1]
- deltamapy += -1
- if keys[pygame.K_DOWN]:
- deltamovement_y += +pixelscale[1]
- deltamapy += 1
- # apply the appropriate changes to the coordinates
- mapx += deltamapx
- mapy += deltamapy
- movement_x +=deltamovement_x
- movement_y +=deltamovement_y
- # 'footpos' is the position of the player's feet in map coordinates. When dealing with detection, or walking on
- # different terrain, it makes more sense to ask 'where are the player's feet?' than 'where is the player's head?'
- # footpos is positioned 3 pixels below the player's head.
- footposx = int(min(max(mapx,0),world.get_width()/pixelscale[0]))
- footposy = int(min(mapy+3,int(world.get_height()/pixelscale[1] - 1)))
- # PixelCol finds the color of the pixel at the player's feet
- PixelCol = world.get_at((footposx*pixelscale[0],footposy*pixelscale[1]))
- #if the player's feet are on the slippery road, distinguished by its brown-purple color, set RoadSlow to true.
- if (100<PixelCol[0]<155) and (70<PixelCol[1]<115) and (PixelCol[2]==84):
- RoadSlow = True
- # If the player is walking into an obstacle, he should not move, regardless of the circumstances.
- # The code below calls 'hitting_obstacle_query' and checks if the player is walking into a wall. If
- # so, all motion changes are reversed immediately.
- if hitting_obstacle_query(PixelCol):
- mapx -= deltamapx
- mapy -= deltamapy
- movement_x -=deltamovement_x
- movement_y -=deltamovement_y
- # PixelCol is useful for diagnostics to see what color/terraint the player is on.
- print(PixelCol)
- # Boundaries for fire "character"
- def bounce_rect_between_two_positions(rect, start_pos, end_pos, num_frame, frame_count):
- if frame_count % num_frame < num_frame / 2:
- new_pos_x = start_pos[0] + (end_pos[0] - start_pos[0]) * (
- frame_count % (num_frame / 2)) / (
- num_frame / 2)
- new_pos_y = start_pos[1] + (end_pos[1] - start_pos[1]) * (
- frame_count % (num_frame / 2)) / (
- num_frame / 2)
- else:
- new_pos_x = end_pos[0] + (start_pos[0] - end_pos[0]) * (frame_count % (num_frame / 2)) / (
- num_frame / 2)
- new_pos_y = end_pos[1] + (start_pos[1] - end_pos[1]) * (frame_count % (num_frame / 2)) / (
- num_frame / 2)
- rect.center = (new_pos_x, new_pos_y)
- bounce_rect_between_two_positions(fire_rect, firestart_rect.center, fireend_rect.center, 100, frame_count)
- bounce_rect_between_two_positions(fire2_rect, fire2start_rect.center, fire2end_rect.center, 100, frame_count)
- bounce_rect_between_two_positions(aliem_rect, fire2start_rect.center, fire2end_rect.center, 100, frame_count)
- # if the player is not moving at all, 'is_standing_still' is true. This replaces the walking animation with a simple
- #standing animation.
- is_standing_still = False
- if not keys[pygame.K_LEFT] and not keys[pygame.K_RIGHT] and not keys[pygame.K_UP] and not keys[pygame.K_DOWN]:
- is_standing_still = True
- # boudaries of the map, with a little extra buffer. Prevents movement off the map.
- if mapx < 0:
- mapx = 0
- movement_x = 0
- if mapx > int(world.get_width()/pixelscale[0] - 1) :
- mapx = int(world.get_width()/pixelscale[0] - 1)
- movement_x = 0
- if mapy < 0:
- mapy = 0
- movement_y = 0
- if mapy > int(world.get_height()/pixelscale[1] - 2) :
- mapy = int(world.get_height()/pixelscale[1] -2)
- movement_y = 0
- # Move all the sprites in the scene by movement amount.
- # You can still move the rect of an individual sprite to make
- # it move around the landscape.
- for rect in rect_list:
- rect.move_ip(-movement_x, -movement_y)
- # Check for touching the gun.
- if hero_rect.colliderect(gun_rect) and "gun" not in inventory:
- inventory["gun"] = "Gun"
- dialog = "Gun added to inventory"
- dialog_counter = 30
- dialog_position = (300, 200)
- # Check for touching the blow torch.
- if hero_rect.colliderect(torch_rect) and "blow torch" not in inventory:
- inventory["torch"] = "Blow Torch"
- dialog = "Blow torch added to inventory"
- dialog_counter = 30
- dialog_position = (300, 200)
- # Check for touching the fuel.
- if hero_rect.colliderect(fuel_rect) and "fuel" not in inventory:
- inventory["fuel"] = "Fuel"
- dialog = "Fuel added to the inventory"
- dialog_counter = 30
- dialog_position = (300, 200)
- # Check for touching the maintenance card.
- if hero_rect.colliderect(maintenance_rect) and "maintenance" not in inventory:
- inventory["maintenance"] = "Maintenance Card"
- dialog = "Maintenance Card added to inventory"
- dialog_counter = 30
- dialog_position = (300, 200)
- # Check for touching the scanner.
- if hero_rect.colliderect(scanner_rect) and "scanner" not in inventory:
- inventory["scanner"] = "Scanner"
- dialog = "Scanner added to inventory"
- dialog_counter = 30
- dialog_position = (300, 200)
- # here is a simple transport mechanism if the player touches the fire and aliem.
- # transportloc gives the location in map coordinates where the player is transported
- transportloc = (100, 100)
- if hero_rect.colliderect(aliem_rect) and "gun" not in inventory:
- delta_x = -mapx + transportloc[0]
- delta_y = -mapy + transportloc[1]
- # delta_x and delta_y give the distance, in map coordinates, from the player's location to the transport location
- if hero_rect.colliderect(fire_rect) or hero_rect.colliderect(fire2_rect):
- delta_x = -mapx + transportloc[0]
- delta_y = -mapy + transportloc[1]
- # the entire map is displaced to the transport location
- mapx = transportloc[0]
- mapy = transportloc[1]
- # all rectangles must be translated in a manner consistent witht he map transformation. The different scaling between the map
- # coordinate system and the pixel scale is the reason for the factor of tile_rect.width/height.
- for rect in rect_list:
- rect.move_ip(-delta_x * pixelscale[0], -delta_y * pixelscale[1])
- if "scanner" in inventory:
- dialog = 'Whoa! Watch out for flames, their positronic field might teleport you to an entangled location!'
- dialog_counter = 30
- dialog_position = (200, 200)
- # Draw the map
- screen.blit(map, map_rect)
- #draw the bouncing fire
- screen.blit(fire[frame_count % len(fire)], fire_rect)
- screen.blit(fire2[frame_count % len(fire)], fire2_rect)
- screen.blit(aliem[frame_count % len(aliem)], aliem_rect)
- # Only draw the gun if it hasn't been picked up
- if "gun" not in inventory:
- screen.blit(gun, gun_rect)
- if "fuel" not in inventory:
- screen.blit(fuel, fuel_rect)
- if "maintenance" not in inventory:
- screen.blit(maintenance, maintenance_rect)
- if "torch" not in inventory:
- screen.blit(torch, torch_rect)
- if "scanner" not in inventory:
- screen.blit(scanner, scanner_rect)
- # Pick the sprite frame to draw
- hero_sprite = hero[Hero_anim_count % len(hero)]
- # Flip the sprite depending on direction
- if not is_facing_left:
- hero_sprite = pygame.transform.flip(hero_sprite, True, False)
- if is_standing_still:
- hero_sprite = hero[0]
- screen.blit(hero_sprite, hero_rect)
- #Draw a rectangle around something
- # pygame.draw.rect(screen, (0, 0, 0), hero_rect, 1)
- # Show items in inventory.
- # Respond differently depending on inventory status
- # If the 'tab' button is pressed, the public names of the items in the inventory
- # (the values in the 'inventory' dictionary) fill up the list 'dialog2vec'
- # and are presented on screen for as long as the player holds down tab.
- dialog2vec = []
- if keys[pygame.K_TAB]:
- dialog2vec = ["Inventory:"]
- for x in inventory:
- dialog2vec.append(inventory[x]) # We change this line to call the value instead of the key
- dialog2_counter = 5000000
- dialog2_position = (0, 0)
- if dialog2vec:
- counter = 0
- pygame.draw.rect(screen, (200, 220, 220), [0, 0, 200, 200])
- for invitem in dialog2vec:
- textsurface2 = invfont.render(invitem, True, (0, 0, 0))
- screen.blit(textsurface2, (0, 0 + 35 * counter))
- counter += 1
- # Track how long the dialog is on screen
- dialog2_counter -= 1
- if dialog2_counter == 0:
- screen.blit(textsurface2, (0, 0 + 35 * counter))
- #the "35*counter" is used to space out inventory items verticallye
- # draw any dialog
- if dialog:
- pygame.draw.rect(screen, (200, 220, 220), [50, 425, 600, 50])
- textsurface = myfont.render(dialog, True, (0, 0, 0))
- screen.blit(textsurface, (75, 430))
- # Track how long the dialog is on screen
- dialog_counter -= 1
- if dialog_counter == 0:
- dialog = ''
- #draw the minimap. First we make a smaller version of the game map and the hero sprite.
- # These are drawn into the upper right corner. The position of the human in the map is converted to its
- #appropriate position on the minimap
- # the minimap is 200 pixels across, 100 down
- minimap_size = (200,100)
- # the minimap is positioned to be at the upper right of the map
- minimap_pos = (500,0)
- # scale the game map to the appropriate size
- minimap2 = pygame.transform.scale(minimap,minimap_size)
- # only show the minimap if the 'm' key is hit
- if keys[pygame.K_m]:
- # make the minimap sprite (here he's 5x10 pixels)
- hero_sprite_mini = pygame.transform.scale(hero_sprite,(5,10))
- # take the hero's location and scale it by the ratio of the minimaps size to the real map size
- hero_mmposx = mapx*minimap_size[0]/400
- hero_mmposy = mapy*minimap_size[1]/212
- #draw the minimap
- screen.blit(minimap2, (500, 0))
- # draw the hero (note that the position is translated because of the minimap position)
- screen.blit(hero_sprite_mini,(hero_mmposx+minimap_pos[0],hero_mmposy+minimap_pos[1]))
- # if the player does not have the scanner and hits caps lock, a random hint message will appear.
- # if the player has the scanner and hits caps lock, a random hint message will appear.
- # a new message won't appear until the player turns on caps lock again.
- no_scanner_dialog = ['The scanner could tell me more information','I need a maintenance card to access the red doors.']
- scanner_dialog = ['Scanning for life signs...', 'Ship damaged beyond repair', 'Doors are currently inoperable',
- 'Recommendation: Utilize the blow torch to open doors.', 'These doors looks strange', 'Why is there an oil spill outside?', 'I better be careful' , 'Why is the TV facing a wall?',
- "The mother ship can't save you so your ass is goin' get it", "This games needs more fleshing out..." ]
- while keys[pygame.K_CAPSLOCK] and "scanner" in inventory and (just_used_scanner == False):
- dialog = random.choice(scanner_dialog)
- dialog_counter =60
- dialog_position = (300, 200)
- just_used_scanner = True
- if (not keys[pygame.K_CAPSLOCK]) and "scanner" in inventory and (just_used_scanner == True):
- just_used_scanner = False
- while keys[pygame.K_CAPSLOCK] and "scanner" not in inventory and (just_used_scanner == False):
- dialog = random.choice(no_scanner_dialog)
- dialog_counter = 30
- dialog_position = (300, 200)
- just_used_scanner = True
- if (not keys[pygame.K_CAPSLOCK]) and "scanner" not in inventory and (just_used_scanner == True):
- just_used_scanner = False
- # Bring drawn changes to the front
- pygame.display.update()
- frame_count += 1
- Hero_anim_count +=1
- # 30 fps
- clock.tick(10)
- # loop is over
- pygame.quit()
- sys.exit()
- # Start the program
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement