This question already has answers here:
How to rotate an image(player) to the mouse direction?
(2 answers)
How do I rotate a sprite towards the mouse and move it?
(2 answers)
Closed 2 years ago.
I've been trying and trying, but basically I wanna make a tank game which has a tank that can turn itself by the mouse to fire bullets; when you turn your mouse to a direction, the sprite will follow exactly. the problem is, I can't turn the tank with any code, no matter what.
import os
import pygame
import math
pygame.init()
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (0, 30)
icon = pygame.image.load('Sprite3.png')
pygame.display.set_icon((icon))
pygame.display.set_caption('DeMass.io')
class Tank(object): # represents the bird, not the game
def __init__(self):
""" The constructor of the class """
self.image = pygame.image.load('Sprite0.png')
# the bird's position
self.x = 0
self.y = 0
def handle_keys(self):
""" Handles Keys """
key = pygame.key.get_pressed()
dist = 1
if key[pygame.K_DOWN] or key[pygame.K_s]:
self.y += dist # move down
elif key[pygame.K_UP] or key[pygame.K_w]:
self.y -= dist # move up
if key[pygame.K_RIGHT] or key[pygame.K_d]:
self.x += dist # move right
elif key[pygame.K_LEFT] or key[pygame.K_a]:
self.x -= dist # move left
def draw(self, surface):
""" Draw on surface """
# blit yourself at your current position
surface.blit(self.image, (self.x, self.y))
w = 1900
h = 10000
screen = pygame.display.set_mode((w, h))
tank = Tank() # create an instance
clock = pygame.time.Clock()
connection_angle = 90
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit() # quit the screen
running = False
screen.fill((255, 255, 255))
tank.draw(screen)
pygame.display.update()
tank.handle_keys()
clock.tick(100)
You can use the atan2 function from the built-in math module to calcualte the angle between two coordinates,
and then rotate your sprite accordingly:
import pygame
from math import atan2, degrees
wn = pygame.display.set_mode((400, 400))
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((30, 40), pygame.SRCALPHA)
self.image.fill((255, 0, 0))
self.rect = self.image.get_rect(topleft=(185, 180))
def point_at(self, x, y):
rotated_image = pygame.transform.rotate(self.image, degrees(atan2(x-self.rect.x, y-self.rect.y)))
new_rect = rotated_image.get_rect(center=self.rect.center)
wn.fill((0, 0, 0))
wn.blit(rotated_image, new_rect.topleft)
player = Player()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.MOUSEMOTION:
player.point_at(*pygame.mouse.get_pos())
pygame.display.update()
Output:
Related
I am trying to make objects fall like they would on earth. I already got them to blit where I wanted them to but I can't seem to animate them.
This is the object that I want to fall
import pygame
class circle():
def __init__(self, screen):
planet_color = (255,0,0)
planet_radius = 20
self.screen = screen
ev = pygame.event.get()
self.image = pygame.image.load('../images/jupiter.bmp')
self.image = pygame.transform.scale(self.image, (80, 80))
def blitme(self):
self.x = pygame.mouse.get_pos()
self.rect = self.image.get_rect()
self.rect.center = self.x
self.screen.blit(self.image, self.rect)
And this is the code that runs it. When the mouse is clicked a little picture of Jupiter is made where the mouse was clicked. How do I get this image to fall?
import pygame
import gravfunc as gf
from gravfunc import circle
import sys
def run_game():
screen_height = 670
screen_width = 1270
pygame.init()
screen = pygame.display.set_mode((screen_width, screen_height))
screen.fill((10,10,30))
running = True
circ = circle(screen)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
circ.blitme()
pygame.display.flip()
run_game()
Give your class a self.speed_y attribute and add the GRAVITY to it each frame to accelerate the object. I've also added a self.pos_y attribute because pygame.Rects can't have floating point numbers as their coordinates. So,
increase the speed
add the speed to the position (self.pos_y)
assign the self.pos_y to self.rect.y.
Since you are already using a class, I recommend to make it a pygame sprite subclass (inherit from pygame.sprite.Sprite). Then you can add all circles to a pygame.sprite.Group and update and draw them by calling sprite_group.update() and sprite_grop.draw(screen).
import pygame
GRAVITY = .2 # Pretty low gravity.
class Circle(pygame.sprite.Sprite):
def __init__(self, pos, screen):
super().__init__()
self.screen = screen
self.image = pygame.Surface((80, 80), pygame.SRCALPHA)
pygame.draw.circle(self.image, (30, 90, 150), (40, 40), 40)
self.rect = self.image.get_rect(center=pos)
self.pos_y = pos[1]
self.speed_y = 0
def update(self):
self.speed_y += GRAVITY
self.pos_y += self.speed_y
self.rect.y = self.pos_y
if self.pos_y > self.screen.get_height():
self.kill() # Remove off-screen circles.
def run_game():
pygame.init()
screen = pygame.display.set_mode((1270, 670))
clock = pygame.time.Clock()
running = True
circles = pygame.sprite.Group(Circle((600, 0), screen))
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
elif event.type == pygame.MOUSEBUTTONDOWN:
circles.add(Circle(event.pos, screen))
circles.update()
screen.fill((10, 10, 30))
circles.draw(screen)
pygame.display.flip()
clock.tick(60)
run_game()
pygame.quit()
im trying to get my image (bird) to move up and down on the screen but i cant figure out how to do it here is what i tried im sure its way off but im trying to figure it out if anyone can help that would be great!
import pygame
import os
screen = pygame.display.set_mode((640, 400))
running = 1
while running:
event = pygame.event.poll()
if event.type == pygame.QUIT:
running = 0
screen.fill([255, 255, 255])
clock = pygame.time.Clock()
clock.tick(0.5)
pygame.display.flip()
bird = pygame.image.load(os.path.join('C:\Python27', 'player.png'))
screen.blit( bird, ( 0, 0 ) )
pygame.display.update()
class game(object):
def move(self, x, y):
self.player.center[0] += x
self.player.center[1] += y
if event.key == K_UP:
player.move(0,5)
if event.key == K_DOWN:
player.move(0,-5)
game()
im trying to get it to move down on the down button press and up on the UP key press
As stated by ecline6, bird is the least of your worries at this point.
Consider reading this book..
For now, First let's clean up your code...
import pygame
import os
# let's address the class a little later..
pygame.init()
screen = pygame.display.set_mode((640, 400))
# you only need to call the following once,so pull them out of the while loop.
bird = pygame.image.load(os.path.join('C:\Python27', 'player.png'))
clock = pygame.time.Clock()
running = True
while running:
event = pygame.event.poll()
if event.type == pygame.QUIT:
running = False
screen.fill((255, 255, 255)) # fill the screen
screen.blit(bird, (0, 0)) # then blit the bird
pygame.display.update() # Just do one thing, update/flip.
clock.tick(40) # This call will regulate your FPS (to be 40 or less)
Now the reason that your "bird" is not moving is:
When you blit the image, ie: screen.blit(bird, (0, 0)),
The (0,0) is constant, so it won't move.
Here's the final code, with the output you want (try it) and read the comments:
import pygame
import os
# it is better to have an extra variable, than an extremely long line.
img_path = os.path.join('C:\Python27', 'player.png')
class Bird(object): # represents the bird, not the game
def __init__(self):
""" The constructor of the class """
self.image = pygame.image.load(img_path)
# the bird's position
self.x = 0
self.y = 0
def handle_keys(self):
""" Handles Keys """
key = pygame.key.get_pressed()
dist = 1 # distance moved in 1 frame, try changing it to 5
if key[pygame.K_DOWN]: # down key
self.y += dist # move down
elif key[pygame.K_UP]: # up key
self.y -= dist # move up
if key[pygame.K_RIGHT]: # right key
self.x += dist # move right
elif key[pygame.K_LEFT]: # left key
self.x -= dist # move left
def draw(self, surface):
""" Draw on surface """
# blit yourself at your current position
surface.blit(self.image, (self.x, self.y))
pygame.init()
screen = pygame.display.set_mode((640, 400))
bird = Bird() # create an instance
clock = pygame.time.Clock()
running = True
while running:
# handle every event since the last frame.
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit() # quit the screen
running = False
bird.handle_keys() # handle the keys
screen.fill((255,255,255)) # fill the screen with white
bird.draw(screen) # draw the bird to the screen
pygame.display.update() # update the screen
clock.tick(40)
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN event occurs once every time a key is pressed. KEYUP occurs once every time a key is released. Use the keyboard events for a single action or a step-by-step movement.
If you want to achieve a continuously movement, you have to use pygame.key.get_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.
See also Key and Keyboard event and How can I make a sprite move when key is held down.
Minimal example:
import pygame
import os
class Bird(object):
def __init__(self):
self.image = pygame.image.load(os.path.join('C:\Python27', 'player.png'))
self.center = [100, 200]
def move(self, x, y):
self.center[0] += x
self.center[1] += y
def draw(self, surf):
surf.blit(self.image, self.center)
class game(object):
def __init__(self):
self.screen = pygame.display.set_mode((640, 400))
self.clock = pygame.time.Clock()
self.player = Bird()
def run(self):
running = 1
while running:
self.clock.tick(60)
event = pygame.event.poll()
if event.type == pygame.QUIT:
running = 0
keys = pygame.key.get_pressed()
move_x = keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]
move_y = keys[pygame.K_DOWN] - keys[pygame.K_UP]
self.player.move(move_x * 5, move_y * 5)
self.screen.fill([255, 255, 255])
self.player.draw(self.screen)
pygame.display.update()
g = game()
g.run()
I am trying to make objects fall like they would on earth. I already got them to blit where I wanted them to but I can't seem to animate them.
This is the object that I want to fall
import pygame
class circle():
def __init__(self, screen):
planet_color = (255,0,0)
planet_radius = 20
self.screen = screen
ev = pygame.event.get()
self.image = pygame.image.load('../images/jupiter.bmp')
self.image = pygame.transform.scale(self.image, (80, 80))
def blitme(self):
self.x = pygame.mouse.get_pos()
self.rect = self.image.get_rect()
self.rect.center = self.x
self.screen.blit(self.image, self.rect)
And this is the code that runs it. When the mouse is clicked a little picture of Jupiter is made where the mouse was clicked. How do I get this image to fall?
import pygame
import gravfunc as gf
from gravfunc import circle
import sys
def run_game():
screen_height = 670
screen_width = 1270
pygame.init()
screen = pygame.display.set_mode((screen_width, screen_height))
screen.fill((10,10,30))
running = True
circ = circle(screen)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
circ.blitme()
pygame.display.flip()
run_game()
Give your class a self.speed_y attribute and add the GRAVITY to it each frame to accelerate the object. I've also added a self.pos_y attribute because pygame.Rects can't have floating point numbers as their coordinates. So,
increase the speed
add the speed to the position (self.pos_y)
assign the self.pos_y to self.rect.y.
Since you are already using a class, I recommend to make it a pygame sprite subclass (inherit from pygame.sprite.Sprite). Then you can add all circles to a pygame.sprite.Group and update and draw them by calling sprite_group.update() and sprite_grop.draw(screen).
import pygame
GRAVITY = .2 # Pretty low gravity.
class Circle(pygame.sprite.Sprite):
def __init__(self, pos, screen):
super().__init__()
self.screen = screen
self.image = pygame.Surface((80, 80), pygame.SRCALPHA)
pygame.draw.circle(self.image, (30, 90, 150), (40, 40), 40)
self.rect = self.image.get_rect(center=pos)
self.pos_y = pos[1]
self.speed_y = 0
def update(self):
self.speed_y += GRAVITY
self.pos_y += self.speed_y
self.rect.y = self.pos_y
if self.pos_y > self.screen.get_height():
self.kill() # Remove off-screen circles.
def run_game():
pygame.init()
screen = pygame.display.set_mode((1270, 670))
clock = pygame.time.Clock()
running = True
circles = pygame.sprite.Group(Circle((600, 0), screen))
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
elif event.type == pygame.MOUSEBUTTONDOWN:
circles.add(Circle(event.pos, screen))
circles.update()
screen.fill((10, 10, 30))
circles.draw(screen)
pygame.display.flip()
clock.tick(60)
run_game()
pygame.quit()
im trying to get my image (bird) to move up and down on the screen but i cant figure out how to do it here is what i tried im sure its way off but im trying to figure it out if anyone can help that would be great!
import pygame
import os
screen = pygame.display.set_mode((640, 400))
running = 1
while running:
event = pygame.event.poll()
if event.type == pygame.QUIT:
running = 0
screen.fill([255, 255, 255])
clock = pygame.time.Clock()
clock.tick(0.5)
pygame.display.flip()
bird = pygame.image.load(os.path.join('C:\Python27', 'player.png'))
screen.blit( bird, ( 0, 0 ) )
pygame.display.update()
class game(object):
def move(self, x, y):
self.player.center[0] += x
self.player.center[1] += y
if event.key == K_UP:
player.move(0,5)
if event.key == K_DOWN:
player.move(0,-5)
game()
im trying to get it to move down on the down button press and up on the UP key press
As stated by ecline6, bird is the least of your worries at this point.
Consider reading this book..
For now, First let's clean up your code...
import pygame
import os
# let's address the class a little later..
pygame.init()
screen = pygame.display.set_mode((640, 400))
# you only need to call the following once,so pull them out of the while loop.
bird = pygame.image.load(os.path.join('C:\Python27', 'player.png'))
clock = pygame.time.Clock()
running = True
while running:
event = pygame.event.poll()
if event.type == pygame.QUIT:
running = False
screen.fill((255, 255, 255)) # fill the screen
screen.blit(bird, (0, 0)) # then blit the bird
pygame.display.update() # Just do one thing, update/flip.
clock.tick(40) # This call will regulate your FPS (to be 40 or less)
Now the reason that your "bird" is not moving is:
When you blit the image, ie: screen.blit(bird, (0, 0)),
The (0,0) is constant, so it won't move.
Here's the final code, with the output you want (try it) and read the comments:
import pygame
import os
# it is better to have an extra variable, than an extremely long line.
img_path = os.path.join('C:\Python27', 'player.png')
class Bird(object): # represents the bird, not the game
def __init__(self):
""" The constructor of the class """
self.image = pygame.image.load(img_path)
# the bird's position
self.x = 0
self.y = 0
def handle_keys(self):
""" Handles Keys """
key = pygame.key.get_pressed()
dist = 1 # distance moved in 1 frame, try changing it to 5
if key[pygame.K_DOWN]: # down key
self.y += dist # move down
elif key[pygame.K_UP]: # up key
self.y -= dist # move up
if key[pygame.K_RIGHT]: # right key
self.x += dist # move right
elif key[pygame.K_LEFT]: # left key
self.x -= dist # move left
def draw(self, surface):
""" Draw on surface """
# blit yourself at your current position
surface.blit(self.image, (self.x, self.y))
pygame.init()
screen = pygame.display.set_mode((640, 400))
bird = Bird() # create an instance
clock = pygame.time.Clock()
running = True
while running:
# handle every event since the last frame.
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit() # quit the screen
running = False
bird.handle_keys() # handle the keys
screen.fill((255,255,255)) # fill the screen with white
bird.draw(screen) # draw the bird to the screen
pygame.display.update() # update the screen
clock.tick(40)
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN event occurs once every time a key is pressed. KEYUP occurs once every time a key is released. Use the keyboard events for a single action or a step-by-step movement.
If you want to achieve a continuously movement, you have to use pygame.key.get_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.
See also Key and Keyboard event and How can I make a sprite move when key is held down.
Minimal example:
import pygame
import os
class Bird(object):
def __init__(self):
self.image = pygame.image.load(os.path.join('C:\Python27', 'player.png'))
self.center = [100, 200]
def move(self, x, y):
self.center[0] += x
self.center[1] += y
def draw(self, surf):
surf.blit(self.image, self.center)
class game(object):
def __init__(self):
self.screen = pygame.display.set_mode((640, 400))
self.clock = pygame.time.Clock()
self.player = Bird()
def run(self):
running = 1
while running:
self.clock.tick(60)
event = pygame.event.poll()
if event.type == pygame.QUIT:
running = 0
keys = pygame.key.get_pressed()
move_x = keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]
move_y = keys[pygame.K_DOWN] - keys[pygame.K_UP]
self.player.move(move_x * 5, move_y * 5)
self.screen.fill([255, 255, 255])
self.player.draw(self.screen)
pygame.display.update()
g = game()
g.run()
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)