Move an object on its own with Pygame - python

I'm trying to make a circle move from the middle of the screen to the top, and then back to the middle, and so on, using Pygame.
import pygame
import sys
pygame.init()
gameOver = False
speed = 5
clock = pygame.time.Clock()
fps = 20
class Screen:
largeur = 600
hauteur = 600
demiLargeur = int(largeur/2)
demiHauteur = int(hauteur/2)
screen = pygame.display.set_mode((Screen.largeur, Screen.hauteur))
class Couleurs:
bleu = (000,000,255)
noir = (000,000,000)
class Cercle:
diametre = 50
epaisseur = 5
posTop = [Screen.demiLargeur, Screen.demiHauteur-2*diametre]
class CirclePos:
top = [Cercle.posTop[0],Cercle.posTop[1]]
circleListTop = [CirclePos.top]
class DrawCircles:
def top (circleListTop):
for CirclePos.top in circleListTop:
pygame.draw.circle(screen, Couleurs.bleu, (CirclePos.top[0],CirclePos.top[1]),Cercle.diametre,Cercle.epaisseur)
class UpdateCirclesPositions:
def top(circleListTop):
for idx,CirclePos.top in enumerate(circleListTop):
if CirclePos.top[1] > Cercle.diametre :
CirclePos.top[1] -= speed
else:
circleListTop.pop(idx)
while not gameOver:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.fill(Couleurs.noir)
clock.tick(fps)
DrawCircles.top(circleListTop)
UpdateCirclesPositions.top(circleListTop)
pygame.display.update()
I have this code so far, the idea being to make it move up, make it desappear, and then create another list to move circles from top to middle. I feel it's a bad idea.
Any idea ?
Thanks

As for me you have too much classes. In class Circle you should have its properties and methods update and draw.
When circle is at the top then it should change speed - speed = -speed. The same when it is in the middle. This way it may move all time. But it may need variable direction to check if it already changed direction because it can be in place where it may change speed all time (in every move).
import pygame
# --- constans ---
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
FPS = 20
SPEED = 5
# --- classes ---
class Colors:
blue = (000, 000, 255)
black = (000, 000, 000)
red = (255, 000, 000)
class Circle:
def __init__(self, x, y, size=50, thick=5, color=Colors.blue, speed=SPEED):
self.size = size
self.thick = thick
self.color = color
self.rect = pygame.Rect(0, 0, 2*size, 2*size)
self.rect.centerx = x
self.rect.centery = y
if speed >= 0:
self.direction = 'up'
else:
self.direction = 'down'
self.speed = speed
def draw(self, screen):
pygame.draw.circle(screen, self.color, self.rect.center, self.size, self.thick)
def update(self):
self.rect.y -= self.speed
if self.rect.top <= 0 and self.direction == 'up':
self.direction = 'down'
self.speed = -self.speed
if self.rect.bottom >= screen_rect.centery and self.direction == 'down':
self.direction = 'up'
self.speed = -self.speed
# --- main ---
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
screen_rect = screen.get_rect()
circles = [
Circle(screen_rect.centerx, screen_rect.centery),
Circle(screen_rect.centerx, 0, speed=-SPEED, color=Colors.red)
]
clock = pygame.time.Clock()
game_over = False
while not game_over:
# --- events ----
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
# --- updates --- (without draws)
for item in circles:
item.update()
# --- draws --- (without updates)
screen.fill(Colors.black)
for item in circles:
item.draw(screen)
pygame.display.update()
clock.tick(FPS)
pygame.quit() # close window

Related

Pygame Paddle Collision with Classes

