Why does my pygame program slowdown, when I move my mouse? - python

So I am trying to program a pong game in pygame, python. Whenever I move my mouse fastly, the ball is slowing down. With my mouseposition, I move my paddle, so I need mouse motion. How can I fix this issue or what might be the problem? Am I doing something wrong? Appreciate any help, or feedback (I am beginner)
import pygame, random
WHITE = (255, 255, 255)
width = 1000
height = 600
window = pygame.display.set_mode((width, height))
pygame.display.set_caption("Pong Game")
Directions = ["negative", "positive"]
DirectionX = random.choice(Directions)
DirectionY = random.choice(Directions)
class classBall():
def __init__(self):
self.BallIMG = pygame.image.load("Ball.png")
self.X = width/2
self.Y = height/2
BallDisplay = window.blit(self.BallIMG, (self.X, self.Y))
self.Vel = 0.25
pass
def display(self):
global DirectionX, DirectionY
if 25 < self.X < 35 and PaddlePlayer.PosY-15 < self.Y < PaddlePlayer.PosY+115:
DirectionX = "positive"
if width-65 < self.X < width-55 and PaddleComp.PosY-15 < self.Y < PaddleComp.PosY+115:
DirectionX = "negative"
if 10 > self.Y:
DirectionY = "positive"
if height-10 < self.Y:
DirectionY = "negative"
if DirectionY == "positive":
self.Y += self.Vel
else:
self.Y -= self.Vel
if DirectionX == "positive":
self.X += self.Vel
else:
self.X -= self.Vel
BallDisplay = window.blit(self.BallIMG, (self.X, self.Y))
Ball = classBall()
class Paddle1Player():
def __init__(self):
self.PosY = height/2
self.PosX = 30
pygame.draw.rect(window, WHITE, [self.PosX, self.PosY, 5, 100])
def display(self):
x, MausPositionY = pygame.mouse.get_pos()
if not MausPositionY > height-100:
self.PosY = MausPositionY
pygame.draw.rect(window, WHITE, [30, self.PosY, 5, 100])
class Paddle2Computer():
def __init__(self):
self.PosY = height/2
self.PosX = width-35
pygame.draw.rect(window, WHITE, [self.PosX, self.PosY, 5, 100])
def display(self):
if Ball.X > width/2 and DirectionX == "positive":
if self.PosY < Ball.Y and DirectionY == "positive":
self.PosY+= Ball.Vel
elif self.PosY > Ball.Y and DirectionY == "negative":
self.PosY-= Ball.Vel
else:
if not height/2 -1 < self.PosY+25 < height/2:
if self.PosY+25 < height/2:
self.PosY+= Ball.Vel-Ball.Vel*3/10
else:
self.PosY-= Ball.Vel-Ball.Vel*3/10
pygame.draw.rect(window, WHITE, [width-35, self.PosY, 5, 100])
PaddlePlayer = Paddle1Player()
PaddleComp = Paddle2Computer()
running = True
pygame.display.flip()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
window.fill((0,0,0))
Ball.display()
PaddlePlayer.display()
PaddleComp.display()
pygame.display.flip()

You want to be setting up a pygame.time.Clock() and in your event loop be calling clock.tick(60) (for 60fps).
Right now your loop is input-bound and not FPS-bound.
In Pygame, normalizing game-speed across different fps values
pygame clock.tick() vs framerate in game main loop

Related

Increase the ball speed as Pong game progress

