I'm making a program that clones pong based off a tutorial and I already have the program to where it is multiplayer with two separate people. I want to add an AI in the program instead of a player 2. I've been stuck on this for quite some time and would appreciate any help! Here is the code currently:
import sys, os, math, random, pygame
from pygame.locals import *
class paddle(pygame.sprite.Sprite):
def __init__(self, xy):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('assets', 'pong_paddle.gif'))
self.rect = self.image.get_rect()
self.rect.centerx, self.rect.centery = xy
self.movementspeed = 5
self.velocity = 0
def up(self):
# increases vertical velocity
self.velocity -= self.movementspeed
def down(self):
# decreases vertical velocity
self.velocity += self.movementspeed
def move(self, dy):
# moves the paddle y, doesn't go out of top or bottom
if self.rect.bottom + dy > 400:
self.rect.bottom = 400
elif self.rect.top + dy < 0:
self.rect.top = 0
else:
self.rect.y += dy
def update(self):
# makes the paddle move every frame
self.move(self.velocity)
class aiplayer(object):
def __init__(self):
self.bias = random.random() - 0.5
self.hit_count = 0
def update(self, paddle, game,):
if (paddle.rect.centerx < game.bounds.centerx and game.ball.rect.centerx < game.bounds.centerx) or (paddle.rect.centerx > game.bounds.centerx and game.ball.rect.centerx > game.bounds.centerx):
delta = (paddle.rect.centery + self.bias * paddle.rect.height) - game.ball.rect.centery
if abs(delta) > paddle.velocity:
if delta > 0:
paddle.direction = -1
else:
paddle.direction = 1
else:
paddle.direction = 0
else:
paddle.direction = 0
def hit(self):
self.hit_count += 1
if self.hit_count > 6:
self.bias = random.random() - 0.5
self.hit_count = 0
def lost(self):
self.bias = random.random() - 0.5
def won(self):
pass
def render(self, surface):
x, y = self.location
w, h = self.image.get_size()
surface.blitz(self.image, (x-w/2, y-h/2))
class Ball(pygame.sprite.Sprite):
def __init__(self, xy):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('assets', 'pong_ball.gif'))
self.rect = self.image.get_rect()
self.rect.centerx, self.rect.centery = xy
self.maxspeed = 10
self.servespeed = 5
self.velx = 0
self.vely = 0
def reset(self):
self.rect.centerx, self.rect.centery = 400, 200
self.velx = 0
self.vely = 0
def serve(self):
angle = random.randint(-45, 45)
if abs(angle) < 5 or abs(angle-180) < 5:
angle = random.randint(10, 20)
if random.random() > .5:
angle += 180
# this gets the velocity for the x and y coords
x = math.cos(math.radians(angle))
y = math.sin(math.radians(angle))
self.velx = self.servespeed * x
self.vely = self.servespeed * y
class Game(object):
def __init__(self):
pygame.init()
# creates the window
self.window = pygame.display.set_mode((800, 400))
# makes a clock
self.clock = pygame.time.Clock()
# window title
pygame.display.set_caption("Pong")
# tells pygame to watch for these certain events so we can close window
pygame.event.set_allowed([QUIT, KEYDOWN, KEYUP])
self.background = pygame.Surface((800, 400))
self.background.fill((55, 255, 85))
pygame.draw.line(self.background, (0,0,0), (400, 0), (400, 400), 2)
self.window.blit(self.background, (0,0))
#lets the background show up
pygame.display.flip()
#renders the sprites so that they actually show up
self.sprites = pygame.sprite.RenderUpdates()
# makes the paddles, adds to sprite group
self.leftpaddle = paddle((50, 200))
self.sprites.add(self.leftpaddle)
self.rightpaddle = paddle((750, 200))
self.sprites.add(self.rightpaddle)
# makes the ball
self.ball = Ball((400, 200))
self.sprites.add(self.ball)
def run(self):
# this lets the game run using a loop so its always active and never closes
running = True
while running:
self.clock.tick(60)
# pygame event, if user closes the game, then stop running
running = self.handleEvents()
pygame.display.set_caption("Pong %d fps" % self.clock.get_fps())
self.manageBall()
# updates the sprites(paddles, ball)
for sprite in self.sprites:
sprite.update()
# renders the sprites
self.sprites.clear(self.window, self.background)
dirty = self.sprites.draw(self.window)
pygame.display.update(dirty)
def handleEvents(self):
for event in pygame.event.get():
if event.type == QUIT:
return False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
return False
# controls the right paddle
if event.key == K_w:
self.leftpaddle.up()
if event.key == K_s:
self.leftpaddle.down()
if event.key == K_UP:
self.rightpaddle.up()
if event.key == K_DOWN:
self.rightpaddle.down()
# serves the ball
if event.key == K_SPACE:
if self.ball.velx == 0 and self.ball.vely == 0:
self.ball.serve()
elif event.type == KEYUP:
if event.key == K_w:
self.leftpaddle.down()
if event.key == K_s:
self.leftpaddle.up()
if event.key == K_UP:
self.rightpaddle.down()
if event.key == K_DOWN:
self.rightpaddle.up()
elif event.type ==
return True
def manageBall(self):
# this moves the ball
self.ball.rect.x += self.ball.velx
self.ball.rect.y += self.ball.vely
if self.ball.rect.top < 0:
self.ball.rect.top = 1
# makes the ball bounce
self.ball.vely *= -1
elif self.ball.rect.bottom > 400:
self.ball.rect.bottom = 399
# makes ball bounce off bottom
self.ball.vely *= -1
# resets the ball if it hits the left or right screen
if self.ball.rect.left < 0:
self.ball.reset()
return
elif self.ball.rect.right > 800:
self.ball.reset()
return
collision = pygame.sprite.spritecollide(self.ball, [self.leftpaddle, self.rightpaddle], dokill = False)
if len(collision) > 0:
hitpaddle = collision[0]
# sends the ball back
self.ball.velx *= -1
# makes sure the ball doesn't get stuck in the paddle
self.ball.rect.x += self.ball.velx
# makes the game and runs it
if __name__ == '__main__':
game = Game()
game.run()
Make a function AI in the aiplayer and have it return up or down
int AI(self.position,ball.position):
if self.y>ball.y:
return -1
elif self.y<ball.y:
return 1
then, in the update() code for aiplayer, do something similar to this
self.y += movespeed*AI(self.position,ball.position)
Then, it either moves the paddle up or down depending on where the ball is ( you might need to switch if you add or subtract the movespeed to get the paddle to go the right direction). Also, it might be more effective to use the center of the paddle so that it won't put the top or bottom edge of the paddle at the ball.
Related
This question already has answers here:
How do I detect collision in pygame?
(5 answers)
How to make ball bounce off wall with PyGame?
(1 answer)
Closed 1 year ago.
So, im having this trouble with collisions in my pygame Python Ping-pong game. Exactly in that fragment of code
#computer
if (x_ball > (x*9) and x_ball < (x*9)+15) and (y_ball < y+55 and y_ball > y-55):
print(f"col at x={x_ball} y= {y_ball}")
x_ball = 890
speed_x*=-1
So it is basic computer movement, repeating the y position of ball. But when i implemented AI movement, ball is going through the computer pallete, sometimes bouncing away. How to make it right? I lost my mind tbh.
import pygame
from pygame.constants import DROPTEXT
pygame.init()
#window
w_width = 1000
w_height = 600
screen = pygame.display.set_mode((w_width, w_height))
clock = pygame.time.Clock()
open = True
#player
x,y = 100,250
#define player action variables
speed = 5
speed_x,speed_y = -5,3
moving_down = False
moving_up = False
#define ball action variables
x_ball,y_ball = 500,250
radius = 10
class palette(pygame.sprite.Sprite):
global x,y
def __init__(self, x, y, speed):
self.speed = speed
pygame.sprite.Sprite.__init__(self)
self.player_rect = pygame.Rect(x,y,30,100)
def draw(self):
pygame.draw.rect(screen, 'White', self.player_rect)
def move(self, moving_up, moving_down):
#reset movement variables
global dy
dy = 0
#assing movement variables if moving up or down
if moving_up:
dy = -self.speed
if moving_down:
dy = self.speed
#update pallete possition
self.player_rect.y += dy
class EnemyPalette(pygame.sprite.Sprite):
global x,y
def __init__(self, x, y, speed):
self.speed = speed
pygame.sprite.Sprite.__init__(self)
self.enemy_rect = pygame.Rect(x,y,30,100)
def draw(self):
pygame.draw.rect(screen, 'White', self.enemy_rect)
#ai move
def move(self, speed,x_ball,y_ball):
self.speed = speed
self.x_ball = x_ball
self.y_ball = y_ball
global dy
dy = 0
dy = y_ball-50
#update enemy pallete possition
self.enemy_rect.y = dy
def ball():
global speed_x,speed_y,x_ball,y_ball
#update pos of bal
x_ball += speed_x
y_ball += speed_y
#basic colision with screen
y = player.player_rect.y
x = player.player_rect.x
#turn off left and right collisions
# if x_ball>=w_width-(0.5*radius) or x_ball <=0+(0.5*radius):
# speed_x*=-1
if y_ball>=w_height-(0.5*radius) or y_ball <=0+(0.5*radius):
speed_y*=-1
#set ball on middle when crosses screen
if x_ball>=w_width or x_ball<=0:
x_ball=500
#collision with pallettes
#player
if (x_ball < x+30 and x_ball > x) and (y_ball < y+120 and y_ball > y):
print(f"left paddle col at x={x_ball} y= {y_ball}")
x_ball = x+30
speed_x*=-1
#computer
if (x_ball > (x*9) and x_ball < (x*9)+15) and (y_ball < y+55 and y_ball > y-55):
print(f"right paddle col at x={x_ball} y= {y_ball}")
x_ball = 890
speed_x*=-1
pygame.draw.circle(screen, (255,255,255), (x_ball,y_ball), radius, 5)
return x_ball,y_ball
#ai movement
#build players and enemies
player = palette(x,y, speed)
enemy = EnemyPalette(x*9,y,speed)
#game
while open:
for event in pygame.event.get():
#quit game
if event.type == pygame.QUIT:
open = False
#keyboard presses
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
moving_up = True
if event.key == pygame.K_s:
moving_down = True
if event.key == pygame.K_ESCAPE:
open = False
#keyboard button released
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
moving_up = False
if event.key == pygame.K_s:
moving_down = False
screen.fill((0,0,0))
clock.tick(60)
pygame.display.flip
#init players
player.draw()
enemy.draw()
player.move(moving_up, moving_down)
enemy.move(speed,x_ball,y_ball)
ball()
pygame.display.update()
You have to test against the enemy rectangle. Get the x and y coordinate form the enemy rectangle before the collision test:
y = enemy.enemy_rect.y
x = enemy.enemy_rect.x
if (x_ball > x and x_ball < x+15) and (y_ball < y+100 and y_ball > y):
print(f"right paddle col at x={x_ball} y= {y_ball}")
x_ball = 890
speed_x*=-1
Simplify the code with chained Comparisons:
y = enemy.enemy_rect.y
x = enemy.enemy_rect.x
if x < x_ball < x+15 and y < y_ball < y+100:
# [...]
Or even better pygame.Rect.collidepoint:
if enemy.enemy_rect.collidepoint(x_ball, y_ball):
# [...]
I recommend reading How do I detect collision in pygame? and Sometimes the ball doesn't bounce off the paddle in pong game.
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.
When I run my code the program says to me:
Traceback (most recent call last):
File "C:\Users\User\Documents\projects\two_player_gun_game.py", line 192, in <module>
if player_one_bullet.is_collided_with(player_two):
NameError: name 'player_one_bullet' is not defined
I do not understand why this reason comes up I have created a function in one of the classes which is is_collided_with but. it still seems not to work can. I have put at the bottom an if statement which checks for collisions. colllisions are meant to be happening for player 1 and 2's bullets.
Here is my code to help:
import pygame
import random
import sys
pygame.init()
screen = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock() # A clock to limit the frame rate.
pygame.display.set_caption("this game")
class Background:
picture = pygame.image.load("C:/images/space.jpg").convert()
picture = pygame.transform.scale(picture, (1280, 720))
def __init__(self, x, y):
self.xpos = x
self.ypos = y
def draw(self):
screen.blit(self.picture, (self.xpos, self.ypos))
class player_first:
picture = pygame.image.load("C:/aliens/ezgif.com-crop.gif")
picture = pygame.transform.scale(picture, (200, 200))
def __init__(self, x, y):
self.xpos = x
self.ypos = y
self.speed_x = 0
self.speed_y = 0
self.rect = self.picture.get_rect()
def update(self):
self.xpos += self.speed_x
self.ypos += self.speed_y
def draw(self): #left right
#screen.blit(pygame.transform.flip(self.picture, True, False), self.rect)
screen.blit(self.picture, (self.xpos, self.ypos))
class player_second:
picture = pygame.image.load("C:/aliens/Giantmechanicalcrab2 - Copy.gif")
picture = pygame.transform.scale(picture, (300, 200))
def __init__(self, x, y):
self.xpos = x
self.ypos = y
self.speed_x = 0
self.speed_y = 0
self.rect = self.picture.get_rect()
def update(self):
self.xpos += self.speed_x
self.ypos += self.speed_y
def draw(self): #left right
#screen.blit(pygame.transform.flip(self.picture, True, False), self.rect)
screen.blit(self.picture, (self.xpos, self.ypos))
class player_one_Bullet(pygame.sprite.Sprite):
picture = pygame.image.load("C:/aliens/giphy.gif").convert_alpha()
picture = pygame.transform.scale(picture, (100, 100))
def __init__(self):
self.xpos = 360
self.ypos = 360
self.speed_x = 0
super().__init__()
self.rect = self.picture.get_rect()
def update(self):
self.xpos += self.speed_x
def draw(self):
screen.blit(self.picture, (self.xpos, self.ypos))
#self.screen.blit(pygame.transform.flip(self.picture, False, True), self.rect)
def is_collided_with(self, sprite):
return self.rect.colliderect(sprite.rect)
class player_two_Bullet(pygame.sprite.Sprite):
picture = pygame.image.load("C:/aliens/MajesticLavishBackswimmer-size_restricted.gif").convert_alpha()
picture = pygame.transform.scale(picture, (100, 100))
picture = pygame.transform.rotate(picture, 180)
def __init__(self):
self.xpos = 360
self.ypos = 360
self.speed_x = 0
super().__init__()
self.rect = self.picture.get_rect()
def update(self):
self.xpos -= self.speed_x
def draw(self):
screen.blit(self.picture, (self.xpos, self.ypos))
#self.screen.blit(pygame.transform.flip(self.picture, False, True), self.rect)
def is_collided_with(self, sprite):
return self.rect.colliderect(sprite.rect)
player_one = player_first(0, 0)
player_two = player_second(1000, 0)
cliff = Background(0, 0)
player_one_bullet_list = pygame.sprite.Group()
player_two_bullet_list = pygame.sprite.Group()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
player_one.speed_y = -5
elif event.key == pygame.K_s:
player_one.speed_y = 5
elif event.key == pygame.K_UP:
player_two.speed_y = -5
elif event.key == pygame.K_DOWN:
player_two.speed_y = 5
elif event.key == pygame.K_SPACE:
player_one_bullet = player_one_Bullet()
player_one_bullet.ypos = player_one.ypos
player_one_bullet.xpos = player_one.xpos
player_one_bullet.speed_x = 14
player_one_bullet_list.add(player_one_bullet)
elif event.key == pygame.K_KP0:
player_two_bullet = player_two_Bullet()
player_two_bullet.ypos = player_two.ypos
player_two_bullet.xpos = player_two.xpos
player_two_bullet.speed_x = 14
player_two_bullet_list.add(player_two_bullet)
elif event.type == pygame.KEYUP:
# Stop moving when the keys are released.
if event.key == pygame.K_s and player_one.speed_y > 0:
player_one.speed_y = 0
elif event.key == pygame.K_w and player_one.speed_y < 0:
player_one.speed_y = 0
if event.key == pygame.K_DOWN and player_two.speed_y > 0:
player_two.speed_y = 0
elif event.key == pygame.K_UP and player_two.speed_y < 0:
player_two.speed_y = 0
if player_one_bullet.is_collided_with(player_two):
player_one_bullet.kill()
if player_two_bullet.is_collided_with(player_one):
player_two_bullet.kill()
player_one.update()
player_two.update()
cliff.draw()
player_one.draw()
player_two.draw()
player_one_bullet_list.update()
player_two_bullet_list.update()
for player_one_bullet in player_one_bullet_list:
player_one_bullet.draw()
for player_two_bullet in player_two_bullet_list:
player_two_bullet.draw()
pygame.display.flip()
clock.tick(60)
#IGNORE THIS
#player_one_bullet_list = pygame.sprite.Group()
#elif event.key == pygame.K_SPACE:
# player_one_bullet = player_one_Bullet()
#
# player_one_bullet.ypos = player_one.ypos
# player_one.xpos = player_one.xpos
#
# player_one_bullet.speed_x = 14
#
# player_one_bullet_list.add(player_one_bullet)
#
#
#player_one_bullet_list.update()
#
# for player_one_bullet in player_one_bullet_list:
# player_one_bullet.draw()
#if hammerhood.rect.colliderect(crab): #.rect.top
# hammerhood.speed_y = 0
When python complains about something not being defined, it typically means you are trying to use something which is not there or has not yet been made.
This is the only time you define 'player_one_bullet':
elif event.key == pygame.K_SPACE:
player_one_bullet = player_one_Bullet()`
So long as you do not press space, there are no bullets and 'player_one_bullet' remains undefined.
That is the reason why this piece of code gives an error:
if player_one_bullet.is_collided_with(player_two):
You cannot use something which does not exist!
Additionally only the last bullet fired from each player will check if it is hitting the other player, the other bullets will ignore everything!
Fortunately there is an easy way to fix it; instead of doing this:
if player_one_bullet.is_collided_with(player_two):
player_one_bullet.kill()
if player_two_bullet.is_collided_with(player_one):
player_two_bullet.kill()
You can use player_one_bullet_list and player_two_bullet_list to check if bullets exist and whether they are colliding!
for bullet in player_one_bullet_list.sprites():
if bullet.is_collided_with(player_two):
player_one_bullet.kill()
for bullet in player_two_bullet_list.sprites():
if bullet.is_collided_with(player_one):
player_two_bullet.kill()
Now you have a for loop that iterates through the list of bullets and if any exist only then it checks whether there is a collision.
Hope this helps you out!
I'm new to programming and to Python as well as Pygame. As such, I'm not yet comfortable with sprites in Pygame. I'm trying to make a game where a block jumps whenever the spacebar is pressed - similar to Mario.
My code doesn't work as desired because whenever the spacebar is pressed, the block incrementally moves up (I've added a gravity component), instead of "jumping".
import pygame
pygame.init()
game_display = pygame.display.set_mode((800, 800))
# fixed variables at the start
x_pos = 400
y_pos = 400
current_speed = 15
def jump_coords(y_position, speed):
if speed >= 0:
#to move up, reduce the y-coordinate
y_position -= speed
return y_position
game_exit = False
# main loop
while not game_exit:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
y_pos = jump_coords(y_pos, current_speed)
# 1 represents gravity value
current_speed -= 1
rect_one = pygame.Rect(x_pos, y_pos, 10, 10)
pygame.draw.rect(game_display, (255, 0, 0), rect_one)
pygame.display.update()
I know that I have to somehow make y_pos keep updating in the while loop whilst speed >= 0 but I'm not sure how to implement it.
I made the minimal changes to your code to get the block to bounce:
import pygame
pygame.init()
game_display = pygame.display.set_mode((800, 800))
# fixed variables at the start
x_pos = 400
y_pos = 400
x_old = x_pos
y_old = y_pos
current_speed = 15
def jump_coords(y_position, speed):
# to move up, reduce the y-coordinate
y_position -= speed
if y_position > 400:
y_position = 400
global jump_flag
jump_flag = False
global current_speed
current_speed = 15
return y_position
game_exit = False
jump_flag = False
# main loop
while not game_exit:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
jump_flag = True
elif event.key == pygame.K_ESCAPE:
exit(0)
if jump_flag:
x_old = x_pos
y_old = y_pos
y_pos = jump_coords(y_pos, current_speed)
# 1 represents gravity value
current_speed -= 1
rect_old = pygame.Rect(x_old, y_old, 10, 10)
pygame.draw.rect(game_display, (0, 0, 0), rect_old)
rect_one = pygame.Rect(x_pos, y_pos, 10, 10)
pygame.draw.rect(game_display, (255, 0, 0), rect_one)
pygame.display.update()
The most important changes was the removal of the check for speed greater than zero. The speed has to go negative if the block is going to come back down. The next change was to save the old x and y coordinates so that we can draw a black square over the old position. I also made it possible to exit the program by pressing the Escape key.
I made this from scratch, I hope it's not too daunting!
import pygame,sys
pygame.init()
screen = pygame.display.set_mode((800, 800))
tm = 20 # Terminal Velocity
gravity = 1
class Player:
def __init__(self,speed,x,y):
self.speed = speed
self.x = x; self.y = y
self.yVelocity = 0
self.xVelocity = 0
def getKeys(self):
key = pygame.key.get_pressed()
if key[pygame.K_a]: self.xVelocity -= self.speed
if key[pygame.K_d]: self.xVelocity += self.speed
if key[pygame.K_SPACE]:
if isGround(self.x,self.y):
self.yVelocity -= 20
def move(self,dt):
if self.x < 0:
self.x = 0
if self.x > 800-15:
self.x = 800-15
if self.y < 0:
self.y = 0
if self.y > 800-10:
self.y = 800-10
self.x += self.xVelocity
self.y += self.yVelocity
if self.xVelocity != 0:
self.xVelocity /= 70*dt
if self.yVelocity < tm and not isBlocking(self.x,self.y+self.yVelocity):
self.yVelocity += gravity
if isBlocking(self.x,self.y):
self.yVelocity = 0
def draw(self):
screen.fill((255,0,0),(self.x,self.y,10,10))
def isBlocking(x,y):
if x < 0 or x > 800 or y < 0 or y > 800:
return True
elif y >= 400:
return True
else:
return False
def isGround(x,y):
if y >= 400:
return True
else:
return False
player = Player(1,400,400)
clock = pygame.time.Clock()
while True:
dt = clock.tick(60)/1000 # limit to 60 FPS.
screen.fill((0,0,0))
if pygame.event.poll().type == pygame.QUIT: pygame.quit(); sys.exit()
player.getKeys()
player.move(dt)
player.draw()
pygame.display.flip()
Hope it helps!
I'm fairly new to programming, game programming especially. I'm trying to make pong using pygame, but have run into a slight issue. Essentially, the ball hits a paddle, stops, and then keeps going once the paddle is out of the way. Obviously I want the ball to bounce back, but I can't figure out why it won't, when I've coded (what I thought was) the appropriate logic for ball-paddle collisions. Here's my code:
# importing stuff
import sys, pygame
from pygame.locals import *
# starting pygame
pygame.init()
# defining basic colours
white = (255, 255, 255)
black = (0, 0, 0)
# set up the clock
clock = pygame.time.Clock()
# text and such
tFont = pygame.font.SysFont("monospace", 15)
# setting window res and setting display
winX, winY = 600, 300
window = pygame.display.set_mode((winX, winY))
# setting the speed for on screen stuff
playSpeed = 5 # player speed (p1 and p2)
# counts points for each player
# 1 2
points = [0, 0]
# tallies number of times FPS is counted and added to toal amount
fpsCount = 0
fpsTotal = 0
class Ball(object):
def __init__(self, speed):
# set default ball position in screen centre
self.ballX = winX / 2
self.ballY = winY / 2
self.ballSpeed = speed
def move(self):
if points[0] > points[1]: # if p1 has more points than p2
self.ballX -= self.ballSpeed # ball goes to p1's side
elif points[0] < points[1]: # only other condition could be p2 having more points
self.ballX += self.ballSpeed # ball goes to p2's side
elif points[0] == points[1]: # if points are equal
self.ballX -= self.ballSpeed # favour player 1 (change later)
pygame.draw.circle(window, black, (self.ballX, self.ballY), 3)
def collide(self, paddle): # unsure if 'paddle' necessary
# if ball hits top of paddle, bounce to top
# if hits bottom, bounce to bottom
# if ball hits midsection, bounce straight (middle could be about 10px?)
if paddle == playerOne:
self.ballX
self.ballX += self.ballSpeed
class Paddle(object):
# set the player number (1/2) and if it's an AI or real player
def __init__(self, player, aiornot):
if player == 1 and aiornot == False:
self.coords = [[40, 130], [40, 160]]
elif player == 2 and aiornot == False:
self.coords = [[560, 130], [560, 160]]
self.movement = 'stop' # sets default movement
def move(self):
if self.movement == 'down' and self.coords[1][1] < 300:
self.moveDown()
elif self.movement == 'up' and self.coords[0][1] > 0:
self.moveUp()
elif self.movement == 'stop':
self.stop()
# draw the paddle in new position
pygame.draw.line(window, black, self.coords[0], self.coords[1], 10)
# movement functions, for direction and such
def moveDown(self):
self.coords[0][1] += playSpeed
self.coords[1][1] += playSpeed
def moveUp(self):
self.coords[0][1] -= playSpeed
self.coords[1][1] -= playSpeed
def stop(self):
self.coords[0][1] = self.coords[0][1]
self.coords[1][1] = self.coords[1][1]
ball = Ball(playSpeed)
playerOne = Paddle(1, False)
playerTwo = Paddle(2, False)
# main loop
while True:
# event handling for exit
for event in pygame.event.get():
if event.type == QUIT:
# print the average FPS
print round(fpsTotal / fpsCount, 2), "fps (avg)"
pygame.quit()
sys.exit()
# setting direction upon arrow key press
elif event.type == KEYDOWN:
if event.key == K_DOWN:
playerOne.movement = 'down'
elif event.key == K_UP:
playerOne.movement = 'up'
elif event.key == K_s:
playerTwo.movement = 'down'
elif event.key == K_w:
playerTwo.movement = 'up'
# when the key is released, stop moving
elif event.type == KEYUP:
if event.key == K_DOWN or event.key == K_UP:
playerOne.movement = 'stop'
elif event.key == K_s or event.key == K_w:
playerTwo.movement = 'stop'
print "player1:", playerOne.coords
print "player2:", playerTwo.coords
# this is a mess... if the balls x coords = the paddles x coords, and the balls y
# coord is somewhere between the start and end point of the paddle, then do the balls
# collision function on the paddle
if ball.ballX >= playerOne.coords[0][0] and ball.ballX <= playerOne.coords[1][0]: # or ball.ballX == 40
if ball.ballY >= playerOne.coords[0][1] and ball.ballY <= playerOne.coords[1][1]:
ball.collide(playerOne)
print ball.ballX, ball.ballY
# fill the window
window.fill(white)
# redraw the bat with new position
playerOne.move()
playerTwo.move()
# redraw the ball with new position
ball.move()
# set FPS to 60
clock.tick(60)
# for working out average FPS
fpsCount += 1
fpsTotal += clock.get_fps()
# set window title
pygame.display.set_caption("Long Pong")
# render FPS to text, display text
text = tFont.render(str(round(clock.get_fps(), 2)), 8, black)
window.blit(text, (545, 5))
# update display
pygame.display.update()
And also a pastebin here if it's easier to look at/copy.
I appreciate any help with this, I've been able to work out any other problem on my own, but I can't tell what I'm missing here.
I hope the below code helps. Although my program was a bit different because every time the ball hit the paddle we had to generate a new ball.
import random
from livewires import games, color
games.init(screen_width = 640, screen_height = 480, fps = 50)
class Ball(games.Sprite):
quit_label = games.Text(value = "Press Q to Quit", size = 25, color = color.white, top = 5, right = 130,
is_collideable = False)
games.screen.add(quit_label)
def update(self):
if self.right > games.screen.width:
self.dx = -self.dx
if self.left < 0:
self.game_over()
if self.bottom > games.screen.height or self.top < 0:
self.dy = -self.dy
#pressing 'q' quits the game
if games.keyboard.is_pressed(games.K_q):
self.game_over()
def bounce(self):
self.dx = -self.dx
def game_over(self):
""" End the game. """
end_message = games.Message(value = "Game Over",
size = 90,
color = color.red,
x = games.screen.width/2,
y = games.screen.height/2,
lifetime = 3 * games.screen.fps,
after_death = games.screen.quit,
is_collideable = False)
games.screen.add(end_message)
self.destroy()
class Paddle(games.Sprite):
image = games.load_image("paddle.bmp")
score = games.Text(value = 0, size = 25, color = color.white, top = 15,
right = games.screen.width - 10, is_collideable = False)
games.screen.add(score)
def __init__(self):
super(Paddle, self).__init__(image = Paddle.image, x = games.mouse.x, bottom = games.screen.height)
def update(self):
""" Move to mouse y position. """
self.y = games.mouse.y
if self.left > 0:
self.left = 10
if self.right > games.screen.height:
self.right = games.screen.height
self.check_catch()
def check_catch(self):
for ball in self.overlapping_sprites:
Paddle.score.value += 1
ball_image2 = games.load_image("ball.bmp")
ball2 = Ball(image = ball_image2,
x = games.screen.width/2,
y = games.screen.height/2,
dx = 1,
dy = 1)
games.screen.add(ball2)
ball.bounce()
def main():
wall_image = games.load_image("background.bmp", transparent = False)
games.screen.background = wall_image
ball_image = games.load_image("ball.bmp")
the_ball = Ball(image = ball_image,
x = games.screen.width/2,
y = games.screen.height/2,
dx = 1,
dy = 1)
games.screen.add(the_ball)
the_paddle = Paddle()
games.screen.add(the_paddle)
games.mouse.is_visible = False
games.screen.mainloop()
# kick it off!
main()