So I have a functioning shooting mechanic in python pygame for a top down shooter, where I am using the mouse position to aim the bullets by working out the angles, however when I do this, the bullets are shooting slightly off where the mouse position is. for instance: the mouse would be where the red arrow is drawn and the bullets will be shooting by a small amount in the wrong direction Any help would be appreciated code below:
main.py:
#-------------Imports-------------#
import pygame,sys
#import globals
from background import*
from player import*
#-------------Constants-------------#
WIDTH,HEIGHT = 500,500
WINDOW = pygame.display.set_mode((WIDTH,HEIGHT))
CLOCK = pygame.time.Clock()
BLACK = (0, 0, 0)
#-------------Instances-------------#
bg = Background()
player = Player()
#-------------Functions-------------#
def draw():
WINDOW.fill(BLACK)
bg.update(WINDOW)
player.update(WINDOW)
pygame.display.update()
#-------------Main Game Loop-------------#
def main():
#globals.intialise()
while 1:
CLOCK.tick(1)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
draw()
#globals.game_ticks += 1
if __name__ == "__main__":
main()
player.py
#-------------Imports-------------#
import pygame,math
#import globals
#-------------Constants-------------#
WIDTH,HEIGHT = 500,500
PLAYER_COLOUR = (255, 212, 112)
BLACK = (0,0,0)
PI = 3.14159265359
#-------------Classes-------------#
class Bullet:
def __init__(self,origin,angle):
self.speed = 20
self.x_speed,self.y_speed = self.speed*math.cos(math.radians(angle)),self.speed*math.sin(math.radians(angle))
self.rect = pygame.Rect(origin[0],origin[1],5,5)
def __del__(self):
pass
def update(self,window):
# move bullet
self.rect.x += self.x_speed
self.rect.y += self.y_speed
# draw bullet
pygame.draw.rect(window,BLACK,self.rect)
# check if bullet is out of the screen
if self.rect.x > WIDTH or self.rect.x < 0:
return -1
elif self.rect.y > HEIGHT or self.rect.y < 0:
return -1
class Player:
def __init__(self):
self.sprite = pygame.transform.scale(pygame.image.load("sprites/temp_player.png"),(50,50))
self.rect = pygame.Rect(250,250,50,50)
self.center = (self.rect.x,self.rect.y)
self.bullets = []
self.fire_rate = 12
def shoot(self,angle,window):
# update all bullets and delete if bullet is out of screen
for bullet in self.bullets:
if bullet.update(window) == -1:
self.bullets.remove(bullet)
del bullet
# instantiate bullet if mouse button pressed
#if pygame.mouse.get_pressed()[0] and globals.game_ticks % self.fire_rate == 0:
if pygame.mouse.get_pressed()[0]:
self.bullets.append(Bullet(self.rect.center,-angle))
def update(self,window):
mx,my = pygame.mouse.get_pos()
# find distance between mouse position and player position
diff_x,diff_y = mx-self.rect.x,my-self.rect.y
# word out angle between mouse and player
angle_rad = math.atan2(diff_y,diff_x)
angle = -360*angle_rad/(2*PI)
# adjust angle according to where we want to rotate the player
# when angle is bottom left
if abs(angle) > 90 and angle < 0:
a = 270-abs(angle)
# when angle is top left
elif abs(angle) > 90:
a = angle-90
# when angle is to the right
else:
a = angle - 90
# create new sprite that is rotated
rotated_image = pygame.transform.rotate(self.sprite,a)
# replace current rectangle with rotated sprite
self.rect = rotated_image.get_rect(center = self.center)
self.shoot(angle,window)
# add image to the screen
#window.blit(pygame.transform.rotate(self.sprite,a),self.rect)
background.py:
#-------------Imports-------------#
import pygame,random,ast,time,globals
#-------------Constants-------------#
WIDTH,HEIGHT = 500,500
TILE_DIMENSION = 9
TILE_SIZE = int(round(WIDTH/TILE_DIMENSION,0))
TO_EDGE = int((TILE_DIMENSION+1)/2)
#-------------Classes-------------#
class Background:
def __init__(self):
self.tiles = self.generate_screen()
self.centre = [2,2]
self.right = 0
self.up = 0
self.speed = 5
def generate_screen(self):
# generate original chunk of tiles
tiles = [[random.randint(100,200) for i in range(TILE_DIMENSION)] for j in range(TILE_DIMENSION)]
# eventually use image instead of random RGB value
return tiles
def movement(self,tile_rects):
keys = pygame.key.get_pressed()
if keys[pygame.K_a] or keys[pygame.K_LEFT]:
# if player is on tile to the left of centre
if (self.right - self.speed) < -TILE_SIZE:
# reset movement and adjust centre
self.right = 0
self.centre[0] -= 1
else:
# add to movement if not on next tile
self.right -= self.speed
# move all rectangles in background to simulate player moving
for i in range(len(tile_rects)):
for j in range(len(tile_rects[0])):
tile_rects[i][j].x += self.speed
if keys[pygame.K_d] or keys[pygame.K_RIGHT]:
# if player is on tile to the right of centre
if (self.right + self.speed) > TILE_SIZE:
# reset movement and adjust centre
self.right = 0
self.centre[0] += 1
else:
# add to movement if not on next tile
self.right += self.speed
# move all rectangles in background to simulate player moving
for i in range(len(tile_rects)):
for j in range(len(tile_rects[0])):
tile_rects[i][j].x -= self.speed
if keys[pygame.K_w] or keys[pygame.K_UP]:
# if player is on tile above the centre
if (self.up + self.speed) > TILE_SIZE:
# reset movement and adjust centre
self.up = 0
self.centre[1] -= 1
else:
# add to movement if not on next tile
self.up += self.speed
# move all rectangles in background to simulate player moving
for i in range(len(tile_rects)):
for j in range(len(tile_rects[0])):
tile_rects[i][j].y += self.speed
if keys[pygame.K_s] or keys[pygame.K_DOWN]:
# if player is on tile below the centre
if (self.up - self.speed) < -TILE_SIZE:
# reset movement and adjust centre
self.up = 0
self.centre[1] += 1
else:
# add to movement if not on next tile
self.up -= self.speed
# move all rectangles in background to simulate player moving
for i in range(len(tile_rects)):
for j in range(len(tile_rects[0])):
tile_rects[i][j].y -= self.speed
return tile_rects
def update(self,window):
# rendering in brand new map chunks
# if part of the chunk trying to be rendered in is non-existant in the 2D map array to the left
if self.centre[0]-TO_EDGE < 0:
# check how many tiles it is offset by
for i in range(0-(self.centre[0]-TO_EDGE)):
# add new column of values at the beginning of the 2D array
for i in range(len(self.tiles)):
self.tiles[i].insert(0,random.randint(120,230))
# due to whole array being shifted to the right, adjust the centre accordingly
self.centre[0] += 1
# if part of the chunk trying to be rendered is non-existant in the 2D map array to the right
if self.centre[0]+TO_EDGE >= len(self.tiles[0]):
# check how many tiles it is offset by
for i in range((self.centre[0]+TO_EDGE)-(len(self.tiles[0])-1)):
# add a new column of values at the end of the 2D array
for i in range(len(self.tiles)):
self.tiles[i].append(random.randint(120,230))
# if part of the chunk trying to be rendered in is non-existant in the 2D array at the top
if self.centre[1]-TO_EDGE < 0:
# check how many tiles it is offset by
for i in range(0-(self.centre[1]-TO_EDGE)):
# add a new row at the top of the 2D array
self.tiles.insert(0,[random.randint(120,230) for i in range(len(self.tiles[0]))])
# due to whole array shifting downwards, adjust the centre accordingly
self.centre[1] += 1
# if part of the chunk trying to be rendered in is non-existant in the 2D array at the bottom
if self.centre[1]+TO_EDGE >= len(self.tiles):
# check how many tiles it is offset by
for i in range((self.centre[1]+TO_EDGE)-(len(self.tiles)-1)):
# add a new row at the bottom of the 2D array
self.tiles.append([random.randint(120,230) for i in range(len(self.tiles[0]))])
# determining which tiles should be rendered in according to the centre(where player would be)
t = []
for i in range(TILE_DIMENSION+2):
t.append([])
for j in range(TILE_DIMENSION+2):
try:
t[i].append(self.tiles[i+(self.centre[1]-TO_EDGE)][j+(self.centre[0]-TO_EDGE)])
except:
pass
# create a rectangle for each tile that is rendered in
tile_rects = [[pygame.Rect((i-1)*TILE_SIZE-self.right,(j-1)*TILE_SIZE+self.up,TILE_SIZE,TILE_SIZE) for i in range(TILE_DIMENSION+2)] for j in range(TILE_DIMENSION+2)]
tile_rects = self.movement(tile_rects)
# draw all rectangles
for i in range(TILE_DIMENSION+2):
for j in range(TILE_DIMENSION+2):
try:
pygame.draw.rect(window,(0,int(t[i][j]),0),tile_rects[i][j])
except:
pass
the background script doesnt affect anything, its just there as a background to make it easier to see, and you may have to make your own temp_player.png image to make it compatible