So I am currently working on Ping with Pygame and I just can't figure out how I should do the collision with the paddle. I have one Pong Game without Classes where i did it like this
if paddle.colliderect(ecl):
bewegungx = abs(bewegungx)
ecl is the ball in this case and here is it with my classes. I currently have only one paddle since I wanna first figure the collision out and then do the rest.
Thank you in advance :)
import pygame
white = (255, 255, 255)
black = (0, 0, 0)
WIDTH = 400
HEIGHT = 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
FPS = 60
clock = pygame.time.Clock()
class Ball():
def __init__(self):
self.ball_w = 30
self.ball_h = 30
self.ball_x = 100
self.ball_y = 150
self.ball_speedx = 3
self.ball_speedy = 3
self.ball_draw = pygame.Rect(self.ball_x, self.ball_y, self.ball_w, self.ball_h)
def draw(self):
pygame.draw.rect(screen, white, self.ball_draw)
def move(self):
self.ball_x += self.ball_speedx
self.ball_y += self.ball_speedy
self.ball_draw.topleft = (self.ball_x, self.ball_y)
def wall_collision(self):
if self.ball_draw.top <=0:
self.ball_speedy = self.ball_speedy *-1
if self.ball_draw.right >= WIDTH:
self.ball_speedx = self.ball_speedx *-1
if self.ball_draw.left <=0:
self.ball_speedx = self.ball_speedx *-1
if self.ball_draw.bottom >= HEIGHT:
self.ball_speedy = self.ball_speedy *-1
class Paddle():
def __init__(self):
self.paddle_w = 30
self.paddle_h = 130
self.paddle_x = 10
self.paddle_y = 150
self.paddle_speed = 0
self.paddle_left = pygame.Rect(self.paddle_x, self.paddle_y, self.paddle_w, self.paddle_h)
def draw(self):
pygame.draw.rect(screen, white, self.paddle_left)
def move(self):
key = pygame.key.get_pressed()
if key[pygame.K_w] and self.paddle_left.top > 0:
self.paddle_left.y -=7
if key[pygame.K_s] and self.paddle_left.bottom < 600:
self.paddle_left.y += 7
ball = Ball()
paddle = Paddle()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
screen.fill(black)
#Ball Functionsw
ball.draw()
ball.move()
ball.wall_collision()
#Paddle Functions
paddle.draw()
paddle.move()
pygame.display.flip()
clock.tick(FPS)
When the Ball hits the Paddle, the direction of the Ball changes. Add a method paddle_left_collision to the Ball class:
class Ball():
# [...]
def paddle_left_collision(self, paddle_rect):
if self.ball_draw.colliderect(paddle_rect):
self.ball_speedx = abs(self.ball_speedx)
Call it in the applicaiton loop
while True:
# handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
# move objects and detect collisisons
ball.move()
paddle.move()
ball.wall_collision()
ball.paddle_left_collision(paddle.paddle_left)
# draw scene
screen.fill(black)
ball.draw()
paddle.draw()
pygame.display.flip()
clock.tick(FPS)
Note that if you have two paddles, change the method as follows:
def paddles_collision(self, paddle_left_rect, paddle_right_rect):
if self.ball_draw.colliderect(paddle_left_rect):
self.ball_speedx = abs(self.ball_speedx)
if self.ball_draw.colliderect(paddle_right_rect):
self.ball_speedx = -abs(self.ball_speedx)
See also How do I detect collision in pygame? and Sometimes the ball doesn't bounce off the paddle in pong game

How do you move the circle to the mouse position [duplicate]

