Collision Detection Not Working - PyGame - python

I'm working in a game, and in this game an object falls from the top of the game screen and the player at the bottom of the screen has to hit the object falling. When the player hits the falling object, the player's width and height needs to increase. When I tested the code, the collision worked when the player hit the falling object from the side, but the collision didn't work when the player hit the falling object in the middle. Can someone help me?
PYTHON
# IMPORTS
import pygame, random
# GLOBALS
global screen, displayW, displayH
global clock, FPS
global end, food, player
# SETGLOBALVALUES
def setGlobalValues():
global screen, displayW, displayH
global clock, FPS
global end, food, player
displayW = 800
displayH = 600
screen = pygame.display.set_mode((displayW, displayH))
clock = pygame.time.Clock()
FPS = 60
end = False
food = Food()
player = Player()
# MAIN
def main():
pygame.init()
setGlobalValues()
setup()
gameLoop()
quitGame()
# GAMELOOP
def gameLoop():
global end, player
while not end:
for event in pygame.event.get():
# ONCLICK QUIT
if event.type == pygame.QUIT:
end = True;
# KEYDOWN
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.velX -= 10
if event.key == pygame.K_RIGHT:
player.velX += 10
# KEYUP
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.velX = 0
if event.key == pygame.K_RIGHT:
player.velX = 0
draw()
animate()
collision()
setFPS()
# DRAW
def draw():
global screen, food, player
# fill background
screen.fill((255, 255, 255))
player.draw()
food.draw()
# update
pygame.display.update()
# ANIMATE
def animate():
global food, player
food.animate()
player.animate()
# COLLISION
def collision():
global player, food;
player.collision()
food.collision();
# SETFPS
def setFPS():
global clock, FPS
clock.tick(FPS);
# CLASSES
class Food():
def __init__(self, img="", x=0, h=0, w=0, velY=0, color=()):
global displayW
self.img = pygame.image.load("assets/img/rsz_burger.png")
self.w = 30
self.h = 30
self.x = random.randrange(0, displayW - self.w)
self.y = -100
self.velY = 3
self.color = (255, 0, 0)
def draw(self):
global screen
screen.blit(self.img, (self.x, self.y))
def animate(self):
self.y += self.velY
if self.y >= displayW:
self.reset()
def collision(self):
global displayW, displayH
# collision with player
if self.y >= player.y and self.y <= player.y + player.h and self.x >= player.x and self.x <= player.x + player.w:
player.w += player.increase
player.h += player.increase
player.y - player.increase
print(player.w)
self.reset()
def reset(self):
self.y = -100
self.x = random.randrange(0, displayW - self.w)
self.velY += 1
screen.blit(self.img, (self.x, self.y))
class Player():
def __init__(self, x=0, y=0, velX=0, velY=0, w=0, h=0, increase=0, color=()):
global displayW, displayH
self.w = 20
self.h = 20
self.x = displayW / 2 - self.w / 2
self.y = displayH - 100
self.velX = 0
self.velY = 0
self.increase = 2
self.color = (0, 0, 0)
def draw(self):
global screen
pygame.draw.ellipse(screen, self.color, (self.x, self.y, self.w, self.h))
def animate(self):
self.x += self.velX
self.y += self.velY
def collision(self):
global displayW
# collision to walls
if self.x <= 0:
self.velX = 0
elif self.x + self.h >= displayW:
self.velX = 0
# SETUP
def setup():
pygame.display.set_caption("Food Catcher")
# QUIT GAME
def quitGame():
pygame.quit()
quit()
# CALL MAIN
if __name__ == "__main__":
main()

The problem was that had to minus the player's width
Before:
if self.y >= player.y and self.y <= player.y + player.h and self.x >= player.x and self.x <= player.x + player.w:
player.w += player.increase
player.h += player.increase
player.y - player.increase
After:
if self.y >= player.y - player.h and self.y <= player.y + player.h and self.x >= player.x - player.w and self.x <= player.x + player.w:
player.w += player.increase
player.h += player.increase
player.y - player.increase
I forgot that the objects x and y start at the top left.

Related

Pygame NameError: free variable 'lost' referenced before assignment in enclosing scope

