I'm attempting to add a segment to the player in my snake clone when the food.rect and snake.rect collide. The code inside the function however will not execute.
def add_segment(self,food):
if self.rect.colliderect(food.rect):
snake_segment = Snake(GREEN,RECTANGLE_WIDTH,RECTANGLE_HEIGHT)
self.body.append(snake_segment)
print('this code works!')
Here is the rest of my code if you need it. I have been struggling with this issue for days, so any help would be much appreciated!
import pygame,sys,random
from pygame.locals import *
pygame.init()
WINDOW_HEIGHT = 500
WINDOW_WIDTH = 500
RECTANGLE_HEIGHT = 20
RECTANGLE_WIDTH = 20
GREEN = (0,255,0)
WHITE = (255,255,255)
BLACK = (0,0,0)
RED = (255,0,0)
clock = pygame.time.Clock()
SCREEN = pygame.display.set_mode((WINDOW_WIDTH,WINDOW_HEIGHT))
pygame.display.set_caption("Snake")
class Snake(object):
def __init__(self, color, width, height):
self.body = []
self.image = pygame.Surface((width,height))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.speed = 20
self.direction = 'right'
self.body = []
self.living = True
self.move = (0,0)
def movement(self):
self.rect.move_ip(self.move)
self.rect.clamp_ip(SCREEN.get_rect())
def blit(self):
SCREEN.blit(self.image,self.rect)
def update(self,food):
self.add_segment(food)
self.draw_snake()
self.movement()
print(self.rect.colliderect(food.rect))
print(self.body)
def add_segment(self,food):
if self.rect.colliderect(food.rect):
snake_segment = Snake(GREEN,RECTANGLE_WIDTH,RECTANGLE_HEIGHT)
self.body.append(snake_segment)
print('this code works!')
def draw_snake(self):
if len(self.body) == 0:
self.blit()
elif len(self.body) >= 1:
for snake_segment in self.body:
snake_segment.blit()
class Food(object):
def __init__(self,color,width,height):
self.image = pygame.Surface((width,height))
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.x = random.randrange(20,500,20)
self.rect.y = random.randrange(20,500,20)
self.state = 'uneaten'
def check_eaten(self,snake):
if snake.rect.colliderect(self.rect):
self.state = 'eaten'
def blit(self):
SCREEN.blit(self.image,self.rect)
def update_state(self,snake):
self.check_eaten(snake)
if self.state == 'uneaten':
self.blit()
elif self.state == 'eaten':
self.rect.x = random.randrange(0,500,20)
self.rect.y = random.randrange(0,500,20)
if self.rect.x == snake.rect.x or self.rect.x == snake.rect.y:
self.rect.x = random.randrange(0,500,20)
self.rect.y = random.randrange(0,500,20)
self.blit()
self.state = 'uneaten'
def update(self,snake):
self.update_state(snake)
print(self.state)
def event_loop(snake,food):
while True:
SCREEN.fill(BLACK)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_RIGHT:
snake.move = (snake.speed,0)
snake.direction = 'right'
elif event.key == K_LEFT:
snake.move = (-snake.speed,0)
snake.direction = 'left'
elif event.key == K_UP:
snake.move = (0,-snake.speed)
snake.direction = 'up'
elif event.key == K_DOWN:
snake.move = (0,snake.speed)
snake.direction = 'down'
food.update(snake)
snake.update(food)
pygame.display.update()
clock.tick(5)
SNAKE = Snake(GREEN,RECTANGLE_WIDTH,RECTANGLE_HEIGHT)
FOOD = Food(RED,RECTANGLE_WIDTH,RECTANGLE_HEIGHT)
event_loop(SNAKE,FOOD)
It' all a matter of order.
food.update(snake) tests if the food collides with the shake and place a the food at a new position.
snake.update(food) test is the snake collides with the food and appends a segment to the snake.
So if food.update(snake) is executed before snake.update(food), then the snake will never eat the food, because the food is moved away before:
food.update(snake)
snake.update(food)
snake.update(food)
food.update(snake)
The snake is never at the position where it is drawn, because the snake is drawn self.draw_snake() before it is moved self.movement().
You've to do it in this order:
Move the snake
Test if the snake is on the food
Draw the snake
class Snake(object):
# [...]
def update(self,food):
self.movement()
self.add_segment(food)
self.draw_snake()
Related
This question already has answers here:
How can i shoot a bullet with space bar?
(1 answer)
How do I stop more than 1 bullet firing at once?
(1 answer)
Closed 1 year ago.
I have created bullets for my car sprite to shoot but when I press space bar the bullet sprite comes out but disappears.When I press the space bar the bullet comes out but disappears right there instead of traveling all the way up to the top of the pygame screen like I want it to. How can I fix this?? I have tried a lot of different things now but I'm stuck.
autopilot.py code:
import pygame
import debris
import car
pygame.init()
WIDTH = 1000
HEIGHT = 400
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("AutoPilot")
screen.fill((255,255,255))
#fps
FPS = 120
clock = pygame.time.Clock()
#background img
bg = pygame.image.load('background/street.png').convert_alpha()
#define variables
######################CAR/DEBRIS##########################
car = car.Car(1,5)
debris = debris.Debris(1,5)
##########################################################
#groups
car_group = pygame.sprite.Group()
car_group.add(car)
debris_group = pygame.sprite.Group()
debris_group.add(debris)
#game runs here
run = True
while run:
#draw street
screen.blit(bg,[0,0])
#update groups
car_group.update()
#car_group.draw(screen)
#draw debris
debris.draw()
#draw car
car.draw()
car.move()
#update bullets
car.bullet_update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#check if key is down
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
if event.key == pygame.K_a:
car.movingLeft = True
if event.key == pygame.K_d:
car.movingRight = True
#shoot bullets
if event.key == pygame.K_SPACE:
car.shoot()
#check if key is up
if event.type == pygame.KEYUP:
if event.key == pygame.K_a:
car.movingLeft = False
if event.key == pygame.K_d:
car.movingRight = False
#update the display
pygame.display.update()
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
car.py code:
import pygame
#screen height & width
WIDTH = 1000
HEIGHT = 400
screen = pygame.display.set_mode((WIDTH,HEIGHT))
#car class
class Car(pygame.sprite.Sprite):
def __init__(self, scale, speed):
pygame.sprite.Sprite.__init__(self)
#load bullets
self.vel = 10
self.bullet = pygame.image.load('car/bullet.png').convert_alpha()
self.rect1 = self.bullet.get_rect()
self.y = float(self.rect1.y)
self.speed = speed
#self.x = x
#self.y = y
self.moving = True
self.frame = 0
self.flip = False
self.direction = 0
#load car
self.images = []
img = pygame.image.load('car/car.png').convert_alpha()
img = pygame.transform.scale(img, (int(img.get_width()) * scale, (int(img.get_height()) * scale)))
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
self.update_time = pygame.time.get_ticks()
self.movingLeft = False
self.movingRight = False
self.rect.x = 465
self.rect.y = 325
#draw car to screen
def draw(self):
screen.blit(self.image,(self.rect.centerx, self.rect.centery))
#move car
def move(self):
# reset the movement variables
dx = 0
dy = 0
# moving variables
if self.movingLeft and self.rect.x > 33:
dx -= self.speed
self.flip = True
self.direction = -1
if self.movingRight and self.rect.x < 900:
dx += self.speed
self.flip = False
self.direction = 1
# update rectangle position
self.rect.x += dx
self.rect.y += dy
#shoot bullets
def shoot(self):
bullets = [self.bullet]
for _ in bullets:
screen.blit(self.bullet,(self.rect.x + 32, self.rect.y))
#update bullet travel
def bullet_update(self):
self.y += self.vel
self.rect1 = self.y
Add a bullet list to the Car class:
class Car(pygame.sprite.Sprite):
def __init__(self, scale, speed):
# [...]
self.bullet_list = []
Add a the position of the bullet to the list when SPACE is pressed. The starting position of the bullet is the position of the car:
class Car(pygame.sprite.Sprite):v
# [...]
def shoot(self):
self.bullet_list.append([self.rect.x, self.rect.y])
Move the bullets:
class Car(pygame.sprite.Sprite):
# [...]
def bullet_update(self):
for bullet_pos in self.bullet_list[:]:
bullet_pos[0] += self.vel
if bullet_pos[0] > 1000:
self.bullet_list.remove(bullet_pos)
Draw the bullets with the car:
class Car(pygame.sprite.Sprite):
# [...]
def draw(self):
for bullet_pos in self.bullet_list:
screen.blit(self.bullet, bullet_pos)
screen.blit(self.image, self.rect.center)
I'm trying to make a Home Screen for two games in pygame, I changed the first game's name to module1 in the code Im providing and the Home Screen to Mainscreen
module1 is already done and now I'm just trying to get the Main Menu script to import the maingame when I click on the play button that I already have on the screen display, then when I finish the game (health reaches 0) , if I want to go back to the Main Menu I should just click anywhere on the "game over" screen that should appear when health reaches 0 or press escape.
here is what I tried:
this is the whole game script, the game loop is at the end of the script and sorry for how messy it is:
# Pygame skeleton
import pygame
import math
import random
import sys
import os
pygame.init()
pygame.mixer.init()
vec = pygame.math.Vector2
# Constants
WIDTH = 1306
HEIGHT = 526
FPS_INGAME = 60
FPS_HOMESCREEN = 30
FULL_SCREEN = (0,0)
bullet_img = pygame.image.load('Bullet.png')
jump = False
bullet_timer = 0
score = 0
moving_left = False
moving_right = False
shoot = False
acceleration = 0.7
friction = -0.1
gravity = 9.8
platform_color = (150,59,230)
# Classes and Sprites
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.shoot_cooldown = 0
self.anime = []
self.frame_index = 0
self.update_time = pygame.time.get_ticks()
self.action = 0
animation_types = ["Shoot","Go"]
for animation in animation_types:
temp_list = []
num_of_frames = len(os.listdir(f'MySprite/{animation}'))
for i in range(1,num_of_frames):
img = pygame.image.load(f'MySprite/{animation}/{i}.png')
temp_list.append(img)
self.anime.append(temp_list)
self.direction = 1
self.flip = False
self.image = self.anime[self.action][self.frame_index]
self.rect = self.image.get_rect()
# vectors and sprite constants
self.health = 100
self.pos = vec(WIDTH/2, HEIGHT/2)
self.vel_vec = vec(0,0)
self.acc_vec = vec(0,0)
def jump(self):
self.rect.y += 1
hits = pygame.sprite.spritecollide(player_group.sprite, platform_group,False)
self.rect.y -= -1
if hits:
self.vel_vec.y = -15
def screen_edge(self):
if self.pos.x > WIDTH:
self.pos.x = 0
if self.pos.x < 0:
self.pos.x = WIDTH
def get_damage(self,damage_mag):
self.health -= damage_mag
def update(self):
animation_cooldown = 75
self.image = self.anime[self.action][self.frame_index]
if pygame.time.get_ticks() - self.update_time >= animation_cooldown:
self.update_time = pygame.time.get_ticks()
self.frame_index += 1
if self.frame_index >= len(self.anime[self.action]):
self.frame_index = 0
if self.shoot_cooldown > 0:
self.shoot_cooldown -= 1
def update_action(self,new_action):
if new_action != self.action:
self.action = new_action
self.frame_index = 0
self.update_time = pygame.time.get_ticks()
def move(self,moving_left,moving_right):
self.acc_vec = vec(0,acceleration)
if moving_left:
self.acc_vec.x = -(acceleration)
self.direction = 1
self.flip = False
if moving_right:
self.acc_vec.x = acceleration
self.direction = -1
self.flip = True
self.acc_vec.x += self.vel_vec.x * friction
self.vel_vec += self.acc_vec
self.pos += self.vel_vec + 0.5 * self.acc_vec
self.rect.midbottom = self.pos
hits = pygame.sprite.spritecollide(player_group.sprite, platform_group,False)
if hits:
self.pos.y = hits[0].rect.top
self.vel_vec.y = 0
def draw(self):
screen.blit(pygame.transform.flip(self.image,self.flip,False),self.rect)
class Platform(pygame.sprite.Sprite):
def __init__(self,x,y,w,h):
super().__init__()
self.image = pygame.Surface((w,h))
self.image.fill(platform_color)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
class Hostiles(pygame.sprite.Sprite):
def __init__(self,x_pos,y_pos,speed):
super(Hostiles,self).__init__()
self.images = []
self.images.append(pygame.image.load('MySprite/images/go_1.png'))
self.images.append(pygame.image.load('MySprite/images/go_2.png'))
self.images.append(pygame.image.load('MySprite/images/go_3.png'))
self.images.append(pygame.image.load('MySprite/images/go_4.png'))
self.images.append(pygame.image.load('MySprite/images/go_5.png'))
self.images.append(pygame.image.load('MySprite/images/go_6.png'))
self.images.append(pygame.image.load('MySprite/images/go_7.png'))
self.images.append(pygame.image.load('MySprite/images/go_8.png'))
self.images.append(pygame.image.load('MySprite/images/go_9.png'))
self.images.append(pygame.image.load('MySprite/images/go_10.png'))
self.index = 0
self.image = self.images[self.index]
self.rect = self.image.get_rect(center = (x_pos,y_pos))
self.speed = speed
def update(self):
self.index += 1
if self.index >= len(self.images):
self.index = 0
self.image = self.images[self.index]
self.rect.centerx += self.speed
if self.rect.centerx >= 1350 or self.rect.centerx <= -50:
self.kill()
class Hostiles2(pygame.sprite.Sprite):
def __init__(self,x_pos,y_pos,speed):
super(Hostiles2,self).__init__()
self.images2 = []
self.images2.append(pygame.image.load('MySprite/images2/go_1.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_2.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_3.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_4.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_5.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_6.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_7.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_8.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_9.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_10.png'))
self.index = 0
self.image = self.images2[self.index]
self.rect = self.image.get_rect(center = (x_pos,y_pos))
self.speed = speed
def update(self):
self.index += 1
if self.index >= len(self.images2):
self.index = 0
self.image = self.images2[self.index]
self.rect.centerx += self.speed
if self.rect.centerx >= 1350 or self.rect.centerx <= -50:
self.kill()
class Bullets(pygame.sprite.Sprite):
def __init__(self,x,y,direction):
super().__init__()
self.speed = 10
self.image = bullet_img
self.rect = self.image.get_rect(center = (x,y))
self.direction = direction
def update(self):
self.rect.x -= (self.direction * self.speed)
if self.rect.left >= WIDTH or self.rect.right <= 0:
self.kill()
screen.blit(self.image,self.rect)
# Functions
def make_text(font_type,font_size,text,color,position):
font = pygame.font.Font(font_type, font_size)
title = font.render(text,True,(color))
title_rect = title.get_rect(center = (position))
screen.blit(title,title_rect)
def main_game():
pygame.draw.rect(screen,(255,0,0),(22,20,200,10))
pygame.draw.rect(screen,platform_color,(22,20,2 * player_group.sprite.health,10))
screen.blit(heart,(0,2))
bullet_group.draw(screen)
player.draw()
hostiles_group.draw(screen)
platform_group.draw(screen)
bullet_group.update()
player_group.update()
hostiles_group.update()
player_group.update()
player.screen_edge()
if shoot:
if player.shoot_cooldown == 0:
bullet = Bullets(player.rect.centerx - (0.6 * player.direction * player.rect.size[0]),player.rect.centery,player.direction)
bullet_group.add(bullet)
player.shoot_cooldown = 40
if moving_left or moving_right:
player.update_action(1)
else:
player.update_action(0)
player.move(moving_left,moving_right)
if pygame.sprite.spritecollide(player_group.sprite,hostiles_group,True):
player_group.sprite.get_damage(10)
pygame.sprite.groupcollide(hostiles_group, bullet_group,True,True)
return 2
def game_over():
screen.fill((0,0,0))
text = gamefont.render("GAME OVER",True,(255,255,255))
text_rect = text.get_rect(center = (653,243))
screen.blit(text,text_rect)
scoresurface = gamefont.render(f"Score: {score}",True,(255,255,255))
score_rect = scoresurface.get_rect(center = (653,283))
screen.blit(scoresurface,score_rect)
# Creating window
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("game name")
clock = pygame.time.Clock()
# Groups and objects
gamefont = pygame.font.Font('Chernobyl.ttf',40)
player = Player()
platform = Platform(0,HEIGHT-96,WIDTH,100)
platform_group = pygame.sprite.GroupSingle()
platform_group.add(platform)
player_group = pygame.sprite.GroupSingle()
player_group.add(player)
hostiles_group = pygame.sprite.Group()
hostile_event = pygame.USEREVENT
pygame.time.set_timer(hostile_event,300)
bullet_group = pygame.sprite.Group()
pygame.mouse.set_visible(True)
sky = pygame.image.load('SkyNight.png')
wallpaper = pygame.image.load('GamePlatform.png')
heart = pygame.image.load('Heart.png')
# Game loop
running = True
while running:
# Events (Inputs)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == hostile_event:
random_xpos = [-40,-20]
random_xpos2 = [1340,1360]
random_hs = [-2,2]
hostile_left = Hostiles2(random.choice(random_xpos),400,random.choice(random_hs))
hostile_right = Hostiles(random.choice(random_xpos2),400,random.choice(random_hs))
hostiles_group.add(hostile_left,hostile_right)
if event.type == pygame.MOUSEBUTTONDOWN and player_group.sprite.health <= 0:
player_group.sprite.health = 100
hostiles_group.empty()
score = 0
import MainMenu
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
moving_left = True
if event.key == pygame.K_RIGHT:
moving_right = True
if event.key == pygame.K_q:
shoot = True
if event.key == pygame.K_ESCAPE:
running = False
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
moving_left = False
if event.key == pygame.K_RIGHT:
moving_right = False
if event.key == pygame.K_q:
shoot = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player_group.sprite.jump()
if player_group.sprite.health > 0:
score += main_game()
print (score)
else:
game_over()
pygame.display.update()
screen.blit(sky,FULL_SCREEN)
screen.blit(wallpaper,FULL_SCREEN)
programIcon = pygame.image.load('icon.png')
pygame.display.set_icon(programIcon)
clock.tick(FPS_INGAME)
and this is all the main screen / main menu .py file:
import pygame,sys
pygame.init()
screen = pygame.display.set_mode((1306,526))
clock = pygame.time.Clock()
pygame.mouse.set_visible(True)
screen_home = pygame.image.load('HomeScreen.png')
def make_text(font_type,font_size,text,color,position):
font = pygame.font.Font(font_type, font_size)
title = font.render(text,True,(color))
title_rect = title.get_rect(center = (position))
screen.blit(title,title_rect)
while True:
font1 = pygame.font.Font('Starjedi.ttf',60)
game1 = font1.render("Play",True,(255,255,255))
game1_rect = game1.get_rect(center = (640,300))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
if game1_rect.collidepoint(event.pos):
import MainGame.py
screen.blit(screen_home,(0,0))
screen.blit(game1,game1_rect)
make_text('Chernobyl.ttf',70,"Title Here",(255,255,255),(315,80))
pygame.display.update()
clock.tick(45)
when I run the main menu I get the Home Screen I made, then I click on the on my display screen and it imports the game script and the game starts, when my health reaches 0 and I click on the screen to quit the game loop, it takes me back to the main menu which is exactly what I wanted,however, when I press play again to go back to the game it doesn't work it gives me an error:
ModuleNotFoundError: No module named 'MainGame.py'; 'MainGame' is not a package
I know the code is a mess I'm still new at this I'm sorry if my question wasn't clear enough, any help would be appreciated!
Ok, now that I see your code I can see you have a big problem using import:
You use it like this:
import MainGame.py
Assume the file you created is MainGame.py you supposed to import it this way:
import MainGame
Same goes to
import MainMenu.py
And that's might be the problem, though if you still have an issue, so instead of:
in the game, this is part of the main game loop:
Please copy all of the code, in both files, and write the name of each file next to the code.
Im making a platformer in python using pygame, but i am stuck on the collision, jumping and gravity logic, i figured out the collision logic but not the gravity and jumping. So im asking someone to make a example for my code, because im stuck on this for about 3 weeks now.
Project File: https://github.com/1NilusNilus/Pygame-Platformer
Code:
import pygame
import os
import sys
class Level(object):
def __init__(self, path):
self.path = path
def get(self):
with open(self.path, "r") as file:
data = file.read()
data = data.split("\n")
return data
class Tile(object):
def __init__(self, screen, level):
self.screen = screen
self.level = level
self.sprites = {
"dirt": pygame.image.load("C:/Users/entit/Desktop/Python/Platformer/img/dirt.png"),
"grass": pygame.image.load("C:/Users/entit/Desktop/Python/Platformer/img/grass.png"),
"brick": pygame.image.load("C:/Users/entit/Desktop/Python/Platformer/img/brick.png")
}
self.pos = [0,0]
self.size = [30,30]
self.rect = pygame.rect.Rect(self.pos, self.size)
self.tiles = []
def testCollision(self, player_rect):
hitlist = []
for tile in self.tiles:
if player_rect.colliderect(tile):
hitlist.append(tile)
return hitlist
def draw(self):
self.pos[0] = 0
self.pos[1] = 0
for tiles in self.level:
self.pos[0] = 0
for tile in tiles:
if tile == "1":
self.screen.blit(self.sprites["dirt"], self.pos)
self.tiles.append(pygame.Rect(self.pos, self.size))
if tile == "2":
self.screen.blit(self.sprites["grass"], self.pos)
self.tiles.append(pygame.Rect(self.pos, self.size))
if tile == "3":
self.screen.blit(self.sprites["brick"], self.pos)
self.tiles.append(pygame.Rect(self.pos, self.size))
self.pos[0] += self.size[0]
self.pos[1] += self.size[1]
class Player(object):
def __init__(self, screen, tile, sprite):
self.screen = screen
self.sprite = sprite
self.tile = tile
self.vel = [0, 0]
self.acc = [0.1, 0.1]
self.pos = [180, 390]
self.size = self.sprite.get_size()
self.player_rect = pygame.rect.Rect(self.pos, self.size)
self.dir = {"right":False, "left":False}
def draw(self):
self.screen.blit(self.sprite, self.pos)
def move(self):
self.collision_types = {"left":False, "right":False, "top":False, "bottom":False}
self.player_rect.x = self.pos[0]
self.player_rect.y = self.pos[1]
self.pos[0] += self.vel[0]
for tile in self.tile.testCollision(self.player_rect):
if self.vel[0] > 0:
self.vel[0] = 0
self.pos[0] = tile.left - self.size[0]
self.collision_types["right"] = True
if self.vel[0] < 0:
self.vel[0] = 0
self.pos[0] = tile.right
self.collision_types["left"] = True
self.pos[1] += self.vel[1]
for tile in self.tile.testCollision(self.player_rect):
if self.vel[1] > 0:
self.pos[1] = tile.top - self.size[1]
self.collision_types["bottom"] = True
self.vel[1] = 0
if self.vel[1] < 0:
self.pos[1] = tile.bottom
self.collision_types["top"] = True
if self.dir["left"]:
self.vel[0] = -2
elif self.dir["right"]:
self.vel[0] = 2
else:
self.vel[0] = 0
class Game:
def __init__(self, screen):
self.screen = screen
self.clock = pygame.time.Clock()
self.FPS = 60
self.running = True
self.bgcolor = (66,135,245)
self.level = Level("C:/UserS/entit/Desktop/Python/Platformer/level.txt").get()
self.tile = Tile(self.screen, self.level)
self.player = Player(self.screen, self.tile, pygame.image.load("C:/UserS/entit/Desktop/Python/Platformer/img/player.png"))
def events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT:
self.player.dir["left"] = True
if event.type == pygame.KEYUP and event.key == pygame.K_LEFT:
self.player.dir["left"] = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
self.player.dir["right"] = True
if event.type == pygame.KEYUP and event.key == pygame.K_RIGHT:
self.player.dir["right"] = False
def update(self):
self.player.move()
def draw(self):
self.screen.fill(self.bgcolor)
self.tile.draw()
self.player.draw()
pygame.display.update()
def run(self):
while self.running:
self.events()
self.update()
self.draw()
self.clock.tick(self.FPS)
pygame.quit()
sys.exit()
def main():
os.environ["SDL_VIDEO_CENTERED"] = "1"
pygame.init()
screen_size = [720,480]
screen = pygame.display.set_mode(screen_size)
pygame.display.set_caption("platformer")
game = Game(screen)
game.run()
if __name__ == "__main__":
main()
Adding the gravity logic is straight forward. Gravity is acceleration so it increases the vertical velocity toward the ground. In a pygame screen, positive Y is down, so gravity increases the Y velocity. For the jump, you just set the Y velocity to a negative number (up) and let gravity do the rest.
Only a few changes are needed:
In the Player class:
def __init__(self, screen, tile, sprite):
self.gravity = .1 # gravity acceleration # add this line
self.screen = screen
self.sprite = sprite
.........
def move(self):
self.vel[1] += self.gravity # adjust vertical velocity # add this line
self.collision_types = {"left":False, "right":False, "top":False, "bottom":False}
.........
In the Game class:
def events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE: # player jump # add this line
self.player.vel[1] = -5 # add this line
........
Note that with the jump added, the player can collide with a platform from the side or bottom while the player X and Y velocities are both non-zero. You will need to update the collision logic for this.
new to pygame and game programming in general, just wondered how I could get a camera to follow a car (nothing fancy) in a top down car game - think Micro Machines! I'm using Python 3.6, and have got a bike rotating, and moving around. I've kept the code here shorter but I do have a static image for reference if the camera worked!
Here's what I have:
import pygame, math, sys, random
from pygame.locals import *
display_width = 1280
display_height = 800
# Sets size of screen
screen = pygame.display.set_mode((display_width, display_height))
# Initialises clock
clock = pygame.time.Clock()
# Colours
white = (255,255,255)
black = (0,0,0)
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class VehicleSprite(Entity):
# Creates a vehicle class
MAX_FORWARD_SPEED = 10
MAX_REVERSE_SPEED = 2
ACCELERATION = 0.05
TURN_SPEED = 0.000000000001
def __init__(self, image, position):
Entity.__init__(self)
# Creates object instance off
pygame.sprite.Sprite.__init__(self)
self.src_image = pygame.image.load(image)
self.position = position
self.speed = self.direction = 0
self.k_left = self.k_right = self.k_down = self.k_up = 0
def update(self, time):
# SIMULATION
self.speed += (self.k_up +self.k_down)
if self.speed > self.MAX_FORWARD_SPEED:
self.speed = self.MAX_FORWARD_SPEED
if self.speed < -self.MAX_REVERSE_SPEED:
self.speed = -self.MAX_REVERSE_SPEED
# Degrees sprite is facing (direction)
self.direction += (self.k_right + self.k_left)
x, y = self.position
rad = self.direction * math.pi / 180
x += -self.speed*math.sin(rad)
y += -self.speed*math.cos(rad)
self.position = (x, y)
self.image = pygame.transform.rotate(self.src_image, self.direction)
self.rect = self.image.get_rect()
self.rect.center = self.position
class Background(pygame.sprite.Sprite):
def __init__(self, image_file, location):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
rect = screen.get_rect()
# Background
BackGround = Background('/home/pi/gametuts/images/backgrounds/bkg_img.png', [0, 0])
# Bike image load
bike = VehicleSprite('/home/pi/gametuts/images/BikePixelBig.png', rect.center)
bike_group = pygame.sprite.RenderPlain(bike)
# Ball image load
ball = VehicleSprite('/home/pi/gametuts/images/ironball.png', rect.center)
ball_group = pygame.sprite.RenderPlain(ball)
# Main game loop
def game_loop():
while 1:
#USER INPUT
# Sets frame rate
time = clock.tick(60)
for event in pygame.event.get():
if not hasattr(event, 'key'): continue
down = event.type == KEYDOWN
# Bike Input (Player 1)
if event.key == K_d: bike.k_right = down * -5
elif event.key == K_a: bike.k_left = down * 5
elif event.key == K_w: bike.k_up = down * 2
elif event.key == K_s: bike.k_down = down * -2
# Quit
elif event.key == K_ESCAPE: sys.exit(0)
#RENDERING
# Game background
screen.fill(white)
screen.blit(BackGround.image, BackGround.rect)
# Bike render
bike_group.update(time)
bike_group.draw(screen)
ball_group.update(time)
ball_group.draw(screen)
pygame.display.flip()
game_loop()
pygame.quit()
quit()
Thanks in advance!
The simplest way to implement a camera is to use a pygame.math.Vector2 as the camera, subtract the player velocity from it each frame and add it to the position of all game elements during the blitting.
import pygame as pg
from pygame.math import Vector2
class Player(pg.sprite.Sprite):
def __init__(self, pos, walls, *groups):
super().__init__(*groups)
self.image = pg.Surface((30, 50))
self.image.fill(pg.Color('dodgerblue'))
self.rect = self.image.get_rect(center=pos)
self.vel = Vector2(0, 0)
self.pos = Vector2(pos)
self.walls = walls
self.camera = Vector2(0, 0)
def update(self):
self.camera -= self.vel # Change the camera pos if we're moving.
# Horizontal movement.
self.pos.x += self.vel.x
self.rect.centerx = self.pos.x
# Change the rect and self.pos coords if we touched a wall.
for wall in pg.sprite.spritecollide(self, self.walls, False):
if self.vel.x > 0:
self.rect.right = wall.rect.left
elif self.vel.x < 0:
self.rect.left = wall.rect.right
self.pos.x = self.rect.centerx
self.camera.x += self.vel.x # Also move the camera back.
# Vertical movement.
self.pos.y += self.vel.y
self.rect.centery = self.pos.y
for wall in pg.sprite.spritecollide(self, self.walls, False):
if self.vel.y > 0:
self.rect.bottom = wall.rect.top
elif self.vel.y < 0:
self.rect.top = wall.rect.bottom
self.pos.y = self.rect.centery
self.camera.y += self.vel.y
class Wall(pg.sprite.Sprite):
def __init__(self, x, y, w, h, *groups):
super().__init__(*groups)
self.image = pg.Surface((w, h))
self.image.fill(pg.Color('sienna2'))
self.rect = self.image.get_rect(topleft=(x, y))
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
walls = pg.sprite.Group()
for rect in ((100, 170, 90, 20), (200, 100, 20, 140),
(400, 60, 150, 100), (300, 470, 150, 100)):
walls.add(Wall(*rect))
all_sprites.add(walls)
player = Player((320, 240), walls, all_sprites)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_d:
player.vel.x = 5
elif event.key == pg.K_a:
player.vel.x = -5
elif event.key == pg.K_w:
player.vel.y = -5
elif event.key == pg.K_s:
player.vel.y = 5
elif event.type == pg.KEYUP:
if event.key == pg.K_d and player.vel.x > 0:
player.vel.x = 0
elif event.key == pg.K_a and player.vel.x < 0:
player.vel.x = 0
elif event.key == pg.K_w and player.vel.y < 0:
player.vel.y = 0
elif event.key == pg.K_s and player.vel.y > 0:
player.vel.y = 0
all_sprites.update()
screen.fill((30, 30, 30))
for sprite in all_sprites:
# Add the player's camera offset to the coords of all sprites.
screen.blit(sprite.image, sprite.rect.topleft+player.camera)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
Edit: Here's your code example with a camera. I've also tried to improve a few more things, for example the max(min(...)) trick to clamp the speed value. I'm not sure if the movement works as you want, but you can of course adjust it yourself. (I'd probably make even more modifications to the update method.)
import math
import random
import pygame
pygame.init()
screen = pygame.display.set_mode((1280, 800))
rect = screen.get_rect()
clock = pygame.time.Clock()
WHITE = pygame.Color('white')
# Load images globally and reuse them in your program.
# Also use the `.convert()` or `.convert_alpha()` methods after
# loading the images to improve the performance.
VEHICLE1 = pygame.Surface((40, 70), pygame.SRCALPHA)
VEHICLE1.fill((130, 180, 20))
VEHICLE2 = pygame.Surface((40, 70), pygame.SRCALPHA)
VEHICLE2.fill((200, 120, 20))
BACKGROUND = pygame.Surface((1280, 800))
BACKGROUND.fill((30, 30, 30))
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class VehicleSprite(Entity):
MAX_FORWARD_SPEED = 10
MAX_REVERSE_SPEED = 2
ACCELERATION = 0.05
TURN_SPEED = 0.000000000001
def __init__(self, image, position):
Entity.__init__(self)
self.src_image = image
self.image = image
self.rect = self.image.get_rect(center=position)
self.position = pygame.math.Vector2(position)
self.velocity = pygame.math.Vector2(0, 0)
self.speed = self.direction = 0
self.k_left = self.k_right = self.k_down = self.k_up = 0
def update(self, time):
# SIMULATION
self.speed += self.k_up + self.k_down
# To clamp the speed.
self.speed = max(-self.MAX_REVERSE_SPEED,
min(self.speed, self.MAX_FORWARD_SPEED))
# Degrees sprite is facing (direction)
self.direction += (self.k_right + self.k_left)
rad = math.radians(self.direction)
self.velocity.x = -self.speed*math.sin(rad)
self.velocity.y = -self.speed*math.cos(rad)
self.position += self.velocity
self.image = pygame.transform.rotate(self.src_image, self.direction)
self.rect = self.image.get_rect(center=self.position)
class Background(pygame.sprite.Sprite):
def __init__(self, image, location):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect(topleft=location)
def game_loop():
background = Background(BACKGROUND, [0, 0])
bike = VehicleSprite(VEHICLE1, rect.center)
ball = VehicleSprite(VEHICLE2, rect.center)
bike_group = pygame.sprite.Group(bike)
ball_group = pygame.sprite.Group(ball)
all_sprites = pygame.sprite.Group(bike_group, ball_group)
camera = pygame.math.Vector2(0, 0)
done = False
while not done:
time = clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
# Bike Input (Player 1)
if event.key == pygame.K_d:
bike.k_right = -5
elif event.key == pygame.K_a:
bike.k_left = 5
elif event.key == pygame.K_w:
bike.k_up = 2
elif event.key == pygame.K_s:
bike.k_down = -2
elif event.key == pygame.K_ESCAPE:
done = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d:
bike.k_right = 0
elif event.key == pygame.K_a:
bike.k_left = 0
elif event.key == pygame.K_w:
bike.k_up = 0
elif event.key == pygame.K_s:
bike.k_down = 0
camera -= bike.velocity
all_sprites.update(time)
screen.fill(WHITE)
screen.blit(background.image, background.rect)
for sprite in all_sprites:
screen.blit(sprite.image, sprite.rect.topleft+camera)
pygame.display.flip()
game_loop()
pygame.quit()
I have created code to see whether my aliens are dead however it doesn't work, can anyone see the problem.
CODE:
enemies = pygame.sprite.Group(aliens)
if len(enemies) <= 0:
print("game over")
gameover()
Complete code:
#MathsVaders
import pygame, random, time
from pygame.locals import *
import Databaseconnector
import tkMessageBox
pygame.init()
# set up the graphics window
size = [800, 595]
screen = pygame.display.set_mode(size, 0)
screenrect = screen.get_rect()
pygame.display.set_caption("Mathsvaders")
# set some variables
done = False
life = 3
aliens = pygame.sprite.Group()
allsprites = pygame.sprite.Group()
bombs = pygame.sprite.Group()
green = [0, 255, 0]
white = [255, 255, 255]
# create a timer to control how often the screen updates
clock = pygame.time.Clock()
fps = 100
# loads images to use in the game which link in with my classes(further down)
cannon = pygame.image.load("spaceship.png").convert()
cannon.set_colorkey(white)
blast = pygame.image.load("blast.png").convert_alpha()
boom = pygame.image.load("expl.png").convert_alpha()
bomb = pygame.image.load("missile_player.png").convert_alpha()
back = pygame.image.load("rsz_space.png").convert()
enemy = pygame.image.load("sii.png").convert_alpha()
lives2 = pygame.image.load("alien2.png").convert()
lives2.set_colorkey(white)
lives3 = pygame.image.load("alien3.png").convert()
lives3.set_colorkey(white)
lives1 = pygame.image.load("alien1.png").convert()
lives1.set_colorkey(white)
# (Classes)
# the explosion class
class Explosion(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = boom
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.centery = y
self.count = 6
def update(self):
self.count -= 1
if self.count < 1:
self.kill()
class scoreClass:
def __init__(self):
self.value = 0
# set a font, default font size 28
self.font = pygame.font.Font(None, 28)
def update(self):
text = self.font.render("Score: %s" % self.value, True, (green))
textRect = text.get_rect()
textRect.centerx = screenrect.centerx
screen.blit(text, textRect)
class Msg:
def __init__(self, words):
# set a font, default font size 28
self.font = pygame.font.Font(None, 28)
self.text = self.font.render(words, True, (green))
self.textRect = self.text.get_rect()
def update(self):
self.textRect.centerx = screenrect.centerx
self.textRect.centery = screenrect.centery
screen.blit(self.text, self.textRect)
# the invader class
class Pi(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
aliens.add(self)
self.image = enemy
self.rect = self.image.get_rect()
self.rect.left = x
self.rect.top = y
self.speed = 1
def update(self):
self.rect.right += self.speed
if self.rect.right >= (screenrect.right -5):
self.speed = -1
self.rect.top += self.rect.height
if self.rect.left <= (screenrect.left +5):
self.speed = 1
self.rect.top += self.rect.height
if self.rect.top > screenrect.bottom:
self.kill()
i = random.randrange(1000)
j = self.rect.centerx
if i == 1:
laser_bomb = Bomb(j, self.rect.bottom)
allsprites.add(laser_bomb)
aliens.add(laser_bomb)
class Gun(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = cannon
self.rect = self.image.get_rect()
self.rect.bottom = screenrect.bottom
self.rect.centerx = screenrect.centerx
self.speed=0
def update(self):
self.rect.centerx += self.speed
if self.rect.right >= screenrect.right:
self.rect.centerx = 0
if self.rect.right <= 0:
self.rect.right = screenrect.right
# bomb class
class Bomb(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = bomb
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.centery = y
bombs.add(self)
def update(self):
self.rect.centery +=1
# the laser blast class
class Blast(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = blast
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.top = (player.rect.top + 5)
self.rect.centerx = player.rect.centerx
self.speed = 0
def update(self):
if self.speed == 0:
self.rect.centerx = player.rect.centerx
self.rect.top -= self.speed
# function to make a sheet of invaders
def invade():
for j in range(10, 200, 120):
for i in range(10):
aliens.add(Pi((i*70)+10, j))
def gameover():
message = Msg("Game Over")
message.update()
player.kill()
shot.kill()
SQL = 'INSERT INTO TblScore(Score, StudentID) VALUES (' + str(score.value) + ', ' + str(8) + ')'
Databaseconnector.INSERT(SQL)
#pygame.quit()
##def gameover():
## message = Msg("Game Over")
## message.update()
## player.kill()
## shot.kill()
## SQL = 'INSERT INTO TblScore(Score, StudentID) VALUES (' + str(score.value) + ', ' + str(8) + ')'
## Databaseconnector.INSERT(SQL)
##
## #pygame.quit()
def gamewon():
# sprites(aliens) == 0
#sprites.aliens == 0
message = Msg("YOU WON, YOUR SCORE WAS " + score + " WELL DONE")
message.update
aliens.kill()
shot.kill()
pygame.quit()
# pre-game window
invade()
message = Msg("Press a key to play.")
allsprites.add(aliens)
key = True
while key:
screen.blit(back, (0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
for item in (aliens):
item.kill()
key = False
allsprites.update()
allsprites.draw(screen)
message.update()
# set the loop to 40 cycles per second
clock.tick(fps)
# update the display
pygame.display.flip()
# Main Game Starts Here
score = scoreClass()
player = Gun()
shot = Blast()
invade()
allsprites.add(player, aliens, shot)
while done==False:
screen.blit(back, (0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
done=True
if life <= 0:
gamewon()
## elif allsprites == 0:
## gamewon()
else:
# shoots laser missile
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
if shot.speed == 0:
shot.speed = 7
#laser.play()
if event.key == pygame.K_LEFT:
player.speed = -3
if event.key == pygame.K_RIGHT:
player.speed = 3
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.speed = 0
if event.key == pygame.K_RIGHT:
player.speed = 0
hit = pygame.sprite.spritecollide(shot, aliens, 1)
if len(hit) > 0:
explosion1 = Explosion(shot.rect.centerx, shot.rect.top)
score.value += 1500
shot.kill()
#explode.play()
shot = Blast()
allsprites.add(shot, explosion1)
hit2 = pygame.sprite.spritecollide(player, aliens, 1)
if len(hit2) > 0:
life -= 1
#explode.play()
explosion2 = Explosion(player.rect.centerx, player.rect.centery)
allsprites.add(explosion2)
player.kill()
shot.kill()
if life > 0:
ready = Msg("Push Harder !!.")
ready.update()
allsprites.update()
allsprites.draw(screen)
score.update()
pygame.display.flip()
for item in bombs:
item.kill()
while 1:
event = pygame.event.wait()
if event.type == pygame.KEYDOWN:
break
player = Gun()
shot = Blast()
allsprites.add(player, shot)
if shot.rect.top <= screenrect.top:
shot.kill()
shot = Blast()
allsprites.add(shot)
if life == 2:
men = lives2
if life == 1:
men = lives1
if life == 3:
men = lives3
if life > 0:
screen.blit(men, (0,0))
allsprites.update()
allsprites.draw(screen)
score.update()
# set the loop to "fps" cycles per second
clock.tick(fps)
# update the display
pygame.display.flip()
# close pygame
pygame.quit()
This is the "pythonic" way since an empty list is False:
if not enemies:
print("game over")
gameover()
Where is the part of code that kills your aliens?