How can I fix my Pygame collision system? [duplicate] - python

Is there a way in pygame to look for a collision between the a particular side of a sprite and a particular side of another sprite in pygame? For example, if the top of sprite A collides with the bottom of Sprite B, return True.
I am certain there is a way to do this, but I can't find any particular method in the documentation.
Thanks!

There is no function to get sides collision in PyGame.
But you could try to use pygame.Rect.collidepoint to test if A.rect.midleft, A.rect.midright, A.rect.midtop, A.rect.midbottom, A.rect.topleft, A.rect.bottomleft , A.rect.topright, A.rect.bottomright are inside B.rect (pygame.Rect).
EDIT:
Example code. Use arrows to move player and touch enemy.
(probably it is not optimal solution)
import pygame
WHITE = (255,255,255)
BLACK = (0 ,0 ,0 )
RED = (255,0 ,0 )
GREEN = (0 ,255,0 )
BLUE = (0 ,0 ,255)
class Player():
def __init__(self, x=0, y=0, width=150, height=150):
self.rect = pygame.Rect(x, y, width, height)
self.speed_x = 5
self.speed_y = 5
self.move_x = 0
self.move_y = 0
self.collision = [False] * 9
self.font = pygame.font.SysFont("", 32)
self.text = "";
def set_center(self, screen):
self.rect.center = screen.get_rect().center
def event_handler(self, event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
self.move_x -= self.speed_x
elif event.key == pygame.K_RIGHT:
self.move_x += self.speed_x
elif event.key == pygame.K_UP:
self.move_y -= self.speed_y
elif event.key == pygame.K_DOWN:
self.move_y += self.speed_y
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
self.move_x += self.speed_x
elif event.key == pygame.K_RIGHT:
self.move_x -= self.speed_x
elif event.key == pygame.K_UP:
self.move_y += self.speed_y
elif event.key == pygame.K_DOWN:
self.move_y -= self.speed_y
def update(self):
self.rect.x += self.move_x
self.rect.y += self.move_y
def draw(self, screen):
pygame.draw.rect(screen, WHITE, self.rect, 2)
self.draw_point(screen, self.rect.topleft, self.collision[0])
self.draw_point(screen, self.rect.topright, self.collision[1])
self.draw_point(screen, self.rect.bottomleft, self.collision[2])
self.draw_point(screen, self.rect.bottomright, self.collision[3])
self.draw_point(screen, self.rect.midleft, self.collision[4])
self.draw_point(screen, self.rect.midright, self.collision[5])
self.draw_point(screen, self.rect.midtop, self.collision[6])
self.draw_point(screen, self.rect.midbottom, self.collision[7])
self.draw_point(screen, self.rect.center, self.collision[8])
def draw_point(self, screen, pos, collision):
if not collision:
pygame.draw.circle(screen, GREEN, pos, 5)
else:
pygame.draw.circle(screen, RED, pos, 5)
def check_collision(self, rect):
self.collision[0] = rect.collidepoint(self.rect.topleft)
self.collision[1] = rect.collidepoint(self.rect.topright)
self.collision[2] = rect.collidepoint(self.rect.bottomleft)
self.collision[3] = rect.collidepoint(self.rect.bottomright)
self.collision[4] = rect.collidepoint(self.rect.midleft)
self.collision[5] = rect.collidepoint(self.rect.midright)
self.collision[6] = rect.collidepoint(self.rect.midtop)
self.collision[7] = rect.collidepoint(self.rect.midbottom)
self.collision[8] = rect.collidepoint(self.rect.center)
def render_collision_info(self):
text = "collision: "
print "collision:",
if self.collision[0] or self.collision[2] or self.collision[4]:
text += "left "
print "left",
if self.collision[1] or self.collision[3] or self.collision[5]:
text += "right "
print "right",
if self.collision[0] or self.collision[1] or self.collision[6]:
text += "top "
print "top",
if self.collision[2] or self.collision[3] or self.collision[7]:
text += "bottom "
print "bottom",
if self.collision[8]:
text += "center "
print "center",
print
self.text = self.font.render(text, 1, WHITE)
def draw_collision_info(self, screen, pos):
screen.blit(self.text, pos)
#----------------------------------------------------------------------
class Game():
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode( (800,600) )
pygame.display.set_caption("Side Collision")
self.player = Player()
self.enemy = Player()
self.enemy.set_center(self.screen)
def run(self):
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.KEYDOWN:
if event.key == pygame.K_ESCAPE:
RUNNING = False
self.player.event_handler(event)
# --- updates ---
self.player.update()
self.enemy.update()
self.player.check_collision(self.enemy.rect)
self.enemy.check_collision(self.player.rect)
self.player.render_collision_info()
self.enemy.render_collision_info()
# --- draws ----
self.screen.fill(BLACK)
self.player.draw(self.screen)
self.enemy.draw(self.screen)
self.player.draw_collision_info(self.screen, (0,0))
self.enemy.draw_collision_info(self.screen, (0,32))
pygame.display.update()
# --- FPS ---
clock.tick(30)
pygame.quit()
#----------------------------------------------------------------------
Game().run()
EDIT (08.2016): version with colllisions rect, rect_ratio, circle
GitHub: furas/python-examples/pygame/collisions

The logic behind collision is like that:
#Assume two surfaces
objectA
objectB
if objectA.right > objectB.left and objectA.left < objectB.right and objectA.top < objectB.bottom and objectA.bottom > objectB.top
#Collision happens
if you want to detect side collision (as if objectA hitted objectB on the side) you can do the following:
#Here is the code where objectA moves
objectA.X += 10
#Here check Collision, if collision happens objectA hitted objectB from the side
objectA.Y += 10
#Here check Collision again, if collision is true then objectA hitted object B from top/bottom

I solved this by creating multiple collide boxes. This should help a lot of people.
https://youtu.be/W-Vz6le1YUg
Code:
if tanner.axe.colliderect(oak.red) and.
tanner.playerHitBox.colliderect(oak.leftHit) and.
keys_pressed[pygame.K_SPACE]:
Number_of_Hits_Left += 1
print(Number_of_Hits_Left)
if tanner.axe.colliderect(oak.red) and.
tanner.playerHitBox.colliderect(oak.rightHit) and.
keys_pressed[pygame.K_SPACE]:
Number_of_Hits_Right += 1
print(Number_of_Hits_Right)
So I have a total of 5 hit boxes to accomplish said mission. And really all you would have to do is create your main hit box, then create 2 side boxes on the left and right side of main hit box, so that they barely overlap. So let's say you shoot a bullet your code would be something like above. "When bullet collides with side box AND when bullet collides with main box, do something."

Like Furas has said, no, there is not way to get side collisions in Pygame past the point system he set up. And even that one wont give you what you want, because you can never be sure which direction the collision happened when dealing with rows, columns or corners of Rectangles.
This is why most tutorials recommend saving your sprites initial direction. then moving in the opposite direction in case of a collision.

For objectA give the object this method:
def is_collided_with(self, sprite):
return self.rect.colliderect(sprite.rect)
This return statement returns either True or False
then in the main loop for collisions just do:
if objectA.is_collided_with(ObjectB):
Collision happened!

Related

Bullets wont show when fired... Attributes seems to show bullet is moving but wont show [duplicate]

This question already has answers here:
Why is nothing drawn in PyGame at all?
(2 answers)
Closed 1 year ago.
Below is the code... Bullet class is defined first, class is called in _fire_bullet, _update_screen, and _check_KEYDOWN. When spacebar is pressed the event handler should take in the event key, call _fire_bullet function where a bullet object is created and added to sprite list. Then fired and moves across screen. As of now its going to move the wrong direction but I will correct that issue easily when I can actually see the bullet.
#make a pygame window with a blue background
import pygame
import sys
from pygame.sprite import Sprite
class Bullet(Sprite):
""" A class to manage bullets fired from the ship """
def __init__(self, game):
""" create a bullet object at the ships current position """
super().__init__()
self.screen = game.screen
self.bullet_speed = 1.0
self.bullet_width = 300
self.bullet_height = 150
self.bullet_color = (0, 200, 200)
#create a bullet at rect (0,0) and the set the correct position
self.rect = pygame.Rect(0, 0, self.bullet_width, self.bullet_height)
self.rect.midright = game.rect.midright
#store the bullets position as a decimal value
self.y = float(self.rect.y)
self.x = float(self.rect.x)
def update(self):
""" move the bullet up the screen """
#update the decimal position of the bullet.
self.y -= self.bullet_speed
self.rect.x = self.x
#uipdate the rect position
self.rect.y = self.y
def draw_bullet(self):
""" draw the bullet to the screen """
pygame.draw.rect(self.screen, self.bullet_color, self.rect)
class Game:
""" a class the creates a window with a blue screen """
def __init__(self):
pygame.init()
#--------------------------------------------------------------------------------------------
#screen size, color, caption
self.screen = pygame.display.set_mode((1200,800)) #create attribute to hold display settings
self.bg_color = (250,250,250) #create attribute to hold RGB color (blue)
pygame.display.set_caption("Blue Screen")
#--------------------------------------------------------------------------------------------
#--------------------------------------------------------------------------------------------
#tank drawing
self.screen_rect = self.screen.get_rect() #get the screen rect dim
self.image = pygame.image.load('images/tank.bmp') #load the image from directory
self.rect = self.image.get_rect() #get the image rect dim
self.rect.center = self.screen_rect.center #store the screens center x/y coord
#tank movement
self.tank_moving_left = False
self.tank_moving_right = False
self.tank_moving_up = False
self.tank_moving_down = False
self.tank_speed = 1 #tank pixels
self.direction_right = self.image #holds right image
self.direction_left = pygame.transform.flip(self.image, True, False) #holds left image
#--------------------------------------------------------------------------------------------
self.bullets = pygame.sprite.Group()
def move(self):
""" move tnak tank_speed based on direction of movement (key pressed)
also detect collision """
if self.tank_moving_right and self.rect.right < self.screen_rect.right:
self.rect.x += self.tank_speed
if self.tank_moving_left and self.rect.left > self.screen_rect.left:
self.rect.x -= self.tank_speed
if self.tank_moving_down and self.rect.bottom < self.screen_rect.bottom:
self.rect.y += self.tank_speed
if self.tank_moving_up and self.rect.top > self.screen_rect.top:
self.rect.y -= self.tank_speed
def blitme(self):
""" draw the image of the tank """
self.screen.blit(self.image, self.rect)
def _update_screen(self):
""" update screen """
self.screen.fill(self.bg_color)
self.blitme()
pygame.display.flip()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
print(bullet.rect.midright)
def _check_KEYDOWN(self, event):
""" when key is press either quit, or move direction of arrow pressed and flip image """
if event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_RIGHT:
self.tank_moving_right = True
self.image = self.direction_right
elif event.key == pygame.K_LEFT:
self.tank_moving_left = True
self.image = self.direction_left
elif event.key == pygame.K_UP:
self.tank_moving_up = True
elif event.key == pygame.K_DOWN:
self.tank_moving_down = True
elif event.key == pygame.K_SPACE:
self._fire_bullet()
print(1)
def _check_KEYUP(self, event):
""" when key is let go stop moving """
if event.key == pygame.K_RIGHT:
self.tank_moving_right = False
elif event.key == pygame.K_LEFT:
self.tank_moving_left = False
elif event.key == pygame.K_UP:
self.tank_moving_up = False
elif event.key == pygame.K_DOWN:
self.tank_moving_down = False
def _fire_bullet(self):
""" create a bullet and add it to the bullets group """
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
def run_game(self):
""" loops the game/ updates screen/ checks for key clicks"""
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
self._check_KEYDOWN(event)
elif event.type == pygame.KEYUP:
self._check_KEYUP(event)
self.move()
self.bullets.update()
self._update_screen()
if __name__ == '__main__':
a = Game()
a.run_game()
Your _update_screen() function is drawing your bullets after updating the display. The bullets then get overwritten next time _update_screen() is called when you fill the screen with the background color.
If you reorder your screen update function as follows you should be able to see your bullets:
def _update_screen(self):
""" update screen """
self.screen.fill(self.bg_color)
self.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
print(bullet.rect.midright)
pygame.display.flip()
Also, you can create an image for your bullet by changing your initialization function:
…
#create a bullet at rect (0,0) and the set the correct position
self.image = pygame.Surface((self.bullet_width, self.bullet_height))
self.image.fill(self.bullet_color)
self.rect = self.image.get_rect()
Then you won't need a draw_bullet() function, you can replace the drawing of individual bullets in _update_screen() with self.bullets.draw(self.screen)

How do I detect collisions between one rectangle and a previous position of another rectangle? Pygame

I am new to Python and programming in general, so I've decided to make a basic clone of Tron with 2 players. To clarify, Tron is a game where players are riding a bike that creates a path/trail behind them. If a player crashes into the path/trail of another player, they lose. I am trying to detect this type of collision in my code by utilizing rectangles in pygame.
I have a general idea of how I want to implement this idea: Every time a player moves, they make continuous rectangles behind them and those rectangles get appended to a list called tron_path_1 or tron_path_2. So if player 1's rect collides with a rect in the list of the opposing player(tron_path_2), I want to detect that collision. However in my code, I can only detect a collision if the two heads of each player collide with each other. So my question is: How can I detect the collision of a player's rect with the previous rects made by the opposing player?
import pygame
import sys
class Player():
def __init__(self, screen, x, y, w, h, dx, dy, tron_path, color):
"""Create player's tron bike."""
self.screen = screen
self.screen_rect = screen.get_rect()
self.x = x
self.y = y
self.w = w #width
self.h = h #height
self.dx = dx
self.dy = dy
self.tron_path = tron_path
self.color = color
self.player_rect = pygame.Rect(self.x, self.y, self.w, self.h)
def update_position(self):
self.player_rect[0] += self.dx #changes rect's x-coordinate
self.player_rect[1] += self.dy #changes rect's y-coordinate
self.tron_path.append(self.player_rect)
def draw_player(self):
pygame.draw.rect(self.screen, self.color, self.player_rect)
# Initialize pygame settings.
pygame.init()
screen = pygame.display.set_mode((1200,700))
pygame.display.set_caption("Tron")
# Player settings
p1_color = ((219,62,177)) #pink
p2_color = ((255,255,255)) #white
players = []
tron_path_1 = [] # List to keep track of rectangles for each player
tron_path_2 = []
p1 = Player(screen, x=200, y=500, w=5, h=5, dx=5, dy=0, tron_path=tron_path_1, color=p1_color) #player 1
p2 = Player(screen, x=1000, y=500, w=5, h=5, dx=-5, dy=0, tron_path=tron_path_2, color=p2_color) #player 2
players.append(p1)
players.append(p2)
# Initialize
while True:
clockobject = pygame.time.Clock()
clockobject.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
# Player 1 controls
if event.key == pygame.K_w:
p1.dx = 0
p1.dy = -5
elif event.key == pygame.K_s:
p1.dx = 0
p1.dy = 5
elif event.key == pygame.K_d:
p1.dx = 5
p1.dy = 0
elif event.key == pygame.K_a:
p1.dx = -5
p1.dy = 0
# Player 2 controls
if event.key == pygame.K_UP:
p2.dx = 0
p2.dy = -5
elif event.key == pygame.K_DOWN:
p2.dx = 0
p2.dy = 5
elif event.key == pygame.K_RIGHT:
p2.dx = 5
p2.dy = 0
elif event.key == pygame.K_LEFT:
p2.dx = -5
p2.dy = 0
p1.update_position()
p2.update_position()
p1.draw_player()
p2.draw_player()
# Trying to detect collision with one player and another player's path
for rect in tron_path_1:
if p2.player_rect.colliderect(rect):
print("collision")
for rect in tron_path_2:
if p1.player_rect.colliderect(rect):
print("collision")
pygame.display.flip()
When you do tron_path_1.append(p1.player_rect) then you don't create a copy of p1.player_rect. p1.player_rect is a variable that reference a pygame.Rect object.
After tron_path_1.append(p1.player_rect), the variable p1.player_rect and the list element tron_path_1[0] refer to the same object.
Hence, when you change p1.player_rect, then the elements of the list seems to change, too, because there is just 1 pygame.Rect object.
Use .copy() to create a copy of the rectangle:
class Player():
# [...]
def update_position(self):
self.player_rect[0] += self.dx #changes rect's x-coordinate
self.player_rect[1] += self.dy #changes rect's y-coordinate
# self.tron_path.append(self.player_rect) <--- CHANGE TO
self.tron_path.append(self.player_rect.copy())

PyGame rect.move movement not functioning properly

I am developing my first pygame application in the form of a brick breaker clone. For the player paddle, I am checking for key holds in the main game loop and then redrawing the player object's sprite every frame, as show in the code snippet below:
class Player():
def __init__(self):
self.sprite = pg.transform.scale(pg.image.load('49-Breakout-Tiles.png'), (61,16))
self.rect = self.sprite.get_rect()
self.rect.right += displayRect.center[0]-25
self.rect.top += displayRect.center[1]+450
self.draw(0)
def draw(self, x):
pg.draw.rect(display, black, (self.rect.x, self.rect.y, 61, 16))
self.rect.right += x
if not displayRect.contains(self.rect):
self.rect.right -= x
display.blit(self.sprite, self.rect)
#from gameloop
moveNeg, movePos = False, False
while True:
for event in pg.event.get():
if event.type == pg.KEYDOWN:
if event.key == pg.K_LEFT or event.key == pg.K_a:
moveNeg = True
if event.key == pg.K_RIGHT or event.key == pg.K_d:
movePos = True
if event.type == pg.KEYUP:
if event.key == pg.K_LEFT or event.key == pg.K_a:
moveNeg = False
if event.key == pg.K_RIGHT or event.key == pg.K_d:
movePos = False
if moveNeg:
player.draw(-1)
if movePos:
player.draw(1)
This code works fine, and also ensures that the player paddle stays within the display bounds.
However, for the ball object, I am trying to use rect.move(x,y) to move it. I have already tried with rect.right and rect.top but the ball object is still unresponsive. Here is the code I have so far:
class Ball():
def __init__(self):
self.sprite = pg.transform.scale(pg.image.load('58-Breakout-Tiles.png'), (16, 16))
self.rect = self.sprite.get_rect()
self.rect.x += displayRect.center[0]
self.rect.y += displayRect.center[1]
self.dir = [random.uniform(-1.0,1.0), random.uniform(-1.0,1.0)]
print(self.dir)
def draw(self, xy):
pg.draw.rect(display, black, (self.rect.x, self.rect.y, 16, 16))
self.rect = self.rect.move(xy[0], xy[1])
display.blit(self.sprite, self.rect)
The ball is centered when the object is initialised (as shown on lines 3/4 of the __init__ function, but I don't see why this would affect the movement of the ball's rect. Also for clarity, self.dir is used to give the ball a random starting direction, and I am aware that it is able to move upward with this current configuration.
Since I am new to pygame it completely baffles me as to why my logic is flawed so any help is much appreciated.
Thanks
pygame.Rect.move doesn't change the Rect object itself, but it returns an new Rect object (Probably the name of the method is misleading).
This means, that
self.rect.move(xy[0], xy[1])
doesn't change anything. You've to assign the rectangle which is returned by .move to "itself":
self.rect = self.rect.move(xy)
Alternatively you can use pygame.Rect.move_ip(), moves the rectangle "in place" and changes the Rect object:
self.rect.move_ip(xy[0], xy[1])

Re: How to detect and end game when a pygame sprite runs into its tail?

I created a snake-like game in which the user moves the sprite, and the sprite leaves a trail. If the user runs into the trail he's created, I'd like the game to end, and the player to lose.
One idea I had was to somehow track past positions of the sprite (maybe in a list), and then create an if statement that would lead to a game loss (However, I'm was a little unclear on how to do that).
I received an answer to this question that coded for this list:
"I think you could declare a two dimensional list like this:
pastPositions = [[400, 300]]
Then every time the player's position moves, check the list:
for row in pastPositions:
If (player.rect.x == pastPositions[row][0] and player.rect.y == pastPositions[row][1]): done = true # game over
If the player hasn't been there yet, then add that position to the list.
pastPositions.append([player.rect.x, player.rect.y])
This looks like it should work, but when I try to run the code (in Python Interactive), I get an error message that reads: "line 86, in <module> if player.rect.x == astPositions[row][0] and player.rect.y == pastPositions[row][1]: IndexError: list index out of range"
What would you suggest I change the range to so that this doesn't happen? I tried setting it to the width and height of the pygame window.
import pygame
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface([15, 15])
self.image.fill(WHITE)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.change_x = 0
self.change_y = 0
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
self.rect.y += self.change_y
pygame.init()
screen = pygame.display.set_mode([800, 600])
pygame.display.set_caption('The Etch-a-Sketch Game')
myfont = pygame.font.SysFont('Times', 20)
textsurface = myfont.render('This is the Etch-a-Sketch Game', False, (255, 255, 255))
screen.blit(textsurface,(0,0))
myfont = pygame.font.SysFont('Times', 15)
textsurface = myfont.render('Feel free to draw, but if you cross your own path, you will die.', False, (255, 255, 255))
screen.blit(textsurface,(0,20))
player = Player(400, 300)
all_sprites_list = pygame.sprite.Group()
all_sprites_list.add(player)
clock = pygame.time.Clock()
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.changespeed(-3, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(3, 0)
elif event.key == pygame.K_UP:
player.changespeed(0, -3)
elif event.key == pygame.K_DOWN:
player.changespeed(0, 3)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(3, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(-3, 0)
elif event.key == pygame.K_UP:
player.changespeed(0, 3)
elif event.key == pygame.K_DOWN:
player.changespeed(0, -3)
player.update()
all_sprites_list.draw(screen)
pygame.display.flip()
clock.tick(75)
pygame.quit ()
Recording the points of a very long path seems like a slow way of checking for hitting one's own tail.
If the background is a known colour, perhaps checking for non-background pixel colours in the area the player is about to move into.
It's possible to grab a single pixel colour with the Surface.get_at() function. This returns a RGBA colour, this colour can be compared against a single background colour (or the known background colour from a bitmap at that point), allowing collision to be decided.
In the player.update():
if (screen.get_at((player_next_x, player_next_y)) != BACKGROUND_COLOUR):
# player hit tail
Of course it may be necessary to check both corners of the player's sprite (in the direction of travel).

Pygame Program Execution Error

I'm making a pygame program to animate a sprite, but the problem isn't a particular error:
import sys
import os
import pygame
from pygame.locals import *
pygame.init ()
WHITE = ( 255, 255, 255 )
BLACK = ( 0, 0, 0 )
Surface = pygame.display.set_mode ((400, 400), 0, 32)
pygame.display.set_caption ('Animation Test')
class Processes (object):
#staticmethod
def load_image (imagefile):
image = pygame.image.load (imagefile) #Remember to call imagefile as a string statement
return image, image.get_rect ()
class Sprite (pygame.sprite.Sprite):
def __init__ (self):
pygame.sprite.Sprite.__init__ (self)
self.image, self.rect = Processes.load_image ('frame1.jpg')
self.blindrect = pygame.Rect ((self.rect.top - 289, self.rect.left - 289), (self.rect.width, self.rect.height))
def animation (self, key_event = None, mouse_event = None):
blindpass = 0
if key_event == K_LEFT:
self.rect.centerx = self.rect.centerx - 10
if key_event == K_RIGHT:
self.rect.centerx = self.rect.centerx + 10
if key_event == K_UP:
self.rect.centery = self.rect.centery - 10
if key_event == K_DOWN:
self.rect.centery = self.rect.centery + 10
if mouse_event == MOUSEBUTTONDOWN:
self.rect.centerx, self.rect.centery = pygame.mouse.get_pos ()
if blindpass > 0:
if key_event == K_LEFT:
self.blindrect.centerx = self.blindrect.centerx - 10
if key_event == K_RIGHT:
self.blindrect.centerx = self.blindrect.centerx + 10
if key_event == K_UP:
self.blindrect.centery = self.blindrect.centery - 10
if key_event == K_DOWN:
self.blindrect.centery = self.blindrect.centery + 10
if mouse_event == MOUSEBUTTONDOWN:
self.rect.centerx, self.rect.centery = pygame.mouse.get_pos ()
mecha = Sprite ()
allsprites = pygame.sprite.RenderPlain ((mecha, ))
while True:
Surface.fill (WHITE)
for event in pygame.event.get ():
if event.type == KEYDOWN:
mecha.animation (key_event = event.key)
if event.type == MOUSEBUTTONDOWN:
mecha.animation (mouse_event = event.type)
if event.type == QUIT:
pygame.quit ()
sys.exit (0)
allsprites.draw (Surface)
pygame.display.update ((mecha.rect, mecha.blindrect))
Now, the error is a bit weird. The output is that the sprite does appear on the screen, and it moves when I provide key and mouse input, but the problem is is that it's leaving trails. Which is why I created a rectangle to trail the sprite rectangle which is supposed to be filled with white every time the game loop loops. But it doesn't. At least, not until I minimize the window, and pull it up again, all the trails disappear and the background becomes white instead of black. But when I move the image, the trails start forming again. I minimize, they disappear as supposed to.
If your render function does:
screen.fill(white)
# blit or sprite group drawing
pygame.display.flip()
It will clear the entire screen in white, draw the sprites once. There won't be a trail.
Your code didn't pasted correctly. fLike your if QUIT statement has no indention, for a multi statement. The same with class Sprite
You might get naming problems if you use Surface or Sprite as your class/variable names.
You're not initializing and updating the blindrect correctly. That's why the correct portion of the screen is not being updated and your sprite is leaving a trail.
In your update loop, since you're only updating the portion of the display that changed, you need to update the entire screen once to initialize it before you go into the update loop. That's why the screen is not initially white.
See the updated source below (only the Sprite class and later was modified):
class Sprite (pygame.sprite.Sprite):
def __init__ (self):
pygame.sprite.Sprite.__init__ (self)
self.image, self.rect = Processes.load_image ('frame1.jpg')
#initialize blindrect to be the same rectangle as rect
self.blindrect = pygame.Rect ((self.rect.top, self.rect.left), (self.rect.width, self.rect.height))
def animation (self, key_event = None, mouse_event = None):
print(self.rect)
print(self.blindrect)
#save the current sprite position before moving the sprite
self.blindrect.centerx = self.rect.centerx
self.blindrect.centery = self.rect.centery
if key_event == K_LEFT:
self.rect.centerx = self.rect.centerx - 10
if key_event == K_RIGHT:
self.rect.centerx = self.rect.centerx + 10
if key_event == K_UP:
self.rect.centery = self.rect.centery - 10
if key_event == K_DOWN:
self.rect.centery = self.rect.centery + 10
if mouse_event == MOUSEBUTTONDOWN:
self.rect.centerx, self.rect.centery = pygame.mouse.get_pos ()
print(self.rect)
print(self.blindrect)
mecha = Sprite ()
allsprites = pygame.sprite.RenderPlain ((mecha, ))
#need to initially fill the entire surface with white
Surface.fill (WHITE)
pygame.display.update ((pygame.Rect((0,0),(400,400))))
while True:
Surface.fill (WHITE)
for event in pygame.event.get ():
if event.type == KEYDOWN:
mecha.animation (key_event = event.key)
if event.type == MOUSEBUTTONDOWN:
mecha.animation (mouse_event = event.type)
if event.type == QUIT:
pygame.quit ()
sys.exit (0)
allsprites.draw (Surface)
#update only the previous sprite position and new sprite position
pygame.display.update ((mecha.rect, mecha.blindrect))

Categories