I have recently been working on a Space Invaders game in Pygame via Tech with Tim YouTube tutorial and have encounter a name error on line 111:
NameError: free variable 'lost' referenced before assignment in
enclosing scope.
Link to the tutorial https://www.youtube.com/watch?v=Q-__8Xw9KTM&feature=youtu.be&t=1112
Code:
import pygame
import os
import time
import random
import math
import sys
WIDTH, HEIGHT = 750, 750
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("Space Invaders")
#Game Variables
pygame.font.init()
pygame.init()
#Ships
RED_SPACE_SHIP = pygame.image.load(os.path.join('assets','pixel_ship_red_small.png'))
GREEN_SPACE_SHIP = pygame.image.load(os.path.join('assets','pixel_ship_green_small.png'))
BLUE_SPACE_SHIP = pygame.image.load(os.path.join('assets','pixel_ship_blue_small.png'))
YELLOW_SPACE_SHIP = pygame.image.load(os.path.join('assets','pixel_ship_yellow.png'))
#Lasers
RED_LASER = pygame.image.load(os.path.join('assets','pixel_laser_red.png'))
BLUE_LASER = pygame.image.load(os.path.join('assets','pixel_laser_blue.png'))
YELLOW_LASER = pygame.image.load(os.path.join('assets','pixel_laser_yellow.png'))
GREEN_LASER = pygame.image.load(os.path.join('assets','pixel_laser_green.png'))
#Background
BG = pygame.transform.scale2x(pygame.image.load(os.path.join('assets','background-black.png')).convert_alpha())
class Ship:
def __init__(self, x, y, health=100):
self.x = x
self.y = y
self.health = health
self.ship_img = None
self.laser_img = None
self.lasers = []
self.cool_down_counter = 0
def draw(self, window):
screen.blit(self.ship_img, (self.x, self.y))
def get_width(self):
return self.ship_img.get_width()
def get_height(self):
return self.ship_img.get_height()
class Player(Ship):
def __init__(self,x,y, health=100):
super().__init__(x, y, health)
self.ship_img = YELLOW_SPACE_SHIP
self.laser_img = YELLOW_LASER
self.mask = pygame.mask.from_surface(self.ship_img)
self.max_health = health
class Enemy(Ship):
COLOUR_MAP = {
"red": (RED_SPACE_SHIP, RED_LASER),
"green": (GREEN_SPACE_SHIP, GREEN_LASER),
"blue": (BLUE_SPACE_SHIP, BLUE_LASER),
}
def __init__(self, x, y, colour, health=100):
super().__init__(x, y, health)
self.ship_img, self.laser_img = self.COLOUR_MAP[colour]
self.mask = pygame.mask.from_surface(self.ship_img)
def move(self, vel):
self.y += vel
def main():
run = True
FPS = 60
level = 0
lives = 5
main_font = pygame.font.SysFont("comicsans", 50)
lost_font = pygame.font.SysFont("comicsans", 60)
enemies = []
wave_length = 5
enemy_vel = 1
player_vel = 5
player = Player(300, 650)
clock = pygame.time.Clock()
def redraw_window():
screen.blit(BG, (0,0))
lives_label = main_font.render(f'Lives: {lives}', 1, (255,255,255))
level_label= main_font.render(f'Level: {level}', 1, (255,255,255))
screen.blit(lives_label, (10,10))
screen.blit(level_label, (WIDTH - level_label.get_width() - 10, 10))
for enemy in enemies:
enemy.draw(screen)
player.draw(screen)
if lost:
lost_label = lost_font.render("You Lost!!", 1, (255,255,255))
screen.blit(lost_label, (WIDTH/2 - lost_label.get_width()/2, 350))
pygame.display.update()
while True:
clock.tick(FPS)
redraw_window()
if lives <= 0 or player.health <= 0:
lost = True
lost_count += 1
if len(enemies) == 0:
level += 1
wave_length += 5
for i in range(wave_length):
enemy = Enemy(random.randrange(50, WIDTH-100), random.randrange(-1500, -100), random.choice(["red", "blue", "green"]))
enemies.append(enemy)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and player.x - player_vel > 0:
player.x -= player_vel
if keys[pygame.K_RIGHT] and player.x + player_vel + player.get_width() < WIDTH:
player.x += player_vel
if keys[pygame.K_UP] and player.y - player_vel > 0:
player.y -= player_vel
if keys[pygame.K_DOWN] and player.y + player_vel + player.get_height() < HEIGHT:
player.y += player_vel
for enemy in enemies:
enemy.move(enemy_vel)
if enemy.y + enemy.get_height() > HEIGHT:
lives -= 1
enemies.remove(enemy)
main()
For lost and lost_count, you need to mark them as global so the method does not treat them as local variables:
In your code, replace this:
def main():
With this:
lost = False
lost_count = 0
def main():
# use global variables
global lost
global lost_count

