Reputation: 13
What the title says, I have an image that I can control with W,S,A,D. But I want to make the player image that is movable rotate to face the position of my mouse. Here's the relevent code:
import pygame
import random
import time
import math
import sys
pygame.init()
#The size of the game window
display_width = 1280
display_height = 800
#Colors available
black = (0, 0, 0) #colours defined by RGB,
white = (255, 255, 255)
red = (200, 0, 0)
green = (0, 150, 0)
bright_red = (255, 0, 0)
bright_green =(0, 255, 0)
#This code opens up the Game window
gameDisplay = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption("Blockslayer")
clock = pygame.time.Clock()
pygame.mouse.set_visible(True)
#player character info
slayerImg = pygame.image.load('squareslayer.png').convert_alpha()
slayerWidth = 84
slayerHeight = 84
#mouse info
mouse_c = pygame.image.load("crosshair.png ").convert_alpha()
def crosshair(mousex,mousey):
mousex, mousey = pygame.mouse.get_pos()
small_ch = pygame.transform.scale(mouse_c, (20, 20))
gameDisplay.blit(small_ch, (mousex, mousey,))
print(mousex,mousey)
#player character
def slayer(x,y,):
#small_slayer = pygame.transform.scale(slayerImg, (120, 80,))
pos = pygame.mouse.get_pos()
angle = 360 - math.atan2(pos[1] - 84, pos[0] - 84) * 180 / math.pi
rotimage = pygame.transform.rotate((slayerImg), angle,)
rect = rotimage.get_rect(center=(x, y))
gameDisplay.blit(rotimage, rect,)
pygame.display.update()
#Game Logic
def block_game_loop():
x = (display_width * 0.45)
y = (display_height * 0.8)
pos = pygame.mouse.get_pos()
angle = 360 - math.atan2(pos[1] + x - 84, pos[0] + y - 84) * 180 / math.pi
rotimage = pygame.transform.rotate((slayerImg), angle,)
mousex, mousey = pygame.mouse.get_pos()
#def blockguy(blockguyX, blockguyY, blockguyW, blockguyH, ):
#blockguyX = random.randrange(0, 785)
#blockguyY = random.randrange (0, 600)
#blockguyW = 166
#blockguyH = 110
#blockguy_speed = 5
#Event handler
exit_game = False
while not exit_game:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
pressed = pygame.key.get_pressed()
if pressed[pygame.K_s]: y += 7
if pressed[pygame.K_w]: y -= 7
if pressed[pygame.K_a]: x -= 7
if pressed[pygame.K_d]: x += 7
gameDisplay.fill(white)
slayer(x, y,)
#Boundaries
if x > display_width:
x = 1275
if x < 0:
x = 5
if y > display_height:
y = 795
if y < 0:
y = 5
crosshair(mousex,mousey)
#blockguy(blockguyX, blockguyY, blockguyW, blockguyH, )
pygame.display.update()
clock.tick(60)
block_game_loop()
pygame.quit()
quit()
Code is pretty janked together because I don't really know wtf im doing, but here's how the thing works so far Youtube video: https://www.youtube.com/watch?v=zShWAm4pSx8&feature=youtu.be
Upvotes: 1
Views: 1658
Reputation: 1
Here Big Fish, this is my code for that problem:
import math
sprite = sprite_new("spr_plasma_blast")
targetx = 0
targety = 0
m = 0
time = 0
speed = 8
if time == 0:
m = (targety - y)/(targetx - x)
xSpeed = math.sqrt((speed*speed)/((m*m) + 1))
if targetx < x:
xSpeed = -xSpeed
x = x + xSpeed
y = y + xSpeed*m
time = time + 1
Upvotes: 0
Reputation: 20438
Take a look at this rotate
function (read the comments).
import math
import pygame
pygame.init()
gray = (30, 30, 30)
display_width, display_height = (1280, 800)
gameDisplay = pygame.display.set_mode((display_width, display_height))
clock = pygame.time.Clock()
slayerImg = pygame.Surface((104, 84), pygame.SRCALPHA)
pygame.draw.polygon(slayerImg, (0, 120, 250), [(1, 1), (103, 42), (1, 83)])
def rotate(x, y, mouse_pos, image):
# Calculate x and y distances to the mouse pos.
run, rise = (mouse_pos[0]-x, mouse_pos[1]-y)
# Pass the rise and run to atan2 (in this order)
# and convert the angle to degrees.
angle = math.degrees(math.atan2(rise, run))
# Rotate the image (use the negative angle).
rotimage = pygame.transform.rotate(image, -angle)
rect = rotimage.get_rect(center=(x, y))
return rotimage, rect
def block_game_loop():
x = display_width * 0.45
y = display_height * 0.8
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
pressed = pygame.key.get_pressed()
if pressed[pygame.K_s]: y += 7
if pressed[pygame.K_w]: y -= 7
if pressed[pygame.K_a]: x -= 7
if pressed[pygame.K_d]: x += 7
mousex, mousey = pygame.mouse.get_pos()
# Boundaries
if x > display_width:
x = 1275
if x < 0:
x = 5
if y > display_height:
y = 795
if y < 0:
y = 5
gameDisplay.fill(gray)
rotimage, rect = rotate(x, y, (mousex, mousey), slayerImg)
gameDisplay.blit(rotimage, rect)
pygame.display.update()
clock.tick(60)
block_game_loop()
pygame.quit()
Addendum: Here's an example that shows you how you can shoot rotated bullets. You need some basic trigonometry knowledge, because you need to calculate the x- and y-velocity with math.cos
and math.sin
. That will give you a unit vector (with length 1) that you need to scale to the desired speed. Now you need to put the velocity
list together with a rect, an extra position list and the rotated image into a list that represents a bullet object. To update the rect position you first have to add the velocity to the pos and then assign the pos to the rect center (you have to do it that way, because rects can only have ints as the x and y position).
I recommend to use pygame.math.Vector2
s and pygame sprites and sprite groups instead of lists as you can see in the linked answer, because that's a lot nicer to read. You still need to add code to remove bullets, which would also be simpler to implement with sprites and sprite groups.
import math
import pygame as pg
from pygame.math import Vector2
pg.init()
screen = pg.display.set_mode((640, 480))
FONT = pg.font.Font(None, 24)
BLACK = pg.Color('black')
BULLET_IMAGE = pg.Surface((20, 11), pg.SRCALPHA)
pg.draw.polygon(BULLET_IMAGE, pg.Color('grey11'), [(0, 0), (20, 5), (0, 11)])
def update_bullets(bullets):
"""Add the velocity to the pos then assign pos to the rect center."""
for bullet_rect, pos, velocity, _ in bullets:
pos[0] += velocity[0]
pos[1] += velocity[1]
bullet_rect.center = pos
def draw_bullets(bullets, screen):
for bullet_rect, pos, _, image in bullets:
screen.blit(image, bullet_rect)
pg.draw.rect(screen, (200, 140, 0), bullet_rect, 1)
def main():
clock = pg.time.Clock()
# The cannon image and rect.
cannon_img = pg.Surface((60, 22), pg.SRCALPHA)
pg.draw.rect(cannon_img, pg.Color('grey19'), [0, 0, 35, 22])
pg.draw.rect(cannon_img, pg.Color('grey19'), [35, 6, 35, 10])
orig_cannon_img = cannon_img # Store orig image to preserve quality.
cannon = cannon_img.get_rect(center=(320, 240))
angle = 0 # Angle of the cannon.
# Add bullets to this list. Bullets will also be lists
# consisting of a pygame.Rect, the velocity and the image.
bullets = []
bullet_speed = 5
playing = True
while playing:
for event in pg.event.get():
if event.type == pg.QUIT:
playing = False
elif event.type == pg.MOUSEBUTTONDOWN:
# Left button fires a bullet from cannon center with
# current angle. Add the bullet to the bullets list.
if event.button == 1:
# Use cosine and sine to calculate the x and y
# velocity. Scale them by the desired speed.
velocity = (math.cos(math.radians(angle)) * bullet_speed,
math.sin(math.radians(angle)) * bullet_speed)
img = pg.transform.rotate(BULLET_IMAGE, -angle)
bullet_rect = img.get_rect(center=cannon.center)
# The extra pos list is needed because the pygame.Rect
# can only have ints as the x and y value. We still
# need the rect for collision detection.
pos = list(bullet_rect.center)
bullet = [bullet_rect, pos, velocity, img]
bullets.append(bullet)
update_bullets(bullets)
# Find angle to target (mouse pos).
x, y = Vector2(pg.mouse.get_pos()) - cannon.center
angle = math.degrees(math.atan2(y, x))
# Rotate the cannon image.
cannon_img = pg.transform.rotate(orig_cannon_img, -angle)
cannon = cannon_img.get_rect(center=cannon.center)
# Draw
screen.fill(pg.Color('darkseagreen4'))
draw_bullets(bullets, screen)
screen.blit(cannon_img, cannon)
txt = FONT.render('angle {:.1f}'.format(angle), True, BLACK)
screen.blit(txt, (10, 10))
pg.draw.line(
screen, pg.Color(150, 60, 20),
cannon.center, pg.mouse.get_pos(), 2)
pg.display.update()
clock.tick(30)
if __name__ == '__main__':
main()
pg.quit()
Upvotes: 1