Im thinking about making a 2d shooting game in pygame and i want to make my player(Player_1) point to the mouse direction.I looked for a solution for hours and tried all solution i could find but none had worked so can you pls help me ?
Here's my code:
import pygame, sys, os
from pygame.locals import *
os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.init()
#Exit settings
def quit():
pygame.quit()
sys.quit()
def events():
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
quit()
#IDS
CLOCK=pygame.time.Clock()
FPS=120
DS=pygame.display.set_mode((0,0), pygame.FULLSCREEN)
pygame.display.set_caption("Shooting simulator")
W,H=DS.get_size()
P_X=W/2-50
P_Y=H/2-50
#Colors
Red=pygame.Color("#FF0000")
Blue=pygame.Color("#0000FF")
Green=pygame.Color("#00FF00")
Black=pygame.Color("#000000")
White=pygame.Color("#FFFFFF")
#IGT(in game things)
Player_1=pygame.image.load("Img/Player_1.png").convert()
def game_loop():
while True:
events()
DS.fill(White)
DS.blit(Player_1,(P_X,P_Y))
pygame.display.flip()
game_loop()
This is my player(Player_1)
I will really appreciate all help.
You have to compute the angle of the vector from the player to the mouse. get the mouse position by pygame.mouse.get_pos() and the rectangle (pygame.Rect) around the player:
mx, my = pygame.mouse.get_pos()
player_rect = Player_1.get_rect(topleft=(P_X,P_Y))
Calculate the vector from the player to the mouse and compute the angle of vector by math.atan2. The y-axis needs to be reversed (-dy) as the y-axis is generally pointing up, but in the PyGame coordinate system the y-axis is pointing down.
dx, dy = mx - player_rect.centerx, player_rect.centery - my
angle = math.degrees(math.atan2(-dy, dx)) - correction_angle
In addition, a correction angle must be deducted (- correction_angle). The correction angle depends on the Sprite. If the Sprite
is looking to the right, the correction angle is 0: correction_angle = 0
is looking up, the correction angle is 90: correction_angle = 90
is looking to the left, the correction angle is 180: correction_angle = 180
is looking down, the correction angle is 270: correction_angle = 270
Rotate the player with pygame.transform.rotate() by the angle around its center:
(See also How do I rotate an image around its center using Pygame?)
rot_image = pygame.transform.rotate(Player_1, angle)
rot_image_rect = rot_image.get_rect(center=player_rect.center)
Minimal example: repl.it/#Rabbid76/PyGame-RotateWithMouse
import math
import pygame
pygame.init()
window = pygame.display.set_mode((300, 300))
player = pygame.image.load("player.png").convert_alpha()
# 0 - image is looking to the right
# 90 - image is looking up
# 180 - image is looking to the left
# 270 - image is looking down
correction_angle = 90
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
player_pos = window.get_rect().center
player_rect = player.get_rect(center = player_pos)
mx, my = pygame.mouse.get_pos()
dx, dy = mx - player_rect.centerx, my - player_rect.centery
angle = math.degrees(math.atan2(-dy, dx)) - correction_angle
rot_image = pygame.transform.rotate(player, angle)
rot_image_rect = rot_image.get_rect(center = player_rect.center)
window.fill((255, 255, 255))
window.blit(rot_image, rot_image_rect.topleft)
pygame.display.flip()
pygame.quit()
exit()
Here is a simple block of code that you can use to help.
It uses some trigonometry and assumes the following are defined before:
elsie is the player
position = pygame.mouse.get_pos()
angle = math.atan2(position[1] - (elsiepos[1] + 32), position[0] - (elsiepos[0] + 26))
elsierot = pygame.transform.rotate(elsie, 360 - angle * 57.29)
elsiepos1 = (elsiepos[0] - elsierot.get_rect().width / 2, elsiepos[1] - elsierot.get_rect().height / 2)
screen.blit(elsierot, elsiepos1)
This block should come directly after you detect keys, and should come before drawing the player, in this case, elsie.
Related
I am quite new to Pygame 2 (actually python in general), and I wanted to make a little game for school. I used the code from this, but I can't get it to move towards the cursor when I press SPACE. I don't want it to move in the x/y axis...
This is the code btw
import sys, pygame, math
from pygame.locals import *
spaceship = ('spaceship.png')
mouse_c = ('cursor.png')
backg = ('background.jpg')
lazer = pygame.mixer.Sound("pew.WAV")
pygame.init()
display_width = 1280
display_height = 720
screen = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("Space Survival")
bk = pygame.image.load(backg).convert_alpha()
space_ship = pygame.image.load(spaceship).convert_alpha()
mousec = pygame.image.load(mouse_c).convert_alpha()
clock = pygame.time.Clock()
pygame.mouse.set_visible(False)
Ammo = 20
Fuel = 200
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONDOWN and event.button == 1 and Ammo <= 20:
print("Pew")
pygame.mixer.Sound.play(lazer)
elif event.type == MOUSEBUTTONDOWN and event.button == 3 and Fuel <= 200:
print("Boost")
screen.blit(bk, (0, 0))
pos = pygame.mouse.get_pos()
angle = 270-math.atan2(pos[1]-(display_height/2),pos[0]-(display_width/2))*180/math.pi
rotimage = pygame.transform.rotate(space_ship,angle)
rect = rotimage.get_rect(center=((display_width/2),(display_height/2)))
screen.blit(rotimage,rect) #I need space_ship to rotate towards my cursor
screen.blit(mousec, (pos))
pygame.display.update()
clock.tick(60) #FPS
Running Pygame 2.0 on Python 3.8.
Any tips will be much appreciated :)
Write a function that "follows2 an target:
def FollowMe(pops, fpos, step):
# [...]
I recommend to compute the distance between the spaceship and the mouse and the unit direction vector from (fpos) to (pops).
The distance can be get by computing the Euclidean distance. Pygame provides distance_to() for that. Th unit direction vector can be computed by dividing the direction vector by the distance or by normalizing (normalize()) the direction vector:
target_vector = pygame.math.Vector2(pops)
follower_vector = pygame.math.Vector2(fpos)
distance = follower_vector.distance_to(target_vector)
direction_vector = target_vector - follower_vector
if distance > 0:
direction_vector /= distance
Now you can define an exact step_distance and move to follower in direction of the sprite:
if distance > 0:
new_follower_vector = follower_vector + direction_vector * step_distance.
Define a step and ensure that the step distance is not grater than the step:
step_distance = min(distance, step)
The maximum step distance is
max_step = distance - minimum_distance
Put it all together:
def FollowMe(pops, fpos, step):
target_vector = pygame.math.Vector2(pops)
follower_vector = pygame.math.Vector2(fpos)
new_follower_vector = pygame.math.Vector2(fpos)
distance = follower_vector.distance_to(target_vector)
if distance > 0:
direction_vector = (target_vector - follower_vector) / distance
step_distance = min(distance, step)
new_follower_vector = follower_vector + direction_vector * step_distance
return (new_follower_vector.x, new_follower_vector.y)
See also How to make smooth movement in pygame.
Use the function to move the space ship in the direction of the mouse and pygame.key.get_pressed() to move the ship when SPACE is pressed. pygame.key.get_pressed() returns a list with the state of each key. If a key is held down, the state for the key is True, otherwise False. Use pygame.key.get_pressed() to evaluate the current state of a button and get continuous movement:
ship_pos = display_width // 2, display_height // 2
while True:
# [...]
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
ship_pos = FollowMe(pos, ship_pos, 3)
angle = 270-math.atan2(pos[1]-ship_pos[1],pos[0]-ship_pos[0])*180/math.pi
rotimage = pygame.transform.rotate(space_ship,angle)
rect = rotimage.get_rect(center=ship_pos)
For the rotation of an image see How to rotate an image(player) to the mouse direction? and How do I rotate an image around its center using PyGame?
See also Rotate towards target or mouse respectivley Move towards target and the answer to the question How do I rotate a sprite towards the mouse and move it?
Minimal example without any usage of external resources (sound and images):
import sys, pygame, math
from pygame.locals import *
pygame.init()
def FollowMe(pops, fpos, step):
target_vector = pygame.math.Vector2(pops)
follower_vector = pygame.math.Vector2(fpos)
new_follower_vector = pygame.math.Vector2(fpos)
distance = follower_vector.distance_to(target_vector)
if distance > 0:
direction_vector = (target_vector - follower_vector) / distance
step_distance = min(distance, step)
new_follower_vector = follower_vector + direction_vector * step_distance
return (new_follower_vector.x, new_follower_vector.y)
display_width = 1280
display_height = 720
screen = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("Space Survival")
clock = pygame.time.Clock()
bk = pygame.Surface(screen.get_size())
space_ship = pygame.Surface((20, 50), pygame.SRCALPHA)
space_ship.fill((0, 255, 0))
mousec = pygame.Surface((20, 20), pygame.SRCALPHA)
mousec.fill((255, 0, 0))
ship_pos = display_width // 2, display_height // 2
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
pos = pygame.mouse.get_pos()
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
ship_pos = FollowMe(pos, ship_pos, 3)
angle = 270-math.atan2(pos[1]-ship_pos[1],pos[0]-ship_pos[0])*180/math.pi
rotimage = pygame.transform.rotate(space_ship,angle)
rect = rotimage.get_rect(center=ship_pos)
screen.blit(bk, (0, 0))
screen.blit(rotimage,rect)
screen.blit(mousec, pos)
pygame.display.update()
I know that to get a pixel color in Pygame I use get_at.
But I need to get a pixel that is outside my screen, ie, I have an image already blitted with just a portion visible.
For example, a 1000x1000 image inside a 500,500 screen will only have 50% visible, the rest will be "off" the screen. So I need to access the portion off the screen.
But if I reference get_at with a coordinate greater or less then the screen dimensions, Pygame stops with an error:
IndexError: pixel index out of range
import pygame
W = 1600
H = 600
pygame.init()
screen = pygame.display.set_mode([W, H])
image = pygame.image.load('huge_background.png').convert_alpha()
screen.blit(image, [-5000, -420])
pygame.display.update()
screen.get_at([100, -5]) # generates "IndexError: pixel index out of range"
How can I get the background image pixel color outside the screen dimensions?
Here is the currently visible pygame screen (1600 x 600). The 3 lines (in magenta) are the collision "detectors":
And here is the background that will scroll (8000 x 8000):
So here is an idea of the scenario:
So, the collision detector lines might exceed the pygame screen limits but need to "read" the outside pixels to detect the collision.
Here's a stand-alone example that tracks the position of the view/camera on a larger background.
import pygame
W = 600
H = 400
pygame.init()
# generate repeated KEYDOWN events when a key is held
pygame.key.set_repeat(500, 50)
screen = pygame.display.set_mode([W, H])
# image = pygame.image.load('huge_bkgnd.png').convert_alpha()
#create a large bkgnd image
bkgnd = pygame.Surface((W*10, H*10))
# draw a rainbow on the bkgnd surface
colours = ["red", "orange", "yellow", "green", "lightblue1", "blue", "purple"]
bar_width = bkgnd.get_width() // (10 * len(colours))
for x in range(0, bkgnd.get_width() // bar_width):
rect = [x*bar_width, 0, bar_width, bkgnd.get_height()]
bkgnd.fill(pygame.Color(colours[x % len(colours)]), rect)
position = [0, 0]
clock = pygame.time.Clock() #for limiting FPS
finished = False
while not finished:
for event in pygame.event.get():
if event.type == pygame.QUIT:
finished = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
position[0] -= 100
if event.key == pygame.K_RIGHT:
position[0] += 100
if event.key == pygame.K_UP:
position[1] -= 100
if event.key == pygame.K_DOWN:
position[1] += 100
# for all key movement clamp position to size of background
position[0] = max(0, min(position[0], bkgnd.get_width() - W))
position[1] = max(0, min(position[1], bkgnd.get_height() - H))
try:
x = position[0] + W*2 # just look at what's to the right
y = position[1]
print(f"At {position}: Heading for ({x},{y}) {bkgnd.get_at((x, y))}")
except IndexError:
print(f"Heading for the edge! {bkgnd.get_width() - position[0]} to go!")
# copy bkgnd to screen
view_rect = (*position, W, H)
screen.blit(bkgnd.subsurface(view_rect), (0,0))
# update the screen
pygame.display.update()
clock.tick(60) # limit FPS
pygame.quit()
Ignore the hacky-bit at the start to generate a rainbow background image so horizontal movement is obvious.
The program moves the position based on arrow key presses. Using pygame.key.set_repeat() it allows for the arrow keys to be held down.
There's a little bit of house-keeping in the event loop to ensure the view can't move outside the boundary of the background. Then it prints the colour of a pixel in the distance.
After the events are processed, a section of the background is drawn to the screen, based on the current position.
Let me know if you'd like any clarification.
I'm searching for some help with pygame. I'm developing simple game in Python to learn Pygame. I want to make spaceship which we can rotate and we can shooting with laser line.
I have done controlling by arrow keys, we can also rotating spaceship with mouse position, but I've got a problem with shooting. I want to make a line with infinity length from spaceship position to mouse direction. How I can do that? Here is my code:
def draw_objects(self):
SCREEN.fill(BLACK)
self.target = pygame.mouse.get_pos()
self.x = self.player.position[0] #player x position
self.y = self.player.position[1] #player y position
self.mx = self.target[0] #mouse x position
self.my = self.target[1] #mouse y position
self.slope=float(float(self.y-self.my)/float(self.x-self.mx+0.1)) #slope
self.x_new = DISPLAY_WIDTH #ray length
self.y_new = self.y + self.slope * (self.x_new - self.x)
self.player.draw()
self.draw_columns()
for agent in self.all_agents:
agent.draw()
agent.draw_vectors()
if self.player.shoot == True:
pygame.draw.line(SCREEN, GREEN, self.player.position,(self.x_new, self.y_new), 2)
pygame.display.update()
It's not working properly, because it's work only to the right of spaceship. In other cases it draws a line in reflection to cursor.
I will be grateful for your help.
slope doesn't keep direction.
You have to get sign of player_x - mouse_x + 0.1 and use with x_new
dx = player_x - mouse_x + 0.1
reversed_sign_x = 1 if dx < 0 else -1
x_new = reversed_sign_x * DISPLAY_WIDTH
Full working example:
move mouse to move line,
click left button to set player new position.
.
import pygame
# --- constants ---
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
DISPLAY_WIDTH = 800
DISPLAY_HEIGHT = 600
# --- functions ---
def calculate(player_x, player_y, mouse_x, mouse_y):
dx = player_x - mouse_x + 0.1
dy = player_y - mouse_y
reversed_sign_x = 1 if dx < 0 else -1
#reversed_sign_y = 1 if dy < 0 else -1
slope = dy/dx
x_new = reversed_sign_x * DISPLAY_WIDTH
y_new = player_y + slope * (x_new - player_x)
return x_new, y_new
# --- main ---
# - init -
pygame.init()
SCREEN = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
# - objects -
player_x = DISPLAY_WIDTH // 2
player_y = DISPLAY_HEIGHT // 2
mouse_x = player_x
mouse_y = player_y
x_new, y_new = calculate(player_x, player_y, mouse_x, mouse_y)
# - mainloop -
clock = pygame.time.Clock()
running = True
while running:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
player_x, player_y = event.pos
elif event.type == pygame.MOUSEMOTION:
x_new, y_new = calculate(player_x, player_y, event.pos[0], event.pos[1])
# - updates -
# empty
# - draws -
SCREEN.fill(BLACK)
pygame.draw.line(SCREEN, GREEN, (player_x, player_y), (x_new, y_new), 2)
pygame.display.flip()
# - FPS -
clock.tick(25)
# - end -
pygame.quit()
furas is right, you have to check whether the mouse is on the left or right side of the player and negate the DISPLAY_WIDTH if it's on the left. I came to a similar solution:
def target_coords(position):
x, y = position # Unpack player position into x, y.
mx, my = pygame.mouse.get_pos() # Unpack mouse pos into mx, my.
slope = (y-my) / (x-mx+0.1)
# This is a conditional expression, similar to `if condition: ... `else: ... `.
x_new = DISPLAY_WIDTH if x < mx else -DISPLAY_WIDTH
y_new = y + slope * (x_new - x)
return x_new, y_new
Note that this function only computes the target coordinates and returns them (functions should preferably do only one thing). Draw the line and everything else in another function.
There's also an alternative solution: You could use pygame vectors and first calculate the vector to the target, normalize it and scale it by the desired length (the DISPLAY_WIDTH).
import pygame
from pygame.math import Vector2
pygame.init()
DISPLAY_WIDTH = 640
GREEN = pygame.Color('aquamarine1')
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
position = Vector2(300, 200) # A pygame.math.Vector2 as the position.
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill((30, 30, 30))
pygame.draw.circle(screen, GREEN, (int(position.x), int(position.y)), 7)
# Calculate the vector to the target by subtracting pos from mouse pos.
# Normalizing it gives you a unit vector which you can scale
# by multiplying it with the DISPLAY_WIDTH.
target_vec = (pygame.mouse.get_pos()-position).normalize() * DISPLAY_WIDTH
pygame.draw.line(screen, GREEN, position, position+target_vec, 2)
pygame.display.flip()
clock.tick(30)
pygame.quit()
I am writing a simple "game" and I have three questions for you:
How can I make all the balls moving independetly?
When I drag a ball with a mouse and click on the screen, how can i make the ball stay there. I want to draw it on that specific coordinate where the mouse key was pressed. It has to stay there all the time.
If a small ball touches the large one it shoud become a large one and dissapear after 10 seconds.
I have no idea how to do this. Can you please help me.
My code:
import pygame
import sys
from pygame.locals import *
import random
pygame.init()
width = 800
height = 600
fps = 25
clock = pygame.time.Clock()
black = (0, 0, 0)
white = (255, 255, 255)
display_window = pygame.display.set_mode((width, height))
pygame.display.set_caption('Bouncy')
game_over = False
r = random.randint(0, 255)
g = random.randint(0, 255)
b = random.randint(0, 255)
x_cor = random.randint(15, width - 15)
y_cor = random.randint(15, height - 15)
x_change = random.randint(3, 7)
y_change = random.randint(3, 7)
coordinates = []
for i in range(10):
x = random.randint(0, width)
y = random.randint(0, height)
coordinates.append([x, y])
while not game_over:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
if event.type == pygame.mouse.get_pressed():
pass
x_cor += x_change
y_cor += y_change
display_window.fill(white)
mouse_x, mouse_y = pygame.mouse.get_pos()
for coordinate in coordinates:
pygame.draw.circle(display_window, (r, g, b), (coordinate[0], coordinate[1]), 15, 0)
pygame.draw.circle(display_window, black, (mouse_x, mouse_y), 25, 0)
pygame.draw.circle(display_window, (r, g, b), (x_cor, y_cor), 15, 0)
if x_cor > (width - 15) or x_cor < 15:
x_change = x_change * -1
if y_cor > (height - 15)or y_cor < 15:
y_change = y_change * -1
clock.tick(fps)
pygame.display.update()
First and foremost, do the research required before you post here (see the help documents on the intro tour). There are many tutorials on the Internet, and many answered questions in SO (StackOverflow) that deal with moving objects. To get you started in general:
You move the balls independently by keeping a separate set of coordinates for each ball. On each iteration of the game clock, you have to reiterate the new coordinates of each ball.
To make a ball stay in one place, simply do not change its coordinates.
To change the size of a ball, draw it with a larger radius. This means that you also have to remember the radius of each ball. To give it a 10-second lifetime, keep a "lifespan" for each ball; decrement it on each tick of the game clock.
Bascially, you need a Ball object (make a class Ball); instantiate a new object for each ball you need. Write methods to change the position, size, and life span of each ball.
This question already has answers here:
Can't understand how to make character face mouse in PyGame
(2 answers)
How do I make my player rotate towards mouse position?
(1 answer)
How do I rotate an image around its center using Pygame?
(6 answers)
Closed 2 years ago.
Im New To Pygame But Kinda OK On Python, Im Creating A Zombie Shooting Game With an overhead view.
I managed to make the character move when pressing the arrow keys. But now i need to get the player to FACE the mouse/cursor without clicking the screen all the time.
Any Help?
for event in pygame.event.get():
if event.type == MOUSEMOTION:
mousex, mousey = event.pos
# build a vector between player position and mouse position
moveVector = (mousex-playerx, mousey-playery)
"""
compute the angle of moveVector from current vector that player is facing (faceVector).
you should be keeping and updating this unit vector, with each mouse motion
assume you have initial facing vector as (1,0) - facing East
"""
# compute angle as in [1]
# rotate the image to that angle and update faceVector
[1] - How to Find the Angle Between Two Vectors:
http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
Your image may lose quality when rotated at a small angle. It's discussed in Pygame documentation page: http://pygame.org/docs/ref/transform.html#pygame.transform.rotate
import math
mouseX, mouseY = pygame.mouse.get_pos()
playerX, playerY = player.get_pos()
angle = math.atan2(playerX-mouseX, playerY-mouseY)
You might have to fiddle with the order of subtraction (ie, it might be mousePosition-playerPosition) or the order of the x and y parameters to atan2 (ie, you might need to pass in the Y difference as the first parameter rather than the X) but that depends on your coordinate system.
working code :
import pygame, sys, math
from pygame.locals import *
#converte in base ai gradi le cordinate x,y
#maxXY= surface MaxXY
#gradoRot = grado di rotazione
#distXY = spostamento in x,y lungo il vettore di cordinate locali dalle cordinate x,y
#movement from one point to another
def Move(t0,t1,psx,psy,speed):
global mx
global my
speed = speed
distance = [t0 - psx, t1 - psy]
norm = math.sqrt(distance[0] ** 2 + distance[1] ** 2)
direction = [distance[0] / norm, distance[1 ] / norm]
bullet_vector = [direction[0] * speed, direction[1] * speed]
return bullet_vector
# Main Function
if __name__ == '__main__':
pygame.init()
FPS = 30 # frames per second setting
fpsClock = pygame.time.Clock()
# set up the window
DISPLAYSURF = pygame.display.set_mode((800, 600), 0, 32)
alfhaSurface = DISPLAYSURF.convert_alpha()
pygame.display.set_caption('test')
shipImg = pygame.image.load('ship.png')
shipImgcpy=shipImg.copy()
vetShip=pygame.math.Vector2(400,300)
gradi = 0
gradiRot=0
mouseX=0
mouseY=0
SHIP_W=40
SHIP_H=40
vetMouse=pygame.math.Vector2(mouseX,mouseY)
#main loop
while True:
DISPLAYSURF.fill((0,0,0))
alfhaSurface.fill((0,0,0))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
mouseX, mouseY = pygame.mouse.get_pos()
vetMouse=pygame.math.Vector2(mouseX,mouseY)
gradiRot=**math.atan2(vetShip.x-vetMouse.x, vetShip.y-vetMouse.y)**
gradiRot=**math.degrees(gradiRot)**
pygame.display.set_caption(""+str(gradi) +"="+ str(gradiRot)+" "+ str(vetMouse.angle_to(vetShip)) )
pygame.draw.line(alfhaSurface, (255,255,255), (vetShip.x+SHIP_W,vetShip.y+SHIP_H),(vetMouse.x,vetMouse.y),1)
if gradi != int(gradiRot) :
if gradiRot > gradi and gradi != gradiRot :
gradi=gradi+1
if gradiRot < gradi and gradi != gradiRot :
gradi=gradi-1
shipImgcpy=pygame.transform.rotate(shipImg.copy(),gradi)
elif int(vetMouse.distance_to(vetShip)) >0:
posNext=Move(mouseX,mouseY,vetShip.x+SHIP_W,vetShip.y+SHIP_H,1)
vetShip=pygame.math.Vector2(vetShip.x+posNext[0],vetShip.y+posNext[1])
alfhaSurface.blit(shipImgcpy, tuple(vetShip))
DISPLAYSURF.blit(alfhaSurface,(0,0))
pygame.display.update()
fpsClock.tick(FPS)
_, angle = (pg.mouse.get_pos()-self.pos).as_polar()
This line first calculates a vector to the mouse position (self.pos has to be a pygame.math.Vector2) and .as_polar() returns the polar coordinates of the vector which consist of the radial distance and the angle. Finally use the negative angle (because pygame's y-axis is flipped) to rotate the image of the sprite and recalculate the rect.
import pygame as pg
class Player(pg.sprite.Sprite):
def __init__(self, pos):
super().__init__()
self.image = pg.Surface((50, 30), pg.SRCALPHA)
pg.draw.polygon(
self.image,
pg.Color('dodgerblue1'),
((1, 1), (49, 15), (1, 29)))
self.orig_img = self.image
self.rect = self.image.get_rect(center=pos)
self.pos = pg.math.Vector2(pos)
self.vel = pg.math.Vector2(0, 0)
def update(self):
self.rotate()
self.pos += self.vel
self.rect.center = self.pos
def rotate(self):
_, angle = (pg.mouse.get_pos()-self.pos).as_polar()
self.image = pg.transform.rotozoom(self.orig_img, -angle, 1)
self.rect = self.image.get_rect(center=self.rect.center)
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
all_sprites.add(Player((300, 200)))
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
all_sprites.update()
screen.fill((30, 30, 30))
all_sprites.draw(screen)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
math.atan2 can be used as an alternative.
def rotate(self):
rel_x, rel_y = pg.mouse.get_pos() - self.pos
angle = -math.degrees(math.atan2(rel_y, rel_x))
self.image = pg.transform.rotozoom(self.orig_img, angle, 1)
self.rect = self.image.get_rect(center=self.pos)
if event.type == MOUSEBUTTONDOWN:
mouseX, mouseY = pygame.mouse.get_pos()
vetMouse=pygame.math.Vector2(mouseX,mouseY)
gradiRot=vetMouse.angle_to(vetShip)