Reputation: 3
I am currently creating a top-down shooter in Pygame and currently need my enemies to shoot bullets at my player. The problem is that when I move my character the position where the bullets are shooting from moves as well when they are meant to be shot from the enemies at all times. I have watched many different tutorials but non of which have proven helpful. Hoping someone can help.
import pygame
import sys
import math
import random
import time
import multiprocessing
from pygame import mixer
pygame.init()
displayWidth = 100
displayHeight = 200
enemytime = time.time() + 10
enemyshoottime = time.time() + 1
#Enemy
class Enemy1(object):
def __init__(self, x, y):
self.x = x
self.y = y
self.hit_box = (self.x-10, self.y -10, 70, 70)
self.animation_images = [pygame.image.load("Enemy1_animation_0.png"), pygame.image.load("Enemy1_animation_1.png"),
pygame.image.load("Enemy1_animation_2.png"), pygame.image.load("Enemy1_animation_3.png")]
self.animation_count = 0
self.reset_offset = 0
self.offset_x = random.randrange(-150, 150)
self.offset_y = random.randrange(-150, 150)
self.health = 4
def main(self, display):
if self.animation_count + 1 == 16:
self.animation_count = 0
self.animation_count += 1
if self.reset_offset == 0:
self.offset_x = random.randrange(-150, 150)
self.offset_y = random.randrange(-150, 150)
self.reset_offset = random.randrange(120, 150)
else:
self.reset_offset -= 1
if player.x + self.offset_x > self.x-display_scroll[0]:
self.x += 1
elif player.x + self.offset_x < self.x-display_scroll[0]:
self.x -= 1
if player.y + self.offset_y > self.y-display_scroll[1]:
self.y += 1
elif player.y + self.offset_y < self.y-display_scroll[1]:
self.y -= 1
display.blit(pygame.transform.scale(self.animation_images[self.animation_count//4], (50, 50)), (self.x-display_scroll[0], self.y-display_scroll[1]))
self.hit_box = (self.x-display_scroll[0]-10, self.y-display_scroll[1]-10, 70, 70)
pygame.draw.rect(display, (255, 0, 0), self.hit_box, 2)
#Enemy Bullet
class EnemyBullet:
def __init__(self, x, y, playerx, playery):
self.x = x
self.y = y
self.playerx = 300
self.playery = 300
self.speed = 7
self.angle = math.atan2(y-playerx, x-playery)
self.x_vel = math.cos(self.angle) * self.speed
self.y_vel = math.sin(self.angle) * self.speed
def main(self, display):
self.x -= int(self.x_vel)
self.y -= int(self.y_vel)
EnemyBulletRect = pygame.draw.circle(display, (255,0,0), (self.x, self.y), 5)
#list's
enemies = [ Enemy2(800, -200), Enemy3(-300, 500), Enemy4(1000, 400)]
enemy = Enemy1(600, 400)
enemy_bullets = []
sounds = ['explosion1.mp3', 'explosion2.mp3', 'explosion3.mp3']
player = Player(400, 300, 32, 32)
display_scroll = [0,0]
player_bullets = []
while True:
display.fill((0, 0, 0))
display.blit(displayImage, (0, 0))
#display.blit(ImageBackground, (0, 0))
display.blit(Earth, (700, 100))
show_score(textX, textY)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
pygame.quit()
#Enemy shoots
if time.time() >= enemyshoottime:
enemy_bullets.append(EnemyBullet(enemy.x, enemy.y, playerx, playery))
from playsound import playsound
playsound('lazer.mp3', block=False)
enemyshoottime = time.time() + 1
for bullets in enemy_bullets:
bullets.main(display)
#spawn enemies
if time.time() >= enemytime:
# Time to spawn a new enemy.
enemies.append( Enemy3( 100, 500 ) )
enemies.append( Enemy3( 600, 400 ) )
# Reset the alarm.
enemytime = time.time() + 10
Upvotes: 0
Views: 79
Reputation: 211220
The motion vector of the bullet can be calculated from the normalized direction vector (Unit vector) multiplied by the velocity. The unit vector is obtained by dividing the components of the vector by the Euclidean length of the vector.
Do not round the velocity before adding it to the position, but round the position when using it to draw the bullet. If you round the component vectors before adding them or round the position attributes themselves, there will be an inaccuracy that accumulates over time. Round only the values that are used in pygame.draw.circle
Use round
instead of int
.
class EnemyBullet:
def __init__(self, x, y, playerx, playery):
self.x = x
self.y = y
self.speed = 7
dx = playerx - x
dy = playery - y
d = math.sqrt(dx*dx, dy*dy) # or d = math.hypot(dx, dy)
self.x_vel = self.speed * dx / d
self.y_vel = self.speed * dy / d
def main(self, display):
self.x += self.x_vel
self.y += self.y_vel
EnemyBulletRect = pygame.draw.circle(
display, (255,0,0), (round(self.x), round(self.y)), 5)
Upvotes: 0