This question already has answers here:
pygame 2 dimensional movement of an enemy towards the player, how to calculate x and y velocity?
(1 answer)
Pygame make sprite walk in given rotation
(1 answer)
How to make smooth movement in pygame
(2 answers)
Closed 1 year ago.
I created a circle in pygame. The circle moves to wherever you click, but instead of "walking" over there, it just appears. I tried some ways, but it doesn't work. If you could find out a way to do it, that would be great. The moving function is in the move function in the Player class.
# import
import pygame
# initialize pygame
pygame.init()
# frame rate variables
FPS = 120
clock = pygame.time.Clock()
# game variables
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 800
mouse_pos = ''
# colors
BLUE = (0, 0, 255)
# activate screen
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Bonker')
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
# init the sprite class
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.mouse_x = 0
self.mouse_y = 0
def move(self):
# delta x and delta y
dx = 0
dy = 0
# extract info from tuple
(x, y) = mouse_pos
self.mouse_x = x
self.mouse_y = y
# create tuple destination and current position tuple
destination = (self.mouse_x, self.mouse_y)
current_pos = [self.x, self.y]
# draw the rectangle
if current_pos[0] >= SCREEN_WIDTH // 2:
dx = 10
self.x += dx
if current_pos[0] < SCREEN_WIDTH // 2:
dx = -10
self.x += dx
if current_pos[1] >= SCREEN_HEIGHT // 2:
dy = 10
self.y += dy
if current_pos[1] < SCREEN_HEIGHT // 2:
dy = -10
self.y += dy
pygame.draw.circle(screen, BLUE, (self.x, self.y), 20)
def draw(self):
# draw the circle
pygame.draw.circle(screen, BLUE, (SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2), 20)
# create instances
# player instance
player = Player(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2)
player.draw()
# main loop
run = True
while run:
# run frame rate
clock.tick(FPS)
# events
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
screen.fill((0, 0, 0))
mouse_pos = pygame.mouse.get_pos()
player.move()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
pygame.display.update()
pygame.quit()
I think some code is not needed
Help would be appreciated
This will move the circle to the mouse position. It doesn't move in one diagonal, but that can be changed.
# import
import pygame
# initialize pygame
pygame.init()
# frame rate variables
FPS = 120
clock = pygame.time.Clock()
# game variables
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 800
# colors
BLUE = (0, 0, 255)
# activate screen
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Bonker')
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
# init the sprite class
pygame.sprite.Sprite.__init__(self)
self.rect = pygame.Rect(0, 0, 40, 40)
self.rect.x = x
self.rect.y = y
self.radius = 20
self.destination = None
self.moving = False
self.dx = 0
self.dy = 0
def set_destination(self, pos):
self.destination = pos
# delta x and delta y
self.dx = self.destination[0] - self.rect.centerx
self.dy = self.destination[1] - self.rect.centery
self.moving = True
def move(self):
if self.rect.centerx != self.destination[0]:
if self.dx > 0:
self.rect.centerx += 1
elif self.dx < 0:
self.rect.centerx -= 1
if self.rect.centery != self.destination[1]:
if self.dy > 0:
self.rect.centery += 1
elif self.dy < 0:
self.rect.centery -= 1
elif self.rect.center == self.destination:
self.moving = False
def draw(self):
# draw the circle
pygame.draw.circle(screen, BLUE, self.rect.center, self.radius)
# create instances
# player instance
player = Player(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2)
player.draw()
# main loop
run = True
movetime = 100
move = False
while run:
# run frame rate
dt = clock.tick(FPS)
movetime -= dt
if movetime <= 0:
move = True
movetime = 400
# events
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = pygame.mouse.get_pos()
player.set_destination(mouse_pos)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
if player.moving:
player.move()
screen.fill((0, 0, 0))
player.draw()
pygame.display.update()
pygame.quit()

How to move a surface in pygame

I'm making a game in pygame and I'm trying to move the self.jetRect, which is the rectangular area of the Surface (jetSurface), but when I try updating the coordinates of the rectangle, I get a TypeError: 'tuple' object is not callable. I think this is related to the fact that a tuple is immutable, but I don't know how to fix this.
import pygame
pygame.init()
clock = pygame.time.Clock()
# Screen setup
screen_width = 600
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Jet Fighter Game")
# Colors
black = (0, 0, 0)
white = (255, 255, 255)
grey = (100, 100, 100)
# Classes
class PLAYER1:
def __init__(self):
self.jetSurface = pygame.image.load("player1 - blackJet.png")
self.x = 100
self.y = 100
self.speed = 5
self.jetRect = self.jetSurface.get_rect(center = (self.x, self.y))
self.angle = 0
self.rotatedJet = self.jetSurface
def rotateJet(self, surface, angle):
key = pygame.key.get_pressed()
if key[pygame.K_a]:
self.angle += 10
self.rotatedJet = pygame.transform.rotozoom(surface, angle, 1)
self.jetRect = self.rotatedJet.get_rect(center=(self.x, self.y))
if key[pygame.K_d]:
self.angle -= 10
self.rotatedJet = pygame.transform.rotozoom(surface, angle, 1)
self.jetRect = self.rotatedJet.get_rect(center=(self.x, self.y))
if self.angle >= 360:
self.angle = 0
screen.blit(self.rotatedJet, self.jetRect)
def moveJet(self):
key = pygame.key.get_pressed()
if key[pygame.K_w]:
self.y -= self.speed
self.jetRect.center(self.x, self.y)
class PLAYER2:
pass
class BULLET:
pass
class MAIN:
def __init__(self):
self.player1 = PLAYER1()
def rotateJets(self):
self.player1.rotateJet(self.player1.jetSurface, self.player1.angle)
def moveJets(self):
self.player1.moveJet()
main = MAIN()
# Main loop
run = True
while run:
# Checking for events
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# Drawing on screen
screen.fill(grey)
# Movement and Collisions
main.rotateJets()
main.moveJets()
pygame.display.flip()
clock.tick(60)
pygame.quit()
Its a typo. self.jetRect.center is a tuple of (self.x, self.y), so when you do
self.jetRect.center(self.x, self.y), you are doing (self.x, self.y)(self.x, self.y), hence the error message of calling a tuple.
I think you meant to assign the tuple like self.jetRect.center = (self.x, self.y)