Enemy move is wrong why?

I want to create a spaceship game to using pygame. I want to enemies movement like this:
first enemies moving x coordination and enemy x coordinate increasing on x (moving right)
if enemy coordinates x >= WIDHT , enemy coordinates y += 5 and enemy x coordinate is decreasing on x (moving left)
if enemy coordinates x <= 0 ,enemy coordinates y -= 5 and enemy x coordinate is increasing on x (moving right)
I want to move enemies like this, but I typed code and enemies not moving as I want:
import pygame
import random
import time
WIDTH , HEIGHT = (750, 600)
WIN = pygame.display.set_mode((WIDTH,HEIGHT))
BG_IMAGE = pygame.transform.scale(pygame.image.load("yeni_resim.jpg"),(WIDTH, HEIGHT))
CAPTION_IMAGE = pygame.image.load("spaceship.png")
ENEMY_IMAGE = pygame.image.load("enemy.png")
BULLET_IMAGE = pygame.image.load("bullet.png")
PLAYER_IMAGE = pygame.image.load("warship.png")
Creating Bullet Class
class Bullet:
def __init__(self, x, y, img):
self.x = x
self.y = y
self.img = img
self.mask = pygame.mask.from_surface(self.img)
def draw(self, window):
window.blit(self.img, (self.x, self.y))
def move(self, vel):
self.y += vel
def off_screen(self, height):
return not (self.y <= height and self.y >=0)
def collision(self, obj):
pass
And creating ship class(for warship and enemy)
class Ship:
def __init__(self, x, y):
self.x = x
self.y = y
self.ship_img = None
def draw(self, window):
window.blit(self.ship_img, (self.x, self.y))
def get_width(self):
return self.ship_img.get_width()
def get_height(self):
return self.ship_img.get_height()
class Player(Ship):
def __init__(self, x, y):
super().__init__(x, y)
self.ship_img = PLAYER_IMAGE
self.mask = pygame.mask.from_surface(self.ship_img)
def draw(self, window):
super().draw(window)
This is enemy class and i create def for enemy movement:
class Enemy(Ship):
def __init__(self, x, y):
super().__init__(x,y)
self.ship_img = ENEMY_IMAGE
self.mask = pygame.mask.from_surface(self.ship_img)
def move(self, vel):
self.x += vel
if self.x >= 684:
self.x -= vel
self.y += 5
elif self.x <= 0:
self.x += vel
self.y += 5
def main():
run = True
FPS = 60
clock = pygame.time.Clock()
player = Player(350, 500)
player_vel = 8
enemy = Enemy(350, 100)
enemy_vel = 5
def redraw_window():
WIN.blit(BG_IMAGE,(0,0))
player.draw(WIN)
enemy.draw(WIN)
pygame.display.update()
while run:
clock.tick(FPS)
redraw_window()
enemy.move(enemy_vel)
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT] and player.x + player_vel + player.get_width() < WIDTH:
player.x += player_vel
if keys[pygame.K_LEFT] and player.x - player_vel > 0:
player.x -= player_vel
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
main()
Try removing your move function and replacing it with this in the while loop:
enemy.x += enemy_vel
if enemy.x >= WIDTH - ENEMY_IMAGE.get_width() or enemy.x <= 0:
enemy_vel *= -1
enemy_y += 5

Shooting tank bullet in python/pygame