I am writing a Pong clone and I want to make the game get harder as the game progress. For every point (or few points), increase the speed of the ball.
My code is as follows:
import pygame
import sys
import math
class Ball(object):
def __init__(self, x, y, width, height, vx, vy, colour):
self.x = x
self.y = y
self.width = width
self.height = height
self.vx = vx
self.vy = vy
self.colour = colour
def render(self, screen):
pygame.draw.ellipse(screen, self.colour, self.rect)
def update(self):
self.x += self.vx
self.y += self.vy
#property
def rect(self):
return pygame.Rect(self.x, self.y, self.width, self.height)
class Paddle(object):
def __init__(self, x, y, width, height, speed, colour):
self.x = x
self.y = y
self.width = width
self.height = height
self.vx = 0
self.speed = speed
self.colour = colour
def render(self, screen):
pygame.draw.rect(screen, self.colour, self.rect)
def update(self):
self.x += self.vx
def key_handler(self, event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
self.vx = -self.speed
elif event.key == pygame.K_RIGHT:
self.vx = self.speed
elif event.key in (pygame.K_LEFT, pygame.K_RIGHT):
self.vx = 0
#property
def rect(self):
return pygame.Rect(self.x, self.y, self.width, self.height)
class Pong(object):
COLOURS = {"BLACK": ( 0, 0, 0),
"WHITE": (255, 255, 255),
"RED" : (255, 0, 0)}
def __init__(self):
pygame.init()
(WIDTH, HEIGHT) = (640, 480)
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("smach ball hit")
self.ball = Ball(5, 5, 50, 50, 5, 5, Pong.COLOURS["BLACK"])
self.paddle = Paddle(WIDTH / 2, HEIGHT - 50, 100,
10, 3, Pong.COLOURS["BLACK"])
self.score = 0
def play(self):
clock = pygame.time.Clock()
while True:
clock.tick(50)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type in (pygame.KEYDOWN, pygame.KEYUP):
self.paddle.key_handler(event)
self.collision_handler()
self.draw()
def collision_handler(self):
if self.ball.rect.colliderect(self.paddle.rect):
self.ball.vy = -self.ball.vy
self.score += 1
if self.ball.x + self.ball.width >= self.screen.get_width():
self.ball.vx = -(math.fabs(self.ball.vx))
elif self.ball.x <= 0:
self.ball.vx = math.fabs(self.ball.vx)
if self.ball.y + self.ball.height >= self.screen.get_height():
pygame.quit()
sys.exit()
elif self.ball.y <= 0:
self.ball.vy = math.fabs(self.ball.vy)
if self.paddle.x + self.paddle.width >= self.screen.get_width():
self.paddle.x = self.screen.get_width() - self.paddle.width
elif self.paddle.x <= 0:
self.paddle.x = 0
def draw(self):
self.screen.fill(Pong.COLOURS["WHITE"])
font = pygame.font.Font(None, 48)
score_text = font.render("Score: " + str(self.score), True,
Pong.COLOURS["RED"])
self.screen.blit(score_text, (0, 0))
self.ball.update()
self.ball.render(self.screen)
self.paddle.update()
self.paddle.render(self.screen)
pygame.display.update()
if __name__ == "__main__":
Pong().play()
I am pretty new to programming and I don't know much of how it works. For the code that is already there, I had a friend who is more experienced to help me.
I suggest you to add one method that updates the ball speed depending on the score, and you can call it just after the collision detection (because there is where you increase the score). You can include a call to that method like this, inside your play method:
# (...) all your current code
self.collision_handler()
self.speed_up()
self.draw()
And, in the method implementation, you can divide your score, for example by 10, and add it as extra speed. Tweak this value to more or less, so it will fit your game better.
def speed_up(self):
delta = self.score // 10
if self.ball.vx > 0:
self.ball.vx += delta
else:
self.ball.vx -= delta
if self.ball.vy > 0:
self.ball.vy += delta
else:
self.ball.vy -= delta

Pygame is a bit laggy. Is it because of the many calculations?

import pygame
import math
import random
import time
pygame.init()
clock = pygame.time.Clock()
width = 800
height = 600
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Shadow Warrior")
#its like that because this reduses lag a lot and help for better gameplay
def loadify(imgname):
return pygame.image.load(imgname).convert_alpha(screen)
#Models:
logo = loadify("textures/logo.png")
pygame.display.set_icon(logo)
wallModel = loadify("textures/wall.png")
groundModel = loadify("textures/ground.png")
weaponModel = loadify("textures/weapon.png")
enemyBullet = loadify("textures/bullet.png")
playerBullet = loadify("textures/enemyBullet.png")
crosshair = loadify("textures/crosshair.png")
playerWalkAnimR = [loadify("textures\walk0.png"),
loadify("textures\walk1.png"),
loadify("textures\walk2.png")]
playerWalkAnimL = [loadify("textures\walk3.png"),
loadify("textures\walk4.png"),
loadify("textures\walk5.png")]
pygame.mouse.set_visible(False)
tileSize = 64
level = 0
hitParticles = []
weapons = []
removed_bullets = []
enemies = []
backgrounds = []
walls = []
all_bullets = []
# Classes
class Particle:
def __init__(self, x, y, velocityX, velocityY, radius, color):
self.x = x
self.y = y
self.velocityX = velocityX
self.velocityY = velocityY
self.radius = radius
self.color = color
self.lifetime = random.randrange(50, 100)
def draw(self, screen, camx, camy):
self.lifetime -= 1
self.x += self.velocityX
self.y += self.velocityY
pygame.draw.circle(screen, self.color, (self.x - camx, self.y - camy), self.radius)
class Background:
def __init__(self, x, y):
self.x = x
self.y = y
def draw(self, camx, camy):
screen.blit(groundModel, (self.x - camx - tileSize / 2, self.y - camy - tileSize / 2))
class Wall:
def __init__(self, x, y):
self.x = x
self.y = y
#Check if wall collides with smth
def collidesWith(self, other):
return pygame.Rect(self.x, self.y, tileSize, tileSize).colliderect(other.x, other.y, tileSize-16, tileSize)
def draw(self, camx, camy):
screen.blit(wallModel, (self.x - camx - tileSize / 2, self.y - camy - tileSize / 2))
class Bullet:
def __init__(self, x, y, velx, vely, isPlayer):
self.x = x
self.y = y
self.velx = velx
self.vely = vely
self.isPlayer = isPlayer
def collidesWith(self, other):
return pygame.Rect(self.x, self.y, tileSize - 16, tileSize - 16).colliderect(other.x, other.y, tileSize-36, tileSize-36)
def update(self):
self.x += self.velx
self.y += self.vely
for bullet in all_bullets:
for wall in walls:
if bullet.collidesWith(wall):
removed_bullets.append(bullet)
for i in removed_bullets:
if i in all_bullets:
all_bullets.remove(i)
def draw(self, camx, camy):
if (self.isPlayer):
screen.blit(pygame.transform.smoothscale(playerBullet, (16, 16)), (self.x - camx + 5, self.y - camy + 7))
else: screen.blit(pygame.transform.smoothscale(enemyBullet, (16, 16)), (self.x - camx + 5, self.y - camy + 7))
class slimeEnemy:
def __init__(self, x, y):
self.x = x
self.y = y
self.bulletSpeed = 1
self.aliveAnimations = [loadify("textures\slime_animation_0.png"),
loadify("textures\slime_animation_1.png"),
loadify("textures\slime_animation_2.png"),
loadify("textures\slime_animation_3.png"),]
self.animationsCount = 0
self.attackRate = 60
self.resetOffset = 0
self.SlimeHp = 7 + level * 2
self.slimeCollisionDmg = 1 + level/2
self.dmg = 1 + level / 2
self.isAlive = True
# self.isBoss = isBoss
#adding offset so the enemy doesnt move directly towards the player
self.offsetX = random.randrange(-150, 150)
self.offsetY = random.randrange(-150, 150)
def collidesWithAnything(self):
for wall in walls:
if wall.collidesWith(self):
return True
return False
def healthBar(self):
pygame.draw.rect(screen, (0, 255, 0), (self.x - camx - 20, self.y + 40 - camy, self.SlimeHp*10 + level*2, 7))
def collidesWith(self, other):
return pygame.Rect(self.x, self.y, tileSize-36, tileSize-36).colliderect(other.x, other.y, tileSize-36, tileSize-36)
def update(self):
# move enemy accordingly
if self.resetOffset == 0:
self.offsetX = random.randrange(-400, 400)
self.offsetY = random.randrange(-400, 400)
self.resetOffset = random.randrange(120, 150)
else: self.resetOffset -= 1
if player.x + self.offsetX > self.x:
self.x += 1
if self.collidesWithAnything():
self.x -= 1
elif player.x + self.offsetX < self.x:
self.x -= 1
if self.collidesWithAnything():
self.x += 1
if player.y + self.offsetY > self.y:
self.y += 1
if self.collidesWithAnything():
self.y -= 1
elif player.y + self.offsetY < self.y:
self.y -= 1
if self.collidesWithAnything():
self.y += 1
self.healthBar()
def attack(self):
for i in range(3):
angle = random.randrange(0, 360)
bulletSpeed_x = self.bulletSpeed * math.cos(angle) + random.uniform(-5, 5)
bulletSpeed_y = self.bulletSpeed * math.sin(angle) + random.uniform(-5, 5)
all_bullets.append(Bullet(self.x, self.y, bulletSpeed_x, bulletSpeed_y, False))
def drawAlive(self, camx, camy):
if self.animationsCount + 1 == 32:
self.animationsCount = 0
self.animationsCount += 1
if self.attackRate == 0:
self.attackRate = 60
self.attack()
self.attackRate -= 1
screen.blit(pygame.transform.scale(self.aliveAnimations[self.animationsCount// 8], (32, 30)), (self.x - camx, self.y - camy))
class Weapon:
def __init__(self, bulletSpeed, fireRate, bulletDmg):
self.shooting = False
self.bulletSpeed = bulletSpeed
self.fireRate = fireRate
self.bulletDmg = bulletDmg
self.energy = 100
self.i = 0
def handle_weapons(self, screen):
mouse_x, mouse_y = pygame.mouse.get_pos()
rel_x, rel_y = mouse_x - width/2, mouse_y - height/2
angle = (180/math.pi) * - math.atan2(rel_y, rel_x)
#draw crosshair
screen.blit(crosshair, (mouse_x, mouse_y+5))
#rotate and draw weapon accordingly
if angle > 90 or angle < -90:
player_weapon_copy = pygame.transform.rotate(pygame.transform.flip(weaponModel, True, False), angle - 180)
else:
player_weapon_copy = pygame.transform.rotate(weaponModel, angle)
screen.blit(player_weapon_copy, (width/2 +5 - int(player_weapon_copy.get_width()/2), height/2 + 15 - int(player_weapon_copy.get_height()/2)))
def Shooting(self):
if self.shooting:
#calculates the angles the bullet should travel :/
if self.i % self.fireRate == 0:
if (self.energy == 0):
pass
else:
mouse_x, mouse_y = pygame.mouse.get_pos()
distance_x = mouse_x - width/2
distance_y = mouse_y - height/2
angle = math.atan2(distance_y, distance_x)
bulletSpeed_x = self.bulletSpeed * math.cos(angle)
bulletSpeed_y = self.bulletSpeed * math.sin(angle)
all_bullets.append(Bullet(player.x, player.y, bulletSpeed_x, bulletSpeed_y, True))
self.energy -= 1
self.i += 1
class Player:
def __init__(self, x, y):
self.x = int(x)
self.y = int(y)
self.leftPr = False
self.rightPr = False
self.downPr = False
self.upPr = False
self.speed = 4
self.health = 5
self.maxHp = 5
self.animationsCount = 0
def healthBar(self):
pygame.draw.rect(screen, (255, 0, 0), (20, 25, 200, 10))
pygame.draw.rect(screen, (0, 255, 0), (20, 25, self.health*40, 10))
def energyBar(self):
pygame.draw.rect(screen, (255, 0, 0), (20, 55, 200, 10))
pygame.draw.rect(screen, (48, 117, 255), (20, 55, weapon.energy*2, 10))
def collidesWithAnything(self):
for wall in walls:
if wall.collidesWith(self):
return True
return False
def update(self):
if self.leftPr and not self.rightPr:
self.x -= self.speed
if self.collidesWithAnything():
self.x += self.speed
if self.rightPr and not self.leftPr:
self.x += self.speed
if self.collidesWithAnything():
self.x -= self.speed
if self.upPr and not self.downPr:
self.y -= self.speed
if self.collidesWithAnything():
self.y += self.speed
# revert if collision
if self.downPr and not self.upPr:
self.y += self.speed
if self.collidesWithAnything():
self.y -= self.speed
# check for enemy colisions
def animations(self):
if self.animationsCount + 1 >= 36:
self.animationsCount = 0
if self.rightPr:
screen.blit(pygame.transform.scale(playerWalkAnimR[self.animationsCount//12],(64, 64)), (width/2 - 40, height/2 - 30))
elif self.leftPr:
screen.blit(pygame.transform.scale(playerWalkAnimL[self.animationsCount//12],(64, 64)), (width/2 - 40, height/2 - 30))
else:
screen.blit(pygame.transform.scale(playerWalkAnimR[0],(64, 64)), (width/2 - 40, height/2 - 30))
self.animationsCount += 1
weapon = Weapon(10, 20, 2)
player = Player(1, 0)
#Loads map from file
def loadMapFromFile(path):
walls.clear()
backgrounds.clear()
enemies.clear()
with open(path, "r") as f:
y = 0
enemyLocations = []
# bossLocations = []
for line in f.readlines():
x = 0
for char in line:
if char != ' ' and char != "\n":
backgrounds.append(Background(x * tileSize, y * tileSize))
if char == '#':
walls.append(Wall(x * tileSize, y * tileSize))
elif char == 'p' or char == 'P':
player.x = x * tileSize
player.y = y * tileSize
elif char == 'e' or char == 'E':
if random.randint(1, 100) <= 40:
enemyLocations.append((x * tileSize, y * tileSize))
# elif char == 'b' or char == 'B':
# if random.randint(1, 100) <= 10:
# bossLocations.append((x * tileSize, y * tileSize, "True"))
x += 1
y += 1
for enemyL in enemyLocations:
enemies.append(slimeEnemy(*enemyL))
# for enemyL in bossLocations:
# enemies.append(slimeEnemy(*enemyL, "True"))
def gameOverScreen():
pygame.font.init()
font = pygame.font.Font('arial.ttf', 32)
text = font.render('GAME OVER', True, (255, 0, 0), (0, 0, 0))
text.set_colorkey((0, 0, 0))
screen.blit(text, (width/2-80,height/2-40))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
loadMapFromFile('maps/Map0.txt')
hitCooldown = 75
cooldown = 600
#running loop
gameOver = False
running = True
while running:
if gameOver:
gameOverScreen()
pass
else:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
player.upPr = True
if event.key == pygame.K_s:
player.downPr = True
if event.key == pygame.K_d:
player.rightPr = True
if event.key == pygame.K_a:
player.leftPr = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
player.upPr = False
if event.key == pygame.K_s:
player.downPr = False
if event.key == pygame.K_d:
player.rightPr = False
if event.key == pygame.K_a:
player.leftPr = False
if event.type == pygame.MOUSEBUTTONDOWN:
weapon.shooting = True
if event.type == pygame.MOUSEBUTTONUP:
weapon.shooting = False
# updating
camx = player.x - width / 2
camy = player.y - height / 2
screen.fill((0, 0, 0))
player.update()
#check if slime got hit
for bullet in all_bullets:
bullet.update()
for enemy in enemies:
if enemy.collidesWith(player):
if hitCooldown < 0:
hitCooldown = 75
player.health -= enemy.slimeCollisionDmg
if player.health <= 0:
gameOver = True
elif enemy.collidesWith(bullet) and bullet.isPlayer:
removed_bullets.append(bullet)
for i in range(10):
hitParticles.append(Particle(enemy.x, enemy.y, random.randrange(-5, 5)/10, random.randrange(-5, 5)/10, 4, (108, 216, 32)))
enemy.SlimeHp -= weapon.bulletDmg
if enemy.SlimeHp <= 0:
enemy.isAlive = False
if player.health >= player.maxHp:
player.health = player.maxHp
else:
player.health += 1
if weapon.energy >= 100:
weapon.energy = 100
else:
weapon.energy += 2
if bullet.collidesWith(player) and not bullet.isPlayer:
if hitCooldown < 0:
hitCooldown = 75
player.health -= enemy.dmg
if player.health <= 0:
gameOver = True
removed_bullets.append(bullet)
for bg in backgrounds:
bg.draw(camx, camy)
for wall in walls:
wall.draw(camx, camy)
# update all other entities
#draw bullet
for bullet in all_bullets:
bullet.draw(camx, camy)
# slime animations and remove dead slimes
for enemy in enemies:
enemy.update()
if enemy.isAlive:
enemy.drawAlive(camx, camy)
if not enemy.isAlive:
enemies.remove(enemy)
# draw particles
for particle in hitParticles:
if particle.lifetime > 0:
particle.draw(screen, camx, camy)
else:
hitParticles.pop(hitParticles.index(particle))
player.animations()
weapon.handle_weapons(screen)
weapon.Shooting()
player.healthBar()
player.energyBar()
if len(enemies) == 0:
if cooldown <= 0:
cooldown = 600
loadMapFromFile("maps\Map{0}.txt".format(level+1))
level+=1
hitCooldown -= 1
cooldown -= 1
# finally update screen
pygame.display.update()
clock.tick(60)
I know it is written really badly but I'm learning. The game is really laggy and I was wondering how I can make it run faster and smoother. Also is the lag created from the many calculations or am I just dumb? The lag comes when there are a lot of enemies on the map and they shoot at the same time. Can I fix the lag by making all the enemies shoot in different times? The game is for a school project.
I think your biggest issue is this:
class Bullet:
[ ... ]
def update(self):
self.x += self.velx
self.y += self.vely
for bullet in all_bullets: # <-- HERE
for wall in walls:
if bullet.collidesWith(wall):
removed_bullets.append(bullet)
for i in removed_bullets:
if i in all_bullets:
all_bullets.remove(i)
Then in the main loop:
#check if slime got hit
for bullet in all_bullets: # <-- AGAIN
bullet.update()
The code is iterating through the bullets many more times than is necessary. By the time all your bullet objects are updated, they have been processed /N/ * /N/ times (i.e.: N-squared). So as you get more any more bullets, this square grows catastrophically.
Try changing your Bullet.update() to only check itself. This will probably fix your lag issues - or at least help a lot. It will also "correct" your object encapsulation. A single Bullet has no business knowing about all the others, let alone checking collisions on their behalf.
class Bullet:
[ ... ]
def update(self):
self.x += self.velx
self.y += self.vely
for wall in walls:
if self.collidesWith(wall):
all_bullets.remove( self )
break
If you have any more N-squared loops like this, it will give the best speedup reworking them first.

How do I get the enemy to chase the player? I would also like to know how to jump onto the moving object when I jump and not just go through it

moving object. It currently moves left and right across the screen and I would like the user to be able to jump on it.
def moving_object():
global x_speed, y_speed
pygame.draw.rect(win, (200, 140, 150), rectangle)
rectangle.x += x_speed
if rectangle.right >= 500 or rectangle.left <= 0:
x_speed *= -1
class for my enemy. They currently move left and right across the screen but I would like them to follow the user. They can also not jump
class enemy():
walkRight = [pygame.image.load('R1E.png'), pygame.image.load('R2E.png'), pygame.image.load('R3E.png'), pygame.image.load('R4E.png'), pygame.image.load('R5E.png'), pygame.image.load('R6E.png'), pygame.image.load('R7E.png'), pygame.image.load('R8E.png'), pygame.image.load('R9E.png'), pygame.image.load('R10E.png'), pygame.image.load('R11E.png')]
walkLeft = [pygame.image.load('L1E.png'), pygame.image.load('L2E.png'), pygame.image.load('L3E.png'), pygame.image.load('L4E.png'), pygame.image.load('L5E.png'), pygame.image.load('L6E.png'), pygame.image.load('L7E.png'), pygame.image.load('L8E.png'), pygame.image.load('L9E.png'), pygame.image.load('L10E.png'), pygame.image.load('L11E.png')]
def __init__(self, x, y, width, height, end):
self.x = x
self.y = y
self.width = width
self.height = height
self.end = end
self.WalkCount = 0
self.vel = 3
self.path = [self.x, self.end]
self.hitbox = (self.x + 17, self.y + 2, 31, 57)
self.health = 10
self.visible = True
def draw(self, win):
self.move()
if self.visible:
if self.WalkCount + 1 >= 33:
self.WalkCount = 0
if self.vel > 0:
win.blit(self.walkRight[self.WalkCount //3], (self.x, self.y))
self.WalkCount += 1
else:
win.blit(self.walkLeft[self.WalkCount //3], (self.x, self.y))
self.WalkCount += 1
pygame.draw.rect(win, (255, 0, 0), (self.hitbox[0], self.hitbox[1] - 20, 50, 10))
pygame.draw.rect(win, (0, 255, 0), (self.hitbox[0], self.hitbox[1] - 20, 50, 10))
self.hitbox = (self.x + 17, self.y + 2, 31, 57)
def move(self):
if self.vel > 0:
if self.x + self.vel < self.path[1]:
self.x += self.vel
else:
self.vel = self.vel * -1
self.WalkCount = 0
else:
if self.x - self.vel > self.path[0]:
self.x += self.vel
else:
self.vel = self.vel * -1
self.WalkCount = 0
def hit(self):
if self.health > 0:
self.health -= 1
else:
self.visible = False
pass
So here is one way to make a pathfinding algorithm:
import pygame
import time
pygame.init()
screen = pygame.display.set_mode((700, 500))
clock = pygame.time.Clock()
to_coords = [550, 100]
from_coords = (150, 400)
def go_to_koeff(from_, to):
dx = to[0] - from_[0]
dy = to[1] - from_[1]
if dx != 0:
dx /= abs(dx)
if dy != 0:
dy /= abs(dy)
return dx, dy
follow_coords_x = from_coords[0]
follow_coords_y = from_coords[1]
velocity = 1
run = True
while run:
clock.tick(60)
screen.fill((0, 0, 0))
pygame.draw.circle(screen, (0, 255, 0), to_coords, 5)
pygame.draw.circle(screen, (255, 0, 0), from_coords, 5)
pygame.draw.circle(screen, (255, 255, 255), (follow_coords_x, follow_coords_y), 5)
koeff = go_to_koeff((follow_coords_x, follow_coords_y), to_coords)
follow_coords_x += velocity * koeff[0]
follow_coords_y += velocity * koeff[1]
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
to_coords[1] -= 3
if keys[pygame.K_DOWN]:
to_coords[1] += 3
if keys[pygame.K_LEFT]:
to_coords[0] -= 3
if keys[pygame.K_RIGHT]:
to_coords[0] += 3
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.update()
pygame.quit()
so basically the whole algorithm is that go_to_koeff() function: that function returns the koefficent of direction that can be used to change where the white dot moves that can be seen where the coefficient is multiplied by velocity. This algorithm isn't perfect but it finds the position so there is that. (You can play around a bit by moving the green dot with arrow keys to see how it moves)
Another idea that came to mind was tracking player position in a list and making the enemy follow all the coords in the list which could be even worse but it will feel like it is actually following You.
Also I just noticed that there is some useless change of variable names, but it doesn't affect anything much.

How to code bounce movement in pong using pygame

I'm a noob in python and I'm trying to recreate the Pong game, and I'm trying to do it by myself as much as possible.
These are the issues I currently have with my code:
I basically coded every possible movement of the ball when it bounces on the edge. I spent hours working on it, and I got it to work, I was just wondering if there was a more efficient way to produce a similar output with my code (coz I know this is supposed to be a beginner project)?
Every time the ball bounces past the edge, the score increments for a split second, and it goes back to 0 every time the ball respawns.
How can I make the ball spawn at random directions? at the start (and restart) of every round?
Here's my code for the class and the main function of the program:
import pygame
import random
from rect_button import Button
pygame.init()
WIDTH = 800
HEIGHT = 500
window = pygame.display.set_mode((WIDTH, HEIGHT))
TITLE = "Pong"
pygame.display.set_caption(TITLE)
# COLORS
black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)
green = (0, 255, 0)
# FONTS
small_font = pygame.font.SysFont("courier", 20)
large_font = pygame.font.SysFont("courier", 60, True)
class Paddle:
def __init__(self, x, y, width, height, vel, color):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = vel
self.color = color
def draw(self, window):
pygame.draw.rect(window, self.color, (self.x, self.y, self.width, self.height), 0)
class Ball:
def __init__(self, x, y, side, vel, color):
self.x = x
self.y = y
self.side = side
self.vel = vel
self.color = color
self.lower_right = False
self.lower_left = True
self.upper_right = False
self.upper_left = False
self.ball_bag = []
self.last_movement = 'ball.lower_right'
def draw(self, window):
pygame.draw.rect(window, self.color, (self.x, self.y, self.side, self.side), 0)
def move_lower_right(self):
self.x += self.vel
self.y += self.vel
def move_upper_right(self):
self.x += self.vel
self.y -= self.vel
def move_upper_left(self):
self.x -= self.vel
self.y -= self.vel
def move_lower_left(self):
self.x -= self.vel
self.y += self.vel
def start(self):
self.lower_right = True
self.lower_left = False
self.upper_right = False
self.upper_left = False
self.last_movement = 'ball.lower_left'
# return random.choice([self.lower_right, self.lower_left, self.upper_left, self.upper_right]) is True
def main():
run = True
fps = 60
clock = pygame.time.Clock()
# Initializing Paddles
left_paddle = Paddle(20, 100, 10, 50, 5, white)
right_paddle = Paddle(770, 350, 10, 50, 5, white)
balls = []
def redraw_window():
window.fill(black)
left_paddle.draw(window)
right_paddle.draw(window)
for ball in balls:
ball.draw(window)
player_A_text = small_font.render("Player A: " + str(score_A), 1, white)
player_B_text = small_font.render("Player B: " + str(score_B), 1, white)
window.blit(player_A_text, (320 - int(player_A_text.get_width() / 2), 10))
window.blit(player_B_text, (480 - int(player_B_text.get_width() / 2), 10))
pygame.draw.rect(window, white, (20, 450, 760, 1), 0)
pygame.draw.rect(window, white, (20, 49, 760, 1), 0)
pygame.draw.rect(window, white, (19, 50, 1, 400), 0)
pygame.draw.rect(window, white, (780, 50, 1, 400), 0)
pygame.display.update()
while run:
score_A = 0
score_B = 0
clock.tick(fps)
if len(balls) == 0:
ball = Ball(random.randrange(320, 465), random.randrange(200, 285), 15, 3, white)
balls.append(ball)
if ball.lower_left:
ball.move_lower_left()
if ball.last_movement == 'ball.lower_right':
if ball.y + ball.side > HEIGHT - 50:
ball.lower_left = False
ball.last_movement = 'ball.lower_left'
ball.upper_left = True
if ball.last_movement == 'ball.upper_left':
if ball.x < 30:
if left_paddle.x < ball.x < left_paddle.x + left_paddle.width:
if left_paddle.y < ball.y + ball.side < left_paddle.y + left_paddle.height:
ball.lower_left = False
ball.last_movement = 'ball.lower_left'
ball.lower_right = True
else:
score_B += 1
balls.remove(ball)
#ball.start()
if ball.y + ball.side > HEIGHT - 50:
ball.lower_left = False
ball.last_movement = 'ball.lower_left'
ball.upper_left = True
if ball.upper_left:
ball.move_upper_left()
if ball.last_movement == 'ball.lower_left':
if ball.x < 30:
if left_paddle.x < ball.x < left_paddle.x + left_paddle.width:
if left_paddle.y < ball.y + ball.side < left_paddle.y + left_paddle.height:
ball.upper_left = False
ball.last_movement = 'ball.upper_left'
ball.upper_right = True
else:
score_B += 1
balls.remove(ball)
#ball.start()
if ball.y < 50:
ball.upper_left = False
ball.last_movement = 'ball.upper_left'
ball.lower_left = True
if ball.last_movement == 'ball.upper_right':
if ball.y < 50:
ball.upper_left = False
ball.last_movement = 'ball.upper_left'
ball.lower_left = True
if ball.upper_right:
ball.move_upper_right()
if ball.last_movement == 'ball.upper_left':
if ball.y < 50:
ball.upper_right = False
ball.last_movement = 'ball.upper_right'
ball.lower_right = True
if ball.last_movement == 'ball.lower_right':
if ball.x + ball.side > WIDTH - 30:
if right_paddle.x + right_paddle.width > ball.x + ball.side > right_paddle.x:
if right_paddle.y < ball.y + ball.side < right_paddle.y + right_paddle.height:
ball.upper_right = False
ball.last_movement = 'ball.upper_right'
ball.upper_left = True
else:
score_A += 1
balls.remove(ball)
#ball.start()
if ball.y < 50:
ball.upper_right = False
ball.last_movement = 'ball.upper_right'
ball.lower_right = True
if ball.lower_right:
ball.move_lower_right()
if ball.last_movement == 'ball.upper_right':
if ball.y + ball.side > HEIGHT - 50:
ball.lower_right = False
ball.last_movement = 'ball.lower_right'
ball.upper_right = True
if ball.x + ball.side > WIDTH - 30:
if right_paddle.x + right_paddle.width > ball.x + ball.side > right_paddle.x:
if right_paddle.y < ball.y + ball.side < right_paddle.y + right_paddle.height:
ball.lower_right = False
ball.last_movement = 'ball.lower_right'
ball.lower_left = True
else:
score_A += 1
balls.remove(ball)
#ball.start()
if ball.last_movement == 'ball.lower_left':
if ball.y + ball.side > HEIGHT - 50:
ball.lower_right = False
ball.last_movement = 'ball.lower_right'
ball.upper_right = True
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
quit()
keys = pygame.key.get_pressed()
if keys[pygame.K_UP] and right_paddle.y > 50:
right_paddle.y -= right_paddle.vel
if keys[pygame.K_w] and left_paddle.y > 50:
left_paddle.y -= left_paddle.vel
if keys[pygame.K_DOWN] and right_paddle.y + right_paddle.height < HEIGHT - 50:
right_paddle.y += right_paddle.vel
if keys[pygame.K_s] and left_paddle.y + left_paddle.height < HEIGHT - 50:
left_paddle.y += left_paddle.vel
if keys[pygame.K_SPACE]:
pass
redraw_window()
quit()
def main_menu():
run = True
play_button = Button(green, 100, 350, 150, 75, "Play Pong")
quit_button = Button(red, 550, 350, 150, 75, "Quit")
pong_text = large_font.render("Let's Play Pong!!!", 1, black)
while run:
window.fill(white)
play_button.draw(window, black)
quit_button.draw(window, black)
window.blit(pong_text, (int(WIDTH / 2 - pong_text.get_width() / 2), 100))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
quit()
if event.type == pygame.MOUSEMOTION:
if play_button.hover(pygame.mouse.get_pos()):
play_button.color = (0, 200, 0)
else:
play_button.color = green
if quit_button.hover(pygame.mouse.get_pos()):
quit_button.color = (200, 0, 0)
else:
quit_button.color = red
if event.type == pygame.MOUSEBUTTONDOWN:
if play_button.hover(pygame.mouse.get_pos()):
main()
if quit_button.hover(pygame.mouse.get_pos()):
run = False
quit()
main_menu()
Thanks!!!
Answer to
Every time the ball bounces past the edge, the score increments for a split second, and it goes back to 0 every time the ball respawns.
The score is continuously initialized in the main loop. You have to initialize the score before the loop:
def main():
# [...]
score_A = 0 # <--- INSERT
score_B = 0
while run:
# score_A = 0 <--- DELETE
# score_B = 0
Answer to question 1:
Yes. There is definitely a lot more effective way to do things. There is no need to make so many variables for direction. Simply say direction = [True, False], where direction[0] represents left and not direction[0] represents right in x-axis. Similarly, direction[1] represents y axis. This also solves your problem of randomizing the direction at start. You can simply do direction = [random.randint(0, 1), random.randint(0, 1)] in your init method to randomize the direction. The same way, make a list for speed as well. self.speed = [0.5, random.uniform(0.1, 1)]. This way, speed in left and right will always be same, but y will vary depending on the random number chosen, so there is proper randomness and you also don't have to hardcode random directions in. With this, movement becomes really simple.
class Ball:
def __init__(self, x, y, color, size):
self.x = x
self.y = y
self.color = color
self.size = size
self.direction = [random.randint(0, 1), random.randint(0, 1)]
self.speed = [0.5, random.uniform(0.1, 1)]
def draw(self, display):
pygame.draw.rect(display, self.color, (self.x, self.y, self.size, self.size))
def move(self):
if self.direction[0]:
self.x += self.speed[0]
else:
self.x -= self.speed[0]
if self.direction[1]:
self.y += self.speed[0]
else:
self.y -= self.speed[0]
Because we have defined direction directions are Booleans, changing the state also becomes really easy. If the ball hits the paddle, you can simply toggle the bool direction[0] = not direction[0] in x and pick a new random number for y, instead of manually assigning bools.
def switchDirection(self):
self.direction = not self.direction
self.speed[1] = random.uniform(0.1, 1)
Paddle can be improved slightly as well, by giving Paddle class a move function instead of moving in the main loop. It just means you have to write less code.
def move(self, vel, up=pygame.K_UP, down=pygame.K_DOWN):
keys = pygame.key.get_perssed()
if keys[up]:
self.y -= vel
if keys[down]:
self.y += vel
For collisions, I recommend using pygame.Rect() and colliderect since it's a lot more robust and probably more efficient as well.
Example:
import random
import pygame
WIN = pygame.display
D = WIN.set_mode((800, 500))
class Paddle:
def __init__(self, x, y, width, height, vel, color):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = vel
self.color = color
def move(self, vel, up=pygame.K_UP, down=pygame.K_DOWN):
keys = pygame.key.get_pressed()
if keys[up]:
self.y -= vel
if keys[down]:
self.y += vel
def draw(self, window):
pygame.draw.rect(window, self.color, (self.x, self.y, self.width, self.height), 0)
def getRect(self):
return pygame.Rect(self.x, self.y, self.width, self.height)
left_paddle = Paddle(20, 100, 10, 50, 5, (0, 0, 0))
right_paddle = Paddle(770, 350, 10, 50, 5, (0, 0, 0))
class Ball:
def __init__(self, x, y, color, size):
self.x = x
self.y = y
self.color = color
self.size = size
self.direction = [random.randint(0, 1), random.randint(0, 1)]
self.speed = [0.3, random.uniform(0.2, 0.2)]
def draw(self, window):
pygame.draw.rect(window, self.color, (self.x, self.y, self.size, self.size))
def switchDirection(self):
self.direction[0] = not self.direction[0]
self.direction[1] = not self.direction[1]
self.speed = [0.2, random.uniform(0.1, 0.5)]
def bounce(self):
self.direction[1] = not self.direction[1]
self.speed = [0.2, random.uniform(0.01, 0.2)]
def move(self):
if self.direction[0]:
self.x += self.speed[0]
else:
self.x -= self.speed[0]
if self.direction[1]:
self.y += self.speed[1]
else:
self.y -= self.speed[1]
def getRect(self):
return pygame.Rect(self.x, self.y, self.size, self.size)
def boundaries(self):
if ball.x <= 10:
self.switchDirection()
if ball.x + self.size >= 800:
self.switchDirection()
if ball.y + self.size >= 490:
self.bounce()
if ball.y <= 0:
self.bounce()
ball = Ball(400, 250, (255, 0, 0), 20)
while True:
pygame.event.get()
D.fill((255, 255, 255))
ball.draw(D)
ball.boundaries()
ball.move()
#print(ball.x, ball.y)
left_paddle.draw(D)
right_paddle.draw(D)
right_paddle.move(0.4)
left_paddle.move(0.4, down=pygame.K_s, up=pygame.K_w)
if left_paddle.getRect().colliderect(ball.getRect()):
ball.switchDirection()
if right_paddle.getRect().colliderect(ball.getRect()):
ball.switchDirection()
WIN.flip()
I basically coded every possible movement of the ball when it bounces on the edge. I spent hours working on it, and I got it to work, I was just wondering if there was a more efficient way to produce a similar output with my code (coz I know this is supposed to be a beginner project)?
and
How can I make the ball spawn at random directions? at the start (and restart) of every round?
Rather than implementing "every" direction of the ball you can use float coordinates. these variables are usualy called dx and dy.
This way getting a random or reversed direction for your ball is simple, just use random or inverse values for dx and dy.
Th update for your ball should then look like:
def update(self. dt):
self.x += self.dx * self.speed * time_elapsed
self.y += self.dy * self.speed * time_elapsed # Time elasped is often called dt.
Every time the ball bounces past the edge, the score increments for a split second, and it goes back to 0 every time the ball respawns.
See Rabid76's answer. Ideally you should have a GameState object with scores, lives and other stuff as attributes.
Some food for thought on how to reduce all that ball movement/collision code, and make things a bit more reusable:
import pygame
class Ball:
def __init__(self, bounds, color):
from random import randint, choice
self.bounds = bounds
self.position = pygame.math.Vector2(
randint(self.bounds.left, self.bounds.left+self.bounds.width),
randint(self.bounds.top, self.bounds.top+self.bounds.height)
)
self.velocity = pygame.math.Vector2(choice((-1, 1)), choice((-1, 1)))
self.color = color
self.size = 8
def draw(self, window):
pygame.draw.rect(
window,
self.color,
(
self.position.x-self.size,
self.position.y-self.size,
self.size*2,
self.size*2
),
0
)
def update(self):
self.position.x += self.velocity.x
self.position.y += self.velocity.y
if not self.bounds.left+self.size < self.position.x < self.bounds.left+self.bounds.width-self.size:
self.velocity.x *= -1
if not self.bounds.top+self.size < self.position.y < self.bounds.top+self.bounds.height-self.size:
self.velocity.y *= -1
def main():
from random import randint
window_width, window_height = 800, 500
window = pygame.display.set_mode((window_width, window_height))
pygame.display.set_caption("Pong")
clock = pygame.time.Clock()
black = (0, 0, 0)
white = (255, 255, 255)
padding = 20
bounds = pygame.Rect(padding, padding, window_width-(padding*2), window_height-(padding*2))
ball = Ball(bounds, white)
def redraw_window():
window.fill(black)
pygame.draw.rect(
window,
white,
(
padding,
padding,
window_width-(padding*2),
window_height-(padding*2)
),
1
)
ball.draw(window)
pygame.display.update()
while True:
clock.tick(60)
ball.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
break
else:
redraw_window()
continue
break
pygame.quit()
return 0
if __name__ == "__main__":
import sys
sys.exit(main())
This isn't a complete drop-in replacement, I've just reimplemented the Ball class. There are no paddles. Essentially, when instantiating a ball, you pass in a pygame.Rect, which describes the bounds in which the ball is allowed to bounce around in. You also pass in a color tuple. The ball then picks a random position within the bounds (the position is a pygame.math.Vector2, as opposed to storing x and y as separate instance variables). A ball also has a velocity, which is also a pygame.math.Vector2, so that you may have independent velocity components - one for x (horizontal velocity) and one for y (vertical velocity). The size of a ball simply describes the dimensions of the ball. If the size is set to 8, for example, then a ball will be 16x16 pixels.
The Ball class also has an update method, which is invoked once per game-loop iteration. It moves the ball to the next position dictated by the velocity, and checks to see if the ball is colliding with the bounds. If it is, reverse the corresponding velocity component.

How do I make one Sprite move towards another in pygame/python

So I've been doing quite a lot of research on this question, and I still haven't been able to implement other people's solutions to solve mine. I'm trying to make the Mob2 class move towards the Player class. Any suggestions to my code, or even how to improve my code would be greatly appreciated :) BTW, the code I've written below has been made in Atom, if you have any questions I'll be around to answer them. Thank you all so much!!
# Pygame template - skeleton for a new pygame project
import pygame
import random
import math
from os import path
working_dir = path.dirname(__file__)
from pygame.locals import *
WIDTH = 1000
HEIGHT = 700
FPS = 60
# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
# initialize pygame and create window
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Virus Invaders")
clock = pygame.time.Clock()
font_name = pygame.font.match_font('arial')
health = 4
def draw_text(surf, text, size, x, y):
font = pygame.font.Font(font_name, size)
text_surface = font.render(text, True, WHITE)
text_rect = text_surface.get_rect()
text_rect.midtop = (x, y)
surf.blit(text_surface, text_rect)
def newmob():
m = Mob()
all_sprites.add(m)
mobs.add(m)
def newmob2():
n = Mob2()
all_sprites.add(n)
mobs2.add(n)
def draw_health_bar(surf, x, y, health):
if health==4:
healthImage = healthSheet.get_image(0, 102, 176, 23)
screen.blit(healthImage, [50, 50])
if health==3:
healthImage = healthSheet.get_image(0, 128, 176, 23)
screen.blit(healthImage, [50, 50])
if health==2:
healthImage = healthSheet.get_image(0, 155, 176, 23)
screen.blit(healthImage, [50, 50])
if health==1:
healthImage = healthSheet.get_image(0, 182, 176, 23)
screen.blit(healthImage, [50, 50])
if health==0:
healthImage = healthSheet.get_image(0, 209, 176, 23)
screen.blit(healthImage, [50, 50])
class Player(pygame.sprite.Sprite):
def __init__(self, health):
pygame.sprite.Sprite.__init__(self)
self.image = dudeSpriteSheet.get_image(60, 0, 60, 60)
self.rect = self.image.get_rect()
self.radius = 25
#pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
self.rect.centerx = 100
self.rect.centery = 400.5
self.speedx = 0
self.speedy = 0
self.health = health
def update(self):
self.speedx = 0
self.speedy = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_s]:
self.speedy = 4
if keystate[pygame.K_w]:
self.speedy = -4
if keystate[pygame.K_d]:
self.speedx = 4
if keystate[pygame.K_a]:
self.speedx = -4
self.rect.x += self.speedx
self.rect.y += self.speedy
if self.rect.right > WIDTH-80:
self.rect.right = WIDTH-80
if self.rect.left < 90:
self.rect.left = 90
if self.rect.bottom > HEIGHT-87:
self.rect.bottom = HEIGHT-87
if self.rect.top < 187:
self.rect.top = 187
def shoot(self, X, Y, direction):
if direction == 1:
self.image = dudeSpriteSheet.get_image(60, 0, 60, 60)
elif direction == 2:
self.image = dudeSpriteSheet.get_image(0, 0, 60, 60)
elif direction == 3:
self.image = dudeSpriteSheet.get_image(120, 0, 60, 60)
elif direction == 4:
self.image = dudeSpriteSheet.get_image(180, 0, 60, 60)
X = X+self.speedx
Y = Y+self.speedy
bullet = Bullet(self.rect.centerx, self.rect.centery, X, Y)
all_sprites.add(bullet)
bullets.add(bullet)
class Mob(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = virus_img
self.image.set_colorkey(WHITE)
self.rect = self.image.get_rect()
self.radius = int(self.rect.width * 0.85 / 2)
#pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
self.rect.x = WIDTH - 200
self.rect.y = 400.5
self.speedx = random.randrange(-4, 4)
self.speedy = random.randrange(-4, 4)
def update(self):
self.rect.x += self.speedx
self.rect.y += self.speedy
if self.rect.bottom >= HEIGHT - 87:
self.speedy = -self.speedy
if self.rect.top <= 193:
self.speedy = -self.speedy
if self.rect.left <= 94:
self.speedx = -self.speedx
if self.rect.right >= WIDTH - 96:
self.speedx = -self.speedx
class Mob2(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = virus2_img
self.image.set_colorkey(WHITE)
self.rect = self.image.get_rect()
self.radius = int(self.rect.width * 0.85 / 2)
pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
self.rect.x = WIDTH - 200
self.rect.y = 300
self.rot = 0
self.speed = 3
def update(self, Player):
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y, X, Y):
pygame.sprite.Sprite.__init__(self)
self.image = bullet_img
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.radius = 25
self.rect.bottom = y
self.rect.centerx = x
self.speedy = Y
self.speedx = X
def update(self):
self.rect.x += self.speedx
self.rect.y += self.speedy
# Kill if it moves off the top of the screen
if self.rect.bottom < 0 or self.rect.top > 700 or self.rect.right <
0 or self.rect.left > 1000:
self.kill()
class Spritesheet:
#Utility class for loading and parsing spritesheets
def __init__(self, filename):
self.spritesheet = pygame.image.load(filename).convert()
def get_image(self, x, y, width, height):
#Grab an image out of a larger spritesheet
image = pygame.Surface((width, height))
image.blit(self.spritesheet, (0, 0), (x, y, width, height))
image.set_colorkey(BLACK)
return image
# Load all game graphics
background = pygame.image.load(path.join(working_dir,
'GameScreen.png')).convert()
background_rect = background.get_rect()
player_img = pygame.image.load(path.join(working_dir,'dude.png')).convert()
virus_img =
pygame.image.load(path.join(working_dir,'badguy1.png')).convert()
bullet_img =
pygame.image.load(path.join(working_dir,'bullet.png')).convert()
dudeSpriteSheet = Spritesheet(path.join(working_dir,
'DudeSpriteSheet2.png'))
healthSheet = Spritesheet(path.join(working_dir, 'health.png'))
virus2_img =
pygame.image.load(path.join(working_dir,'badguy2(2).png')).convert()
all_sprites = pygame.sprite.Group()
mobs = pygame.sprite.Group()
mobs2 = pygame.sprite.Group()
bullets = pygame.sprite.Group()
player = Player(health)
all_sprites.add(player)
for i in range(8):
newmob()
newmob2()
score = 0
# Game loop
running = True
while running:
# keep loop running at the right speed
clock.tick(FPS)
# Process input (events)
for event in pygame.event.get():
# check for closing window
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
player.shoot(10, 0, 1)
elif event.type == pygame.KEYDOWN and event.key == pygame.K_UP:
player.shoot(0, -10, 2)
elif event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN:
player.shoot(0, 10, 3)
elif event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT:
player.shoot(-10, 0, 4)
# Update
all_sprites.update()
#Check to see if bullet hits a mob
hits = pygame.sprite.groupcollide(mobs, bullets, True,
pygame.sprite.collide_circle)
for hit in hits:
score += 1
newmob()
# Check to see if a virus hits a player
hits = pygame.sprite.spritecollide(player, mobs, True,
pygame.sprite.collide_circle)
for hit in hits:
health -= 1
newmob()
if health <= 0:
running = False
# Draw / render
screen.fill(BLACK)
screen.blit(background, background_rect)
all_sprites.draw(screen)
draw_text(screen, str(score), 18, WIDTH / 2, 10)
draw_health_bar(screen, 5, 5, health)
# *after* drawing everything, flip the display
pygame.display.flip()
pygame.quit()
First compare Mob.rect.x with Player.rect.x to see if it should move left or right, then do the same with rect.y to see if it should move up or down. The its simply getting Mob to move in that direction.

Categories

Resources