Pygame sprite creating duplicate instead of moving

I am fairly new to Pygame.
I am attempting to re-create Pong in Python using Pygame, but I have hit a roadblock.
Here is my code:
import pygame
pygame.init()
UP = "up"
DOWN = "down"
white = (255,255,255)
black = (0,0,0)
pygame.mouse.set_visible(True)
resolution = (800,600)
window = pygame.display.set_mode(resolution)
pygame.display.set_caption("Pong!")
clock = pygame.time.Clock()
sprites_list = pygame.sprite.Group()
running = True
class Paddle(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((25,100))
self.image.fill(white)
pygame.draw.rect(self.image,white, (0,0,25,100))
self.rect = self.image.get_rect()
def move(self,direction,pixels):
if direction == DOWN:
self.rect.y -= pixels
if direction == UP:
self.rect.y += pixels
player1 = Paddle()
player1.rect.x = 0
player1.rect.y = 200
sprites_list.add(player1)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_DOWN]:
player1.move(DOWN, 5)
if keys[pygame.K_UP]:
player1.move(UP, 5)
sprites_list.update()
sprites_list.draw(window)
pygame.display.flip()
clock.tick(60)
pygame.quit()
I am trying to make player1, a Paddle object, move up or down depending on which key is pressed. When I run this code, player1 is stretched out after the up or down arrows are pressed; 5 pixels are added onto player1.rect.
What am I doing wrong and why will sprites_list.update() not put player1 in its new position?
You have to clear screen before you draw elements in new loop.
You can fill window with black color window.fill((0,0,0)) or draw background image in every loop.
This is your code after reorganization and adding window.fill(BLACK)
import pygame
# --- constants --- (UPPER_CASE_NAMES)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
UP = "up"
DOWN = "down"
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
# --- classes ---- (CamelCaseNames)
class Paddle(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((25,100))
self.image.fill(WHITE)
# you don't have to draw white rect if all surface already is white
#pygame.draw.rect(self.image,white, (0,0,25,100))
self.rect = self.image.get_rect()
def move(self, direction, pixels):
if direction == DOWN:
self.rect.y += pixels
if direction == UP:
self.rect.y -= pixels
# --- functions --- (lower_case_names)
# empty
# --- main --- (lower_case_names)
# - init -
pygame.init()
pygame.mouse.set_visible(True)
window = pygame.display.set_mode(resolution)
pygame.display.set_caption("Pong!")
# - objects -
sprites_list = pygame.sprite.Group()
player1 = Paddle()
player1.rect.x = 0
player1.rect.y = 200
sprites_list.add(player1)
# - mainloop -
clock = pygame.time.Clock()
running = True
while running:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_DOWN]:
player1.move(DOWN, 5)
if keys[pygame.K_UP]:
player1.move(UP, 5)
# - updates (without draws) -
sprites_list.update()
# - draws (without updates) -
window.fill(BLACK) # <--- clear screen
sprites_list.draw(window)
pygame.display.flip()
clock.tick(60)
# - end -
pygame.quit()

Assign static Mask on moving Surface with PyGame