I'm working on python project right now using pygame library and I need help with this project I make. I want my tank to shoot bullets and so those bullets ricochet from the walls. What is the best way possible to do this?
I'm sorry that my code looks so messy, I've been watching different youtube tutorials and they all do differently.
Here is my code
import pygame
pygame.init()
# ======================= Variables =======================
# ------------------------ Screen -------------------------
screenWidth = 1060
screenHeight = 798
screenSize = (screenWidth, screenHeight)
display = pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption("Tank game")
bg = pygame.image.load("sprites/background/background1.png")
bg = pygame.transform.scale(bg, (screenWidth, screenHeight))
# ------------------------ Player -------------------------
# ------------------------ Enemy -------------------------
# ----------------------- Other ---------------------------
red = (155, 0, 0)
clock = pygame.time.Clock()
fps = 60
# ========================= Clases ========================
class player(pygame.sprite.Sprite):
def __init__(self, location, angle, vel, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("sprites/player/player_tank.png")
self.x = x
self.y = y
self.vel = vel
self.angle = angle
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
if self.angle == 360:
self.angle = 0
def rotate(self):
rot_image = pygame.transform.rotate(self.image, self.angle)
rot_rect = rot_image.get_rect(center=self.rect.center)
return rot_image, rot_rect
def moving_after_angle_change(self):
x = round(math.cos(math.radians(self.angle + 90)), 1) * self.vel
y = round(math.sin(math.radians(self.angle - 90)), 1) * self.vel
return x, y
class enemy(pygame.sprite.Sprite):
def __init__(self, x, y, width, height, end):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("sprites/enemy/enemy_tank.png")
self.x = x
self.y = y
self.width = width
self.height = height
self.end = end
self.path = [self.x, self.y, self.end]
self.vel = 5
def draw(self, display):
self.move()
display.blit(self.image, (self.x, self.y))
def move(self):
if self.vel > 0:
pass
# Bullet
bullet = pygame.image.load("sprites/bullet/bullet.png")
bullet = pygame.transform.scale(bullet, (16, 16))
bullet_x = 0
bullet_y = 480
bullet_x_change = 0
bullet_y_change = 10
bullet_state = 'ready'
# ======================= Functions =======================
def redrawGameWindow():
display.blit(bg, (0, 0))
display.blit(player_tank.image, player_tank.rect)
display.blit(enemy_tank.image, (enemy_tank.x, enemy_tank.y))
#display.blit(bullet, (player_tank.x + 160, player_tank.y + 100))
pygame.display.flip()
def fireBullet(x, y):
global bullet_state
bullet_state = 'fire'
display.blit(bullet, (x + 16, y + 10))
player_location = [70, 570]
player_angle = 270
player_angle_change = 0
player_vel = 0
player_x_change = 0
player_y_change = 0
player_tank_x_change_store = 0
player_tank_y_change_store = 0
run = True
while run:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
player_vel = 2
elif event.key == pygame.K_DOWN:
player_vel = -2
elif event.key == pygame.K_LEFT:
player_angle_change = 2
elif event.key == pygame.K_RIGHT:
player_angle_change = -2
if event.key == pygame.K_SPACE:
display.blit(bullet, (player_tank.x + 160, player_tank.y + 100))
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
player_vel = 0
elif event.key == pygame.K_DOWN:
player_vel = 0
elif event.key == pygame.K_LEFT:
player_angle_change = 0
elif event.key == pygame.K_RIGHT:
player_angle_change = 0
player_angle += player_angle_change
player_tank = player(player_location, player_angle, player_vel, player_x_change, player_y_change)
enemy_tank = enemy(800, 170, 64, 64, 700)
player_tank.image, player_tank.rect = player_tank.rotate()
player_tank.x_change, player_tank.y_change = player_tank.moving_after_angle_change()
player_tank_x_change_store += player_tank.x_change
player_tank_y_change_store += player_tank.y_change
player_tank.rect.centerx += player_tank_x_change_store
player_tank.rect.centery += player_tank_y_change_store
# Bullet movement
if bullet_state == "fire":
fireBullet(player_tank.x, bullet_y)
bullet_y -= bullet_y_change
redrawGameWindow()
pygame.quit()
quit()
One way to do this is to make the bullets velocity flip when it hits a wall. Now I'm assuming the walls are the edge of the screen so what you need to do is in the loop, check if the bullet is about to hit a wall (the edge of the screen) and if it is, flip its x_change and y_change. So something like this:
if bullet_y <= 0:
bullet_y_change *= -1
bullet_y = 0
if bullet_y >= screenHeight:
bullet_y_change *= -1
bullet_y = screenHeight
if bullet_x <= 0:
bullet_x_change *= -1
bullet_x = 0
if bullet_x >= screenWidth:
bullet_x_change *= 1
bullet_x = screenWidth
Here's a full example, based on an old answer:
import pygame
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((32, 32))
self.image.fill((0, 0, 0))
self.image.set_colorkey((0, 0, 0))
pygame.draw.polygon(self.image, pygame.Color('dodgerblue'), ((0, 0), (32, 16), (0, 32)))
self.org_image = self.image.copy()
self.angle = 0
self.direction = pygame.Vector2(1, 0)
self.rect = self.image.get_rect(center=(200, 200))
self.pos = pygame.Vector2(self.rect.center)
def update(self, events, dt):
for e in events:
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_SPACE:
self.groups()[0].add(Projectile(self.rect.center, self.direction.normalize()))
pressed = pygame.key.get_pressed()
if pressed[pygame.K_a]:
self.angle += 3
if pressed[pygame.K_d]:
self.angle -= 3
self.direction = pygame.Vector2(1, 0).rotate(-self.angle)
self.image = pygame.transform.rotate(self.org_image, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
class Projectile(pygame.sprite.Sprite):
def __init__(self, pos, direction):
super().__init__()
self.image = pygame.Surface((8, 8))
self.image.fill((0, 0, 0))
self.image.set_colorkey((0, 0, 0))
pygame.draw.circle(self.image, pygame.Color('orange'), (4, 4), 4)
self.rect = self.image.get_rect(center=pos)
self.direction = direction
self.pos = pygame.Vector2(self.rect.center)
self.lives = 15
def update(self, events, dt):
# Bounding box of the screen
screen_r = pygame.display.get_surface().get_rect()
# where we would move next
next_pos = self.pos + self.direction * dt
# we hit a hall
if not screen_r.contains(self.rect):
# after 15 hits, destroy self
self.lives -= 1
if self.lives == 0:
return self.kill()
# horizontal reflection
if next_pos.x > screen_r.right or next_pos.x < screen_r.left:
self.direction.x *= -1
# vertical reflection
if next_pos.y > screen_r.bottom or next_pos.y < screen_r.top:
self.direction.y *= -1
# move after applying reflection
next_pos = self.pos + self.direction * dt
# set the new position
self.pos = next_pos
self.rect.center = self.pos
def main():
pygame.init()
screen = pygame.display.set_mode((500, 500))
sprites = pygame.sprite.Group(Player())
clock = pygame.time.Clock()
dt = 0
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
sprites.update(events, dt)
screen.fill((30, 30, 30))
sprites.draw(screen)
pygame.display.update()
dt = clock.tick(60)
if __name__ == '__main__':
main()
See how using the Vector2 class makes this kind of tasks very easy to solve.
Also, look at the proper usage of the Sprite class. Each Sprite minds its own business: the Player class handles rotating the player and creating projectiles, Projectile handles moving the projectiles and bouncing of the wall.

Pygame - Getting enemy sprites to move towards player

As of currently the enemy sprites just spawn on the axis, and "move" with the player which is actually a scrolling background, and I'd like for the enemies to move only along the X axis so it doesn't destroy the immersion.
I'd also like for the sprites to spawn "Off the map" and whenever the map scrolls towards them they move towards the players set X axis? I think that would keep things simple, but isn't really the question at hand right now.
The current code I was trying to get working for the movement was :
def move_towards_player(self, player):
# Find direction vector (dx, dy) between enemy and player.
dx, dy = player.rect.x - self.rect.x, player.rect.y - self.rect.y
dist = math.hypot (dx, dy)
dx, dy = dx / dist, dy / dist # Normalize
# Move along this normalized vector towards the player
self.rect.x += dx * self.speed
self.rect.y += dy * self.speed
But it wouldn't work, this is with importing the math module.
(I know I don't need the y movements just wanted to get it working first)
Here is the rest of the code --
Zombie.py:
import pygame
from pygame.locals import *
import random
import math
class ZombieEnemy(pygame.sprite.Sprite):
def __init__(self, x=300, y=360):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('images/zombie.png')
self.rect = self.image.get_rect()
self.rect.center = (x, y)
all_zombies = pygame.sprite.Group()
for i in range( 50 ):
new_x = random.randrange( 0, 10000) # random x-position
# new_y = random.randrange( 0, ) # random y-position
all_zombies.add(ZombieEnemy(new_x)) # create, and add to group
I wasn't sure if I should create a whole new class for enemy movement, or what my partner is currently working on the Player, and getting the sprite animations and movement working right.
But here is the main code I have as of now:
import pygame
from Zombie import *
import math
from pygame.locals import *
pygame.init()
​
win = pygame.display.set_mode((900,567))
​
pygame.display.set_caption("Power Rangers ZOMBIES")
​
walkRight = [pygame.image.load('images/walk1.png'), pygame.image.load('images/walk2.png'), pygame.image.load('images/walk3.png'), pygame.image.load('images/walk4.png'), pygame.image.load('images/walk5.png'), pygame.image.load('images/walk6.png')]
walkLeft = [pygame.image.load('images/leftwalk2.png'), pygame.image.load('images/leftwalk3.png'), pygame.image.load('images/leftwalk4.png'), pygame.image.load('images/leftwalk5.png'), pygame.image.load('images/leftwalk6.png'), pygame.image.load('images/leftwalk7.png')]
bg = pygame.image.load('images/background.png')
char = pygame.image.load('images/standingstill.png')
clock = pygame.time.Clock()
​
class Player(pygame.sprite.Sprite):
def __init__(self,x,y,width,height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 0
self.isJump = False
self.left = False
self.right = False
self.walkCount = 0
self.jumpCount = 10
​
def draw(self, win):
if self.walkCount + 1 >= 18:
self.walkCount = 0
​
if self.left:
win.blit(walkLeft[self.walkCount//3], (self.x,self.y))
self.walkCount += 1
elif self.right:
win.blit(walkRight[self.walkCount//3], (self.x,self.y))
self.walkCount +=1
else:
win.blit(char, (self.x,self.y))
​
class Background(pygame.sprite.Sprite):
def __init__(self, image_file, location):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image = pygame.image.load('images/background.png')
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
​
BackGround = Background('images/background.png', [0,0])
​
# def redrawGameWindow():
# win.blit(bg, (0,0))
# man.draw(win)
# pygame.display.update()
​
#mainloop
man = Player(100, 340, 40, 60)
run = True
while run:
clock.tick(27)
​
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
​
keys = pygame.key.get_pressed()
​
if keys[pygame.K_LEFT] and man.x > man.vel:
BackGround.rect.left = BackGround.rect.left + int(10)
man.x -= man.vel
man.left = True
man.right = False
elif keys[pygame.K_RIGHT]: #and man.x < 500 - man.width - man.vel:
BackGround.rect.left = BackGround.rect.left - int(10)
man.x += man.vel
man.right = True
man.left = False
else:
man.right = False
man.left = False
man.walkCount = 0
if not(man.isJump):
if keys[pygame.K_SPACE]:
man.isJump = True
man.right = False
man.left = False
man.walkCount = 0
else:
if man.jumpCount >= -10:
neg = 1
if man.jumpCount < 0:
neg = -1
man.y -= (man.jumpCount ** 2) * 0.5 * neg
man.jumpCount -= 1
else:
man.isJump = False
man.jumpCount = 10
# redrawGameWindow()
for zombie in all_zombies:
zombie.move_towards_player(Player)
all_zombie.update()
win.blit(BackGround.image, BackGround.rect)
man.draw(win)
pygame.display.flip()
all_zombies.draw(screen)
​
pygame.quit()
I can't run code but I see two problems
1 - move_towards_player has to be inside class ZombieEnemy
# --- classes ---
class ZombieEnemy(pygame.sprite.Sprite):
def __init__(self, x=300, y=360):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('images/zombie.png')
self.rect = self.image.get_rect()
self.rect.center = (x, y)
def move_towards_player(self, player):
# Find direction vector (dx, dy) between enemy and player.
dx, dy = player.rect.x - self.rect.x, player.rect.y - self.rect.y
dist = math.hypot (dx, dy)
dx, dy = dx / dist, dy / dist # Normalize
# Move along this normalized vector towards the player
self.rect.x += dx * self.speed
self.rect.y += dy * self.speed
# --- other ---
all_zombies = pygame.sprite.Group()
2 - you have to use it in main loop
for zombie in all_zombies:
zombie.move_towards_player(player)
in main loop
while running:
# --- events ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# If keystroke is pressed check right, left.
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
#playerX_change = -2.0
BackGround.rect.left = BackGround.rect.left + 2.5
if event.key == pygame.K_RIGHT:
#playerX_change = 2.0
BackGround.rect.left = BackGround.rect.left - 2.5
# if event.type == pygame.KEYUP:
# if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
# BackGround.rect.left = 0
# --- updates/moves ---
playerX += playerX_change
for zombie in all_zombies:
zombie.move_towards_player(player)
all_zombies.update()
# --- draws ---
screen.blit(BackGround.image, BackGround.rect)
player(playerX,playerY)
all_zombies.draw(screen)
pygame.display.flip()
But here I see other problem - your function expects player as class instance with self.rect inside (similar to ZombieEnemy) but you keep player as separated variables playerImg, playerX, playerY, playerX_change
So you have to create class Player or you have to use playerx, playery in move_towards_player instead of player.rect.x, player.rect.y

python error 'global name 'player' is not defined'

ive been learning python on my own for the past cople months and ive started making games about a weak ago (with pygame) and i have absolutly no idea what i did wrong
this is my code (btw im making pong):
import pygame
pygame.init()
display_width = 800
display_height = 600
black = (0, 0, 0)
white = (255, 255, 255)
gameDisplay = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption('pong')
clock = pygame.time.Clock()
FPS = 60
class Player():
def __init__(self):
self.padWid = 8
self.padHei = 64
self.x = display_width - 16
self.y = (display_height/2) - (self.padHei/2)
self.speed = 3
self.score = 0
self.scoreFont = pygame.font.Font('freesansbold.ttf', 40)
def scoring(self):
self.text = self.scoreFont.render(str(self.score),True,white)
gameDisplay.blit(self.text, [(display_width * 0.75),30])
def movement(self):
key = pygame.key.get_pressed()
if key[pygame.K_UP]:
self.y -= self.speed
elif key[pygame.K_DOWN]:
self.y += self.speed
if self.y <= 0:
self.y = 0
elif self.y >= display_height - self.padHei:
self.y = display_height - self.padHei
def draw(self):
pygame.draw.rect(gameDisplay, white, [self.x, self.y, self.padWid, self.padHei])
class Enemy():
def __init__(self):
self.padWid = 8
self.padHei = 64
self.x = 16
self.y = (display_height/2) - (self.padHei/2)
self.speed = 3
self.score = 0
self.scoreFont = pygame.font.Font('freesansbold.ttf', 40)
def scoring(self):
self.text = self.scoreFont.render(str(self.score),True,white)
gameDisplay.blit(self.text, [(display_width * 0.23),30])
def movement(self):
key = pygame.key.get_pressed()
if key[pygame.K_w]:
self.y -= self.speed
elif key[pygame.K_s]:
self.y += self.speed
if self.y <= 0:
self.y = 0
elif self.y >= display_height - self.padHei:
self.y = display_height - self.padHei
def draw(self):
pygame.draw.rect(gameDisplay, white, [self.x, self.y, self.padWid, self.padHei])
class Ball():
def __init__(self):
self.x = display_width/2
self.y = display_height/2
self.radius = 4
self.x_speed = -3
self.y_speed = 3
def movement(self):
self.x += self.x_speed
self.y += self.y_speed
if self.y <= self.radius or self.y >= display_height - self.radius:
self.y *= -1
if self.x + self.radius >= display_width:
self.__init__()
enemy.score += 1
elif self.x - self.radius <= 0:
self.__init__()
player.score += 1
for n in range(-self.radius, [player.padHei + self.radius]):
if self.y == player.y + n:
if self.x + self.radius >= player.x:
self.x_speed *= -1
break
n += 1
for n in range(-self.radius, [enemy.padHei + self.radius]):
if self.y == player.y + n:
if self.x - self.radius <= enemy.x + enemy.w:
self.x_speed *= -1
break
n += 1
def draw(self):
pygame.draw.circle(gameDisplay, white, [self.x, self.y], self.radius)
def game_loop():
running = True
player = Player()
enemy = Enemy()
ball = Ball()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
gameDisplay.fill(black)
player.movement()
enemy.movement()
ball.movement()
player.draw()
enemy.draw()
ball.draw()
player.scoring()
enemy.scoring()
pygame.display.update()
game_loop()
I always get the following error:
Traceback (most recent call last):
File "C:\programs\python pong\pong.py", line 159, in <module>
game_loop()
File "C:\programs\python pong\pong.py", line 148, in game_loop
ball.movement()
File "C:\programs\python pong\pong.py", line 112, in movement
for n in range(-self.radius, [player.padHei + self.radius]):
NameError: global name 'player' is not defined
You create playerin the function game_loop(), but this variable is local, so you are not able to see it outside that function.
Pass the player as an argument in the ball.movement() function.
In this way:
def movement(self, player):
self.x += self.x_speed
self.y += self.y_speed
...
...
ball.movement(player)

Categories

Resources