import pygame
width = 500
height = 500
win = pygame.display.set_mode((width, height))
pygame.display.set_caption("Client")
running = False
clientNumber = 0
class Player():
def __init__(self, x, y, width, height, color):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = color
self.rect = (x, y, width, height)
self.vel = 3
def draw(self, win):
pygame.draw.rect(win, self.color, self.rect)
def move(self):
keys = pygame.key.get_pressed()
running = bool
if keys[pygame.K_LEFT]:
self.x -= self.vel
if keys[pygame.K_RIGHT]:
self.x += self.vel
if keys[pygame.K_UP]:
self.y -= self.vel
if keys[pygame.K_DOWN]:
self.y += self.vel
if keys[pygame.K_a] and not running:
self.vel += 3
running = True
if not keys[pygame.K_a]:
running = False
self.rect = (self.x, self.y, self.width, self.height)
def redrawWindow(win, player):
win.fill((255, 255, 255))
player.draw(win)
pygame.display.update()
def main():
run = True
p = Player(50, 50, 100, 100, (0, 0, 255))
clock = pygame.time.Clock()
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
p.move()
redrawWindow(win, p)
main()
I succeed in making a rectangle thing that can be moved by keyboard input.
and now I want to change the velocity of the rectangle like, while, pressing 'a', The velocity change to 6 from 3.
but I have no idea how to do that.
I tried to make a "running" bool variable to speed it up only when you pressed it not while pressing it.
But all of my efforts gone wrong.
Compute the current velocity (current_vel) dependent on the key state of a. Use current_vel to move the player instead of self.vel:
class Player():
# [...]
def move(self):
keys = pygame.key.get_pressed()
current_vel = self.vel
if keys[pygame.K_a]:
current_vel += 3
if keys[pygame.K_LEFT]:
self.x -= current_vel
if keys[pygame.K_RIGHT]:
self.x += current_vel
if keys[pygame.K_UP]:
self.y -= current_vel
if keys[pygame.K_DOWN]:
self.y += current_vel
self.rect = (self.x, self.y, self.width, self.height)
Related
I wrote this code below and just get a black screen on my pygame window everytime I run my project on pycharm
I copied this code through a tutorial step by step and checked it but the teacher didn’t seem to have this problem when running the code
import pygame
width = 500
height = 500
win = pygame.display.set_mode((width, height))
pygame.display.set_caption("Client")
clientNumber = 0
class Player():
def __init__(self, x, y, width, height, color):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = color
self.rect = (x, y, width, height)
self.vel = 3
def draw(self, win):
pygame.draw.rect(win, self.color, self.rect)
def move(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.x -= self.vel
if keys[pygame.K_RIGHT]:
self.x += self.vel
if keys[pygame.K_UP]:
self.y -= self.vel
if keys[pygame.K_DOWN]:
self.y += self.vel
self.rect = (self.x, self.y, self.width, self.height)
def redrawWindow(win, player):
win.fill((255, 255, 255))
player.draw(win)
pygame.display.update()
def main():
run = True
p = Player(50, 50, 100, 100, (0, 255, 0))
clock = pygame.time.Clock()
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
p.move()
redrawWindow(win, p)
main()
Press tab before p.move() and redrawWindow(win, p) so they look like this
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
p.move()
redrawWindow(win, p)
They should be indented under while loop.
I get the error message 'Enemy' object has no attribute '_Sprite__g' and I have no idea how to use the sprite groups. I'm trying to get them to spawn randomly across the x-axis only.
import pygame, os, random
pygame.init()
FPS=60
SCREEN = pygame.display.set_mode((400,500))
pygame.display.set_caption('caption')
x=50
y=450
vel = 3
width = 20
height = 20
class Player(object):
def __init__(self,x,y,width,height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 3
self.image = pygame.Surface((width, height))
self.image.fill((0,0,0))
def draw(self,SCREEN):
SCREEN.blit(self.image, (self.x,self.y))
class B():
def __init__(self,x,y,radius, color):
self.x = x
self.y = y
self.color = color
self.radius = radius
self.vel = vel
def draw(self,SCREEN):
pygame.draw.circle(SCREEN, self.color, (self.x,self.y),self.radius)
class Enemy(pygame.sprite.Sprite):
def __init__(self):
self.image = pygame.Surface((20,20))
self.x = random.randrange (0,400)
self.y = 500
self.speed = random.randrange(1,3)
def draw (self,SCREEN):
SCREEN.blit(self.image,(self.x,self.y))
player = Player(x, y, width, height)
bullets = []
enemies = pygame.sprite.Group()
# Main loop
running = True
clock = pygame.time.Clock()
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
for bullet in bullets:
if bullet.x < 450 and bullet.x >0:
bullet.x += bullet.vel
else:
bullets.pop(bullets.index(bullet))
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
if len(bullets)< 5:
bullets.append(B(round(player.x + player.width //2), round(player.y + player.height//2),3, (0,0,0)))
if keys[pygame.K_w] and player.y > 30 - player.width - player.vel:
player.y -= player.vel
if keys[pygame.K_s] and player.y < 500 - player.width - player.vel:
player.y += player.vel
SCREEN.fill((190, 232, 220))
player.draw(SCREEN)
for bullet in bullets:
bullet.draw(SCREEN)
for i in range (8):
e = Enemy()
enemies.add(e)
pygame.display.update()
pygame.quit()
the obects need to be derives from pygame.sprite.Sprite. The base class needs to be initialized as well. Use super() to delegate to the base class constructor. e.g.:
class Player(object):
def __init__(self,x,y,width,height):
super().__init__()
# [...]
pygame.sprite.Group.draw() and pygame.sprite.Group.update() are methods which are provided by pygame.sprite.Group.
The former delegates the to the update method of the contained pygame.sprite.Sprites - you have to implement the method. See pygame.sprite.Group.update():
Calls the update() method on all Sprites in the Group [...]
The later uses the image and rect attributes of the contained pygame.sprite.Sprites to draw the objects - you have to ensure that the pygame.sprite.Sprites have the required attributes. See pygame.sprite.Group.draw():
Draws the contained Sprites to the Surface argument. This uses the Sprite.image attribute for the source surface, and Sprite.rect. [...]
Therefore the Sprite class must have the attributes .rect and .image. However you don't need the draw method:
class Player(pygame.sprite.Sprite):
def __init__(self,x,y,width,height):
super().__init__()
self.vel = 3
self.image = pygame.Surface((width, height))
self.image.fill((0,0,0))
self.rect = self.image.get_rect(topleft = (x, y))
Create a transparent pygame.Surface with the SRCALPHA flag and draw a circle on it:
class B(pygame.sprite.Sprite):
def __init__(self,x,y,radius, color):
super().__init__()
self.x = x
self.y = y
self.color = color
self.radius = radius
self.vel = vel
self.image = pygame.Surface((self.radius * 2, self.radius * 2), pygame.SRCALPHA)
pygame.draw.circle(self.image, self.color, (self.radius, self.radius), self.radius)
self.rect = self.image.get_rect(center = (self.x, self.y))
Add pygame.sprite.Groups for all sprites. add() the player, the enemies and bullets to the Groups:
enemies = pygame.sprite.Group()
bullets = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
all_sprites.add(player)
for i in range (8):
e = Enemy()
enemies.add(e)
all_sprites.add(e)
Draw the Sprites in the all_sprites Group with pygame.sprite.Group.draw. Remove a Sprite (form all Groups) with kill:
while running:
# [...]
for bullet in bullets:
if 0 < bullet.rect.y < 500:
bullet.rect.y -= bullet.vel
else:
bullet.kill()
# [...]
all_sprites.draw(SCREEN)
Use the keyboard event instead of pygame.key.get_pressed() to fire a bullet. See How do I stop more than 1 bullet firing at once?:
The collision of the enemies and bullets can be detected with pygame.sprite.groupcollide(). When the doKill arguments are set True, the sprites will be automatically removed:
pygame.sprite.groupcollide(bullets, enemies, True, True)
Complete example:
import pygame, os, random
pygame.init()
FPS=60
SCREEN = pygame.display.set_mode((400,500))
pygame.display.set_caption('caption')
x=50
y=450
vel = 3
width = 20
height = 20
class Player(pygame.sprite.Sprite):
def __init__(self,x,y,width,height):
super().__init__()
self.vel = 3
self.image = pygame.Surface((width, height))
self.image.fill((0,0,0))
self.rect = self.image.get_rect(topleft = (x, y))
class B(pygame.sprite.Sprite):
def __init__(self,x,y,radius, color):
super().__init__()
self.x = x
self.y = y
self.color = color
self.radius = radius
self.vel = vel
self.image = pygame.Surface((self.radius * 2, self.radius * 2), pygame.SRCALPHA)
pygame.draw.circle(self.image, self.color, (self.radius, self.radius), self.radius)
self.rect = self.image.get_rect(center = (self.x, self.y))
class Enemy(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((20,20))
self.image.fill((255, 0, 0))
y = random.randrange (0, 480)
x = 400
self.rect = self.image.get_rect(topleft = (x, y))
self.speed = random.randrange(1,3)
player = Player(x, y, width, height)
enemies = pygame.sprite.Group()
bullets = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
all_sprites.add(player)
# Main loop
running = True
clock = pygame.time.Clock()
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and len(bullets) < 5:
bullet = B(player.rect.centerx, player.rect.centery, 3, (0,0,0))
bullets.add(bullet)
all_sprites.add(bullet)
if len(enemies) < 8:
e = Enemy()
enemies.add(e)
all_sprites.add(e)
for bullet in bullets:
if bullet.rect.right < 500:
bullet.rect.x += bullet.vel
else:
bullet.kill()
for enemy in enemies:
if enemy.rect.right > 0:
enemy.rect.x -= enemy.speed
else:
enemy.kill()
pygame.sprite.groupcollide(bullets, enemies, True, True)
keys = pygame.key.get_pressed()
if keys[pygame.K_w] and player.rect.top > player.vel:
player.rect.y -= player.vel
if keys[pygame.K_s] and player.rect.bottom < 500 - player.vel:
player.rect.y += player.vel
SCREEN.fill((190, 232, 220))
all_sprites.draw(SCREEN)
pygame.display.update()
pygame.quit()
Per the documentation:
"When subclassing the Sprite, be sure to call the base initializer before adding the Sprite to Groups."
So the first two lines of Enemy __init__() should be:
def __init__(self):
pygame.sprite.Sprite.__init__(self)
You also need to set a rect for the enemy:
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
I am making a pygame game where you control a spaceship and fire bullets to hit the enemies. As of right now, I am trying to make an enemy appear on the screen. Not making it move yet. However, when I ran my following code, Nothing but the spaceship appeared. The spaceship also was able to move and fire bullets.
This is my current code:
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((800, 500))
screen.fill((255, 255, 255))
class Spaceship(pygame.sprite.Sprite):
def __init__(self, s, x, y):
pygame.sprite.Sprite.__init__(self)
self.screen = s
self.x, self.y = x, y
self.image = pygame.image.load("C:/eqodqfe/spaceship.png")
self.image = pygame.transform.scale(self.image, (175, 175))
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def update(self):
self.rect.center = (self.x, self.y)
class Bullet(pygame.sprite.Sprite):
def __init__(self, s, x, y):
pygame.sprite.Sprite.__init__(self)
self.screen = s
self.x, self.y = x, y
self.image = pygame.image.load("C:/eqodqfe/bullet.png")
self.image = pygame.transform.scale(self.image, (100, 100))
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def update(self):
self.y -= 1
self.rect.center = (self.x, self.y)
if self.y < 0:
self.kill()
class Enemy(Spaceship):
def __init__(self, s, x, y):
Spaceship.__init__(self, s, x, y)
self.image = pygame.image.load("C:/eqodqfe/enemy.png")
self.image = pygame.transform.scale(self.image, (175, 175))
self.rect = self.image.get_rect()
spaceship = Spaceship(screen, 400, 400)
enemy = Enemy(screen, 100, 100)
bullets = pygame.sprite.Group()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == MOUSEBUTTONDOWN:
bullet = Bullet(screen, spaceship.x, spaceship.y - 20)
bullets.add(bullet)
bullets.update()
key = pygame.key.get_pressed()
if key[pygame.K_a]:
spaceship.x -= 0.5
elif key[pygame.K_d]:
spaceship.x += 0.5
elif key[pygame.K_w]:
spaceship.y -= 0.5
elif key[pygame.K_s]:
spaceship.y += 0.5
spaceship.update()
screen.blit(enemy.image, enemy.rect)
enemy.update()
screen.fill((255, 255, 255))
screen.blit(spaceship.image, spaceship.rect)
bullets.draw(screen)
pygame.display.update()
What is wrong?
You have to draw the enemy after drawing the background. If you draw the enemy before the background, the background will hide the enemy:
running = True
while running:
# [...]
# screen.blit(enemy.image, enemy.rect) <-- DELETE
enemy.update()
screen.fill((255, 255, 255))
screen.blit(enemy.image, enemy.rect) # <-- INSERT
screen.blit(spaceship.image, spaceship.rect)
bullets.draw(screen)
pygame.display.update()
I have a simple shooter game using pygame. I'm having some problems making the bullet's y coordinate slowly increasing up. I know this is something to do with the way I've programmed the Player class even though a bullet Rect is in it. I think I have to change the update function inside it. This is my code:
import pygame, random, sys, time
pygame.init()
#Constants
WIDTH = 800
HEIGHT = 500
BLACK = (0, 0, 0)
WHITE = (255, 255, 255) # Background Colour
RED = (255, 0, 0)
GREEN = (0, 255, 0)
window = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Pygame Shooter Game")
clock = pygame.time.Clock()
fps = 60
run = True
class Player():
def __init__(self, width, colour, x, y):
self.width = width
self.colour = colour
self.x = x
self.y = y
self.vel = 5
self.shoot = False
self.player = pygame.Rect(self.x, self.y, self.width, self.width)
self.cartridge = pygame.Rect(0, 0, self.width/2, self.width/2)
self.bullet = pygame.Rect(0, 0, 10, 20)
self.shoot = False
def draw(self, win):
self.win = win
pygame.draw.rect(self.win, self.colour, self.player) # Draw player(rect)
pygame.draw.rect(self.win, GREEN, self.cartridge) #Draw cartridge
if self.shoot:
pygame.draw.rect(self.win, BLACK, self.bullet)
def move(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and self.x > 0: self.x -= self.vel # We don't do elif cuz we want them to be able to move diagonally
if keys[pygame.K_RIGHT] and self.x < WIDTH-self.width: self.x += self.vel
if keys[pygame.K_UP] and self.y > 0: self.y -= self.vel
if keys[pygame.K_DOWN] and self.y < HEIGHT-self.width: self.y += self.vel
if keys[pygame.K_SPACE]:
self.shoot = True
def update(self):
self.player = pygame.Rect(self.x, self.y, self.width, self.width)
self.cartridge.midbottom = self.player.midtop
self.bullet.midbottom = self.cartridge.midtop
if self.shoot:
while self.bullet.y > 0:
self.bullet.y -= 1
def main(win):
run = True
player = Player(50, RED, WIDTH/2, HEIGHT/2)
while run:
win.fill(WHITE)
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
player.move()
player.update()
player.draw(win)
pygame.display.update()
pygame.quit()
sys.exit()
main(window)
Also, how can I make the create classes for each individual Cartridge and Bullet, to make the whole code more efficient?
update is invoked continuously in the main application loop. Therefore, no additional animation loops are required for the update. Change the loop to a selection (change while to if):
while self.bullet.y > 0:
if self.bullet.y > 0:
self.bullet.y -= 1
The starting position of the bullet must be set when the bullet is shot, rather than continuously when the bullet is updated:
class Player():
# [...]
def move(self):
# [...]
if keys[pygame.K_SPACE]:
self.shoot = True
self.bullet.midbottom = self.cartridge.midtop # <--- INSERT
def update(self):
self.player = pygame.Rect(self.x, self.y, self.width, self.width)
self.cartridge.midbottom = self.player.midtop
# self.bullet.midbottom = self.cartridge.midtop <--- DELETE
if self.shoot:
if self.bullet.y > 0: # <--- if (not while)
self.bullet.y -= 1
See also:
How can i shoot a bullet with space bar?
How do I stop more than 1 bullet firing at once?
I am just getting started with pygame. My Player instances position does not update on the surface even though it's x value is changed accordingly.
'''__main__.py'''
import script
if __name__ == '__main__':
script.setup()
script.update()
-
'''script.py'''
import pygame
from player import Player
from enemy import Enemy
from ball import Ball
def setup():
global window, player, enemy, ball
pygame.init()
pygame.display.set_caption('Pong')
window = pygame.display.set_mode((800, 600))
player = Player(40, window.get_height() / 2 - 100 / 2, 20, 100)
enemy = Enemy(window.get_width() - 40 - 20, window.get_height() / 2 - 100 / 2, 20, 100)
def draw():
player.update()
enemy.update()
pygame.display.update()
player.draw(window)
enemy.draw(window)
def update():
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
player.up = True
if keys[pygame.K_DOWN]:
player.down = True
if not keys[pygame.K_UP]:
player.up = False
if not keys[pygame.K_DOWN]:
player.down = False
draw()
pygame.quit()
-
'''player.py'''
import pygame
class Player:
'''Player'''
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = (255, 255, 255)
self.rect = (self.x, self.y, self.width, self.height)
self.vel = 10
self.up = False
self.down = False
def draw(self, surface):
pygame.draw.rect(surface, self.color, self.rect)
def update(self):
if self.up:
self.x -= self.vel
if self.down:
self.x += self.vel
The instance's x value changes when I press up or down, but for some reason it does not get drawn on screen. I have tried moving the draw method and the player.update method but can't seem to get it to work properly.
Look at the Player.draw method. It draws using self.rect.
The problem with your update method is that it never updates self.rect. So self.rect stays the same as after constructor.
Remove self.rect as attribute and replace it with either simple method (Option A) or property (Option B):
class Player:
# Options A:
def get_rect(self):
return (self.x, self.y, self.width, self.height)
# Option B:
#property
def rect(self):
return (self.x, self.y, self.width, self.height)
Or update self.rect inside update method. But I do not recommend that. Having it separately was a reason why you got your no-changing-position-bug in the first place.