I just began my first PyGame project yesterday, and I can't find how to properly use Mask entity to apply on a moving Surface.
I made a specific class for animated Surfaces
class LabelObject():
def __init__(self, surface, x, y, endX, speed, idleTime):
self.surface = surface
self.x = x
self.y = y
self.endX = endX
self.speed = speed
self.idleTime = idleTime
self.alpha = 255
self.timer_start = 0
self.timer_end = 0
self.pos = self.surface.get_rect(x=self.x,y=self.y)
def move(self):
self.timer_start += 1
if self.timer_start > self.idleTime:
if self.pos.right > self.endX:
self.pos.x += self.speed
elif self.pos.x < self.x:
self.timer_end += 1
if self.timer_end > self.idleTime:
self.alpha -= 25
if self.timer_end > self.idleTime + 11:
self.pos = self.surface.get_rect(x=self.x, y=self.y)
self.timer_start = 0
self.timer_end = 0
self.alpha = 255
self.surface.set_alpha(self.alpha)
The point of this class is to check if the surface exceeds a given area, and slide to the left to be able to read entirely the text rendered inside it.
In my main loop, I just can blit it to screen like this
label = LabelObject(textSurface,20,10,100,-0.5,30)
while not over:
for event in pygame.event.get():
if event.type == pygame.QUIT
over = True
screen.fill((0,0,0))
label.move()
screen.blit(label.surface, label.pos)
pygame.display.update()
This works fine, but I need to apply a mask on it which doesn't have to move. For this example, the Rect of the mask will be (20, 10, 100-20, label.surface.get_height()). I see some examples about Mask in the web, but I didn't find the way to use it when the mask is static and the surface is moving.
EDIT: I tried using area option in blit function, but there's something strange, the area and the Surface movement are not synchronized.
EDIT2: Finally here is the good blit function with area option. Just need to make the blit with static position, and the area with animated position:
self.screen.blit(label.surface, (label.x,label.y), area=pygame.Rect(label.x-label.pos.x, 0, label.endX-label.x, label.surface.get_height()))
I try to do full working example with subsurface to cut off visible part of full image. Rect (sub_image_rect) is always the same - to draw in the same place. I only change offset to cut off different part of image.
I use text and font to generate some image - and everyone can run it without own images.
import pygame
# --- constants ---
BLACK = ( 0, 0, 0)
RED = (255, 0, 0)
# --- classes ---
class Label():
def __init__(self, text, x, y, width):
font = pygame.font.SysFont(None, 35)
# generate full image
self.image = font.render(text, True, RED)
self.rect = self.image.get_rect(x=x, y=y)
self.width = width
self.speed = 1
# offset of visible part
self.offset_x = 0
self.max_offset_x = self.rect.width - self.width
# visible part of image
self.sub_image = self.image.subsurface((self.offset_x,0), (self.width, self.rect.height))
self.sub_image_rect = self.sub_image.get_rect(x=x, y=y)
def move(self):
# change offset
self.offset_x += self.speed
# change move direction
if self.offset_x < 0:
self.offset_x = 0
self.speed = -self.speed
elif self.offset_x > self.max_offset_x:
self.offset_x = self.max_offset_x
self.speed = -self.speed
print self.offset_x, self.max_offset_x
# visible part of image
self.sub_image = self.image.subsurface((self.offset_x, 0),(self.width, self.rect.height))
def draw(self, surface):
surface.blit(self.sub_image, self.sub_image_rect)
# --- main ---
pygame.init()
screen = pygame.display.set_mode((800,600))
label = Label("Hello World of Python and Pygame!", 100, 100, 200)
# --- mainloop ---
fps = 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.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
# --- updates ---
label.move()
# --- draws ---
screen.fill(BLACK)
label.draw(screen)
fps.tick(25)
pygame.display.flip()
# --- the end ---
pygame.quit()
EDIT: I made example with area in blit. I changed only 3 lines - see # changed in code
import pygame
# --- constants ---
BLACK = ( 0, 0, 0)
RED = (255, 0, 0)
# --- classes ---
class Label():
def __init__(self, text, x, y, width):
font = pygame.font.SysFont(None, 35)
# generate full image
self.image = font.render(text, True, RED)
self.rect = self.image.get_rect(x=x, y=y)
self.width = width
self.speed = 1
# offset of visible part
self.offset_x = 0
self.max_offset_x = self.rect.width - self.width
# visible part of image as 'rect' - 'width' is always the same
self.sub_image_rect = self.image.get_rect(x=0, width=self.width) # changed
def move(self):
# change offset
self.offset_x += self.speed
# change move direction
if self.offset_x < 0:
self.offset_x = 0
self.speed = -self.speed
elif self.offset_x > self.max_offset_x:
self.offset_x = self.max_offset_x
self.speed = -self.speed
# visible part of image - change only `x`
self.sub_image_rect.x = self.offset_x # changed
def draw(self, surface):
surface.blit(self.image, self.rect, area=self.sub_image_rect) # changed
# --- main ---
pygame.init()
screen = pygame.display.set_mode((800,600))
label = Label("Hello World of Python and Pygame!", 100, 100, 200)
# --- mainloop ---
fps = 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.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
# --- updates ---
label.move()
# --- draws ---
screen.fill(BLACK)
label.draw(screen)
fps.tick(25)
pygame.display.flip()
# --- the end ---
pygame.quit()

Categories

Resources