Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- >># The "new" section creates new objects that spawn into the game, such as the player's character.
- def new(self):
- # Start a new game
- # Sets player's starting score to 0.
- self.score = 0
- # We add a sprite group
- self.all_sprites = pg.sprite.Group()
- # A platforms group
- self.platforms = pg.sprite.Group()
- # A powerups group
- self.powerups = pg.sprite.Group()
- # A players group
- self.player = Player(self)
- >for plat in PLATFORM_LIST:
- # The next line takes the list platform on the settings page, and explodes it, gathering each variable from inside the list (this is just a shorter way of coding it)
- Platform(self, *plat)
- # Implements music into the game:
- # The following line means that the music file is queued up and ready to play.
- pg.mixer.music.load(path.join(self.sound_dir, 'gba1complete.ogg'))
- self.run()
- # The next run function is the start of my game loop.
- def run(self):
- # Game Loop
- #Plays music:
- #music.play() would normally only play the music track once, however there is a loop option. The -1 value means infinitely loop the track, which is what I want to happen.
- pg.mixer.music.play(loops=-1)
- self.playing = True
- while self.playing:
- # This will start the clock when the player starts playing
- self.clock.tick(FPS)
- self.events()
- self.update()
- self.draw()
- #Music ends, fadeout instead of stop (milliseconds)
- pg.mixer.music.fadeout(3000)
- def update(self):
- # Game Loop - Update
- self.all_sprites.update()
- # The following initiates a collision check for the player's character:
- # Checks if player hits a platform - only if falling (y velocity is above 0)
- if self.player.vel.y > 0:
- hits = pg.sprite.spritecollide(self.player, self.platforms, False)
- if hits:
- # Line below says that we are only going to snap to the platform if our feet are higher than the platform.
- # REVISIT
- # REVISIT
- # REVISIT
- # REVISIT
- # REVISIT
- # The following mini section explains how I prevented overlapping snaps causing problems.
- lowest = hits[0]
- # We then compare the other hits
- for hit in hits:
- # See if any are lower than the first:
- if hit.rect.bottom > lowest.rect.centery:
- lowest = hit
- if self.player.pos.x < lowest.rect.right + 10 and
- self.player.pos.x > lowest.rect.left -10:
- if self.player.pos.y < lowest.rect.centery:
- # If the player has collided with an object, then we want the player to stop falling in the y direction at that point.
- self.player.pos.y = lowest.rect.top
- # The next line sets the character's velocity to 0, so they do not carry on falling through the object at all. This allows us to run along it also.
- self.player.vel.y = 0
- self.player.jumping = False
- # If the player reaches right 1/4 of the screen
- if self.player.rect.right >= WIDTH -400 :
- # The next line moves the camera as the player moves (by the same velocity)
- self.player.pos.x -= (self.player.vel.x)
- # Next few lines move all of the platforms in the platform list on the settings page.
- for plat in self.platforms:
- # The next line means that the platforms stay behind once the player has moved.
- plat.rect.x -= (self.player.vel.x)
- # The next iteration loop is very similar to the previous one, however it works for the left side of the screen.
- if self.player.rect.right <= WIDTH -700 :
- # Here we set our boundary to the left (WIDTH - 700).
- self.player.pos.x -= (self.player.vel.x)
- # Then we move the platforms forwards, so we can retrace our steps in a level.
- for plat in self.platforms:
- plat.rect.x -= (self.player.vel.x)
- if plat.rect.right <= WIDTH - 10000:
- plat.kill()
- # If the player dies:
- # If the player hits the bottom of the screen:
- if self.player.rect.bottom > HEIGHT:
- # Next loop scrolls platforms upwards when player falls off the map to make the game more realistic.
- for sprite in self.all_sprites:
- # We do not want to scroll the platforms at a constant speed, as this is not realistic, however we want to set a max number, and using the max function here means we pick the max number between the player's vel and 10.
- sprite.rect.y -= max(self.player.vel.y, 10)
- # The next two lines kill all sprites when they reache the bottom of the screen.
- if sprite.rect.bottom < 0:
- sprite.kill()
- # The next line ends the game when the legnth of the platforms is zero, as we have gotten rid of them all.
- if len(self.platforms) == 0:
- # The next line lets the game know that the player's character is dead, and therefore ends the game session.
- self.playing = False
- def events(self):
- # Game Loop - events
- for event in pg.event.get():
- # check for closing window
- if event.type == pg.QUIT:
- if self.playing:
- self.playing = False
- self.running = False
- # Below is an IF loop that determines if the player's character should be jumping or not.
- if event.type == pg.KEYDOWN:
- # First we establish that a key is being pressed, and then identify if it is the spacebar (or jump button)
- if event.key == pg.K_SPACE:
- self.player.jump()
- def draw(self):
- # Game Loop - draw
- self.screen.fill(CYAN)
- self.all_sprites.draw(self.screen)
- self.draw_text(str(self.score), 22, BLACK, WIDTH / 2, 15)
- # *after* drawing everything, flip the display
- pg.display.flip()
- def show_start_screen(self):
- # game splash/start screen
- #Loads music again, can use a different track
- pg.mixer.music.load(path.join(self.sound_dir, 'gba1complete.ogg'))
- pg.mixer.music.play(loops=-1)
- # Fill the start screen background colour as brown to match our survival theme
- self.screen.fill(BROWN)
- # We display our string for 'TITLE', then choose font size, colour and choose where to display it on the screen.
- self.draw_text(TITLE, 48, WHITE, WIDTH / 2, HEIGHT / 4)
- # We display some information on how to play the game to the user
- self.draw_text("A and D Keys to move, Spacebar to jump!", 24, WHITE, WIDTH /2, HEIGHT / 2)
- # We tell the user how to initiate the game
- self.draw_text("Press any key to play", 24, WHITE, WIDTH / 2, HEIGHT * 3 / 4)
- # We display the high score on the starting screen:
- self.draw_text("High Score: " + str(self.highscore), 22, BROWN, WIDTH / 2, 15)
- # We flip the display so that the user actually sees this taking place
- pg.display.flip()
- self.wait_for_key()
- # This time I want to music to stop immediately.
- pg.mixer.music.stop
- def show_go_screen(self):
- # game over/continue
- if not self.running:
- # Return meaning end the function
- return
- # music
- pg.mixer.music.load(path.join(self.sound_dir, 'gba1complete.ogg'))
- pg.mixer.music.play(loops=-1)
- # Choose a background colour for the end screen
- self.screen.fill(BROWN)
- # Display game over
- self.draw_text("Game Over", 48, WHITE, WIDTH / 2, HEIGHT / 4)
- # Display the users score
- self.draw_text("Score: " + str(self.score), 24, WHITE, WIDTH /2, HEIGHT / 2)
- # Tell them how to restart the game
- self.draw_text("Press any key to play again", 24, WHITE, WIDTH / 2, HEIGHT * 3 / 4)
- # The following small section of code determines what message the player recieves - whether the player gets congratulated or commiserations.
- if self.score > self.highscore:
- self.highscore = self.score
- # The following line explains to the player that they have just got a new high score:
- self.draw_text("New High Score!", 22, BROWN, WIDTH / 2, HEIGHT / 2 + 40)
- with open(path.join(self.dir, HS_FILE), 'w') as f:
- # Then we write over the high score file and save it as a string because it is a text file.
- f.write(str(self.score))
- # Following line shows what happens if the player does not get a high score (displays current high score).
- else:
- self.draw_text("High Score: " + str(self.highscore), 22, BROWN, WIDTH / 2, HEIGHT / 2 + 40)
- # Enable the user to see this
- pg.display.flip()
- # Tells the program to stop and waits for the player to input a key to continue
- self.wait_for_key()
- pg.mixer.music.stop
- # The following method can be used in both show_start_screen and show_go_screen (end screen) to make the game wait for the player to press a key.
- def wait_for_key(self):
- # We set a variable to true.
- waiting = True
- # Then we create a while loop so that we can choose when the game waits and when the game continues.
- while waiting:
- # The next line chooses to run the start/end screen at the chosen FPS. We have defined FPS in the settings page so I will use this.
- self.clock.tick(FPS)
- for event in pg.event.get():
- if event.type == pg.QUIT:
- # To leave this screen when the player presses QUIT, we end our loop
- waiting = False
- # Then because we want our whole program to end, we also need to set running to false.
- self.running = False
- # Any other key on the keyboard
- if event.type == pg.KEYUP:
- waiting = False
- #The following method shows the text in my game.
- def draw_text(self, text, size, colour, x, y):
- # The next line gets the font object.
- font = pg.font.Font(self.font_name, size)
- # Next we render a surface for the font to be displayed on.
- # The 'True' value is my choice of whether to use anti-aliasing or not, I chose true as I believe it will make my game look smoother.
- text_surface = font.render(text, True, colour)
- # Then we generate a rectangle to help us generate it on the screen.
- text_rect = text_surface.get_rect()
- # Next we place it
- text_rect.midtop = (x, y)
- # Then we blit it onto the screen
- self.screen.blit(text_surface, text_rect)
- >g = Game()
- g.show_start_screen()
- while g.running:
- g.new()
- g.show_go_screen()
- pg.quit()
- >import pygame as pg
- from Settings import *
- # This allows pygame to access vectors.
- vec = pg.math.Vector2
- # Technically this is not a sprite, but it is another class to define so:
- class Spritesheet:
- # Utility class for loading and parsing (reading through the data file, understanding what it means) spritesheets
- # We will only need to pass it the filename
- def __init__(self, filename):
- # Here we load the spritesheet's filename and convert it
- self.spritesheet = pg.image.load(filename).convert()
- # The following function lets us pick an image from the spritesheet.
- def get_image(self, x, y, width, height):
- # First we make a surface to put the image on:
- image = pg.Surface((width, height))
- # image.blit - Blit it onto this image # (self.spritesheet, - We take this spritesheet
- #(0, 0), - Blit it at this location # (x, y, width, height)) - Choose this chunk
- image.blit(self.spritesheet, (0, 0), (x, y, width, height))
- # Then we return the image
- # Below I will scale my image so that the character is the correct size for the game, as initially it was far too large.
- # The double slash rounds the number to the nearest integer, so there are no errors.
- image = pg.transform.scale(image, (width // 2, height // 2))
- return image
- # The following section creates the image/character model e.g. size etc.
- class Player(pg.sprite.Sprite):
- # The use of 'game' in the parameter below means that the player knows about the variables from the 'main page'.
- def __init__(self, game):
- # Adds the player class to the group.
- self.groups = game.all_sprites
- # Here we set up the Sprite object.
- pg.sprite.Sprite.__init__(self, self.groups)
- # The line below is a 'copy' or a referance that the player class can use so that it knows about the game.
- self.game = game
- # The following line lets the game know whether the player is walking.
- self.walking = False
- # The following line lets the game know whether the player is jumping.
- self.jumping = False
- # The following line asks the game what frame is currently playing.
- self.current_frame = 0
- # The following variable keeps track of what time we made the last change, as each frame would be too fast, (60 per second!)
- self.last_update = 0
- # We choose for the player's image to be at the forefront, rather than the background.
- # The load_images method is called shortly after this section of code.
- self.load_images()
- self.image = self.standing_frames[0]
- # The line below removes the unwanted border around the player's character.
- self.image.set_colorkey(BLACK)
- self.rect = self.image.get_rect()
- # For example, the next line determines where the center of the rectangle that we have just created is, so that the game knows how to affect movement/hitboxes for the player's character.
- self.rect.center = (WIDTH / 2, HEIGHT /2)
- self.pos = vec(WIDTH / 2, HEIGHT / 2)
- self.vel = vec(0, 0)
- self.acc = vec(0, 0)
- # The following method load_images allows me to load all of the frames that are used for the character's animation.
- def load_images(self):
- # I start with the two standing frames:
- self.standing_frames = [self.game.spritesheet.get_image(614, 1063, 120, 191),
- self.game.spritesheet.get_image(690, 406, 120, 201)]
- for frame in self.standing_frames:
- frame.set_colorkey(BLACK)
- # Now I am going to assign my two walking frames for walking right:
- self.walk_frames_r = [self.game.spritesheet.get_image(678, 860, 120, 201),
- self.game.spritesheet.get_image(692, 1458, 120, 207)]
- # Now walk frames for the left direction:
- self.walk_frames_l = []
- # Now we will append the right ones to the left facing lists, and flip them:
- for frame in self.walk_frames_r:
- frame.set_colorkey(BLACK)
- # Here the true and false represent whether I want a horizontal flip and then a vertical flip.
- self.walk_frames_l.append(pg.transform.flip(frame, True, False))
- # Now the jumping frame:
- self.jump_frame = self.game.spritesheet.get_image(382, 763, 150, 181)
- self.jump_frame.set_colorkey(BLACK)
- # The following is a jump function that allows the player to gain velocity in the upwards direction.
- def jump(self):
- # The line below makes the character collide with the platform, however there is no drawing so the player doesn't see this.
- self.rect.x += 1
- # The next line initiates the collision, as we have done before. We collide the character with the game's platforms.
- hits = pg.sprite.spritecollide(self, self.game.platforms, False)
- # The following line means that our character is moved back up 3 spaces. The player never sees this because no drawing of it is done.
- self.rect.x -= 3
- # The next few lines mean that if there is collision, we can jump.
- if hits:
- # Now we play the jump sound at the same time as jumping:
- self.game.jump_sound.play()
- # The value below is the strength of the jump.
- self.vel.y = -PLAYER_JUMP
- # The next section creates player movement. E.g. when certain keys are pressed, the character moves in the corresponding direction.
- def update(self):
- # The following method animates and handles which frame we want to use:
- self.animate()
- # Below I have set vertical acceleration (gravity) to the variable PLAYER_GRAV, which can be found in the Settings page, allowing the character to fall.
- self.acc = vec(0, PLAYER_GRAV)
- keys = pg.key.get_pressed()
- # Here, if the left key is pressed, the player will move left and so on.
- if keys[pg.K_a]:
- self.acc.x = -PLAYER_ACC
- if keys[pg.K_d]:
- self.acc.x = PLAYER_ACC
- # Applies friction by reducing acceleration
- # By adding .x after self.acc and self.vel, gravity is allowed to work properly as we can speed up faster in the y direction.
- self.acc.x += self.vel.x * PLAYER_FRICTION
- # Equations of motion
- self.vel += self.acc
- # The following two lines mean that if we are moving less than 0.1 of a pixel per tick, the player's velocity will get set to 0. This is so that our walking animations stop when we are standing still.
- if abs(self.vel.x) < 0.1:
- # Velocity is set to 0.
- self.vel.x = 0
- self.pos += self.vel + 0.5 * self.acc
- #Wrap around the sides of the screen
- if self.pos.x > WIDTH:
- self.pos.x = 0
- if self.pos.x < 0:
- self.pos.x = WIDTH
- # The next line lets the game know that I want the center of the player's character to be considered the center of the screen.
- self.rect.midbottom = self.pos
- # The recently referred to animate method is used:
- def animate(self):
- # Find out how many ticks have occured since the game was opened:
- now = pg.time.get_ticks()
- # The following small section determines if the player is standing still or not.
- # Is the player still?
- if self.vel.x != 0:
- # If they are not still, then walking is true.
- self.walking = True
- else:
- # If they are still, then walking is false.
- self.walking = False
- # Show Walk Animation:
- if self.walking:
- # here we set the frequency of the occuring updates (milliseconds)
- if now - self.last_update > 100:
- # We call for an update
- self.last_update = now
- # We almost copy what we used for the update loop below
- self.current_frame = (self.current_frame + 1) % len(self.walk_frames_l)
- # We set the bottom of the sprite to the right location whilst we are walking
- bottom = self.rect.bottom
- # Before we set the image for the next frame, we decide if we are walking left or right:
- if self.vel.x > 0:
- # If our velocity is more than 0, we are clearly moving right
- self.image = self.walk_frames_r[self.current_frame]
- else:
- # If our velocity is less than 0, we are clearly moving left
- self.image = self.walk_frames_l[self.current_frame]
- # We request our new rectangle to find the bottom of the character with
- self.rect = self.image.get_rect()
- # We then set the bottom of the character's hitbox again.
- self.rect.bottom = bottom
- # If the player is idle, we want to display the standing frame:
- if not self.jumping and not self.walking:
- # The following is in milliseconds, and determines the time lapse since the last update:
- if now - self.last_update > 280:
- # We call for an update to occur now:
- self.last_update = now
- # Now we change the current frame.
- self.current_frame = (self.current_frame + 1) % len(self.standing_frames)
- # The bottom variable holds where the bottom of our player's rectangle needs to be.
- bottom = self.rect.bottom
- self.image = self.standing_frames[self.current_frame]
- # the following line gets the new rectangle for the new frame we switched to.
- self.rect = self.image.get_rect()
- # the next line keeps the 'bottom' variable that we had for the last frame.
- self.rect.bottom = bottom
- # The next class defines all of the platforms in the game.
- class Platform(pg.sprite.Sprite):
- # The next line shows how when we want to create a new platform object, we will give it a x and a y coordinate, along with a width and a height.
- def __init__(self, game, x, y):
- # Adds the platform class to the group.
- self.groups = game.all_sprites, game.platforms
- pg.sprite.Sprite.__init__(self, self.groups)
- self.game = game
- # First, we create the image.
- self.image = pg.Surface((w, h))
- # Hext, we choose a colour for the platform.
- self.image.fill(BROWN)
- # We make it a rectangular shape.
- self.rect = self.image.get_rect()
- # Then we place it at it's predetermined coordinates.
- self.rect.x = x
- self.rect.y = y
- #Powerups class
- class Pow(pg.sprite.Sprite):
- # I pass the class 'self', 'game' and 'plat'.
- def __init__(self, game, plat):
- # I create my list of groups:
- self.groups = game.all_sprites, game.powerups
- # I then initialise them (including groups):
- pg.sprite.Sprite.__init__(self, self.groups)
- # The following line allows me to use 'game'
- self.game = game
- # The following line allows me to use 'plat'
- self.plat = plat
- # Now we need different types of platforms.
- # The first type I am creating is called 'boost', it will shoot the player upwards a litte bit.
- self.type = choice(['boost'])
- # This is the art that will be used for my 'boost' powerup.
- self.image = self.game.spritesheet.get_image(820, 1805, 71, 70)
- self.image.set_colorkey(BLACK)
- self.rect = self.image.get_rect()
- # The following line sets the powerup's location to the center of the platform.
- self.rect.centerx = self.plat.rect.centerx
- self.rect.bottom = self.plat.rect.top - 5
- def update(self):
- self.rect.bottom = self.plat.rect.top -5
- if not self.game.platforms.has(self.plat):
- # If this loop returns false, we will delete the powerup as well.
- self.kill()
- >TITLE = "Survival Game"
- WIDTH = 1000
- HEIGHT = 800
- FPS = 60
- HS_FILE = "highscore.txt"
- PLAYER_ACC = 0.5
- PLAYER_FRICTION = -0.12
- PLAYER_GRAV = 0.3
- PLAYER_JUMP = 10
- FONT_NAME = 'Echelon'
- SPRITESHEET = "spritesheet_jumper.png"
- # Starting platforms
- # The following list includes all the platforms I am going to be using in my game, and each platform takes in four values each. The x and y coordinates, and also the height and width of the platforms themselves.
- # (x, y, Width, Height)
- PLATFORM_LIST = [
- # Floor platforms
- (0, HEIGHT - 40, WIDTH + 500, 40),
- (2200, HEIGHT - 40, WIDTH + 100, 40),
- (4000, HEIGHT - 40, WIDTH + 100, 40),
- (6000, HEIGHT - 40, WIDTH + 100, 40),
- # Starting 3 platforms
- (650, HEIGHT - 125, WIDTH - 600, 20),
- (650, HEIGHT - 250, WIDTH - 600, 20),
- (650, HEIGHT - 375, WIDTH - 600, 20),
- # Middle Layer of short platforms
- (1100, HEIGHT - 250, WIDTH - 800, 30),
- (1500, HEIGHT - 250, WIDTH - 800, 30),
- (2000, HEIGHT - 250, WIDTH - 800, 30),
- (2500, HEIGHT - 250, WIDTH - 800, 30),
- (3000, HEIGHT - 250, WIDTH - 800, 30),
- (3500, HEIGHT - 250, WIDTH - 800, 30),
- # Lower Layer of short platforms
- (1175, HEIGHT - 180, WIDTH - 800, 30),
- (1575, HEIGHT - 180, WIDTH - 800, 30),
- (2075, HEIGHT - 180, WIDTH - 800, 30),
- (2575, HEIGHT - 180, WIDTH - 800, 30),
- (3075, HEIGHT - 180, WIDTH - 800, 30),
- (3575, HEIGHT - 180, WIDTH - 800, 30),
- # Upper Layer of short platforms
- (1150, HEIGHT - 320, WIDTH - 800, 30),
- (1550, HEIGHT - 320, WIDTH - 800, 30),
- (2050, HEIGHT - 320, WIDTH - 800, 30),
- (2550, HEIGHT - 320, WIDTH - 800, 30),
- (3050, HEIGHT - 320, WIDTH - 800, 30),
- (3550, HEIGHT - 320, WIDTH - 800, 30),
- # In between platforms (Lowest)
- (1250, HEIGHT - 115, WIDTH - 800, 30),
- (1750, HEIGHT - 115, WIDTH - 800, 30),
- (2250, HEIGHT - 115, WIDTH - 800, 30),
- (2750, HEIGHT - 115, WIDTH - 800, 30),
- (3250, HEIGHT - 115, WIDTH - 800, 30),
- (3750, HEIGHT - 115, WIDTH - 800, 30)
- ]
- WHITE = (255, 255, 255)
- BLACK = (0, 0, 0)
- RED = (255, 0, 0)
- GREEN = (0, 255, 0)
- BLUE = (0, 0, 255)
- YELLOW = (255, 255, 0)
- CYAN = (0, 255, 255)
- BROWN = (200, 140, 101)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement