How to rotate an image without losing pixel data? (Pygame) - python

Here's my code (Python 3.5):
import sys
import pygame
pygame.init()
screen_width = 640
screen_height = 480
screen = pygame.display.set_mode((screen_width, screen_height))
running = True
class Actor:
def __init__(self, x, y, w, h):
self.x = x
self.y = y
self.w = w
self.h = h
self.surface = pygame.image.load("GFX/player.bmp")
def draw(self):
screen.blit(self.surface, (self.x, self.y))
class Player(Actor):
def __init__(self):
Actor.__init__(self, 0, 0, 32, 32)
self.directions = [False, False, False, False]
self.speed = 0.1
def update(self):
if self.directions[0]:
self.y -= self.speed
if self.directions[1]:
self.y += self.speed
if self.directions[2]:
self.x -= self.speed
if self.directions[3]:
self.x += self.speed
player = Player()
def rot_center(image, angle):
orig_rect = image.get_rect()
rot_image = pygame.transform.rotate(image, angle)
rot_rect = orig_rect.copy()
rot_rect.center = rot_image.get_rect().center
rot_image = rot_image.subsurface(rot_rect).copy()
return rot_image
def redraw():
screen.fill((75, 0, 0))
player.draw()
player.update()
pygame.display.flip()
while (running):
for e in pygame.event.get():
if e.type == pygame.QUIT:
sys.exit()
elif e.type == pygame.KEYDOWN:
if e.key == pygame.K_ESCAPE:
sys.exit()
if e.key == pygame.K_w:
player.directions[0] = True
if e.key == pygame.K_s:
player.directions[1] = True
if e.key == pygame.K_a:
player.directions[2] = True
if e.key == pygame.K_d:
player.directions[3] = True
elif e.type == pygame.KEYUP:
if e.key == pygame.K_w:
player.directions[0] = False
if e.key == pygame.K_s:
player.directions[1] = False
if e.key == pygame.K_a:
player.directions[2] = False
if e.key == pygame.K_d:
player.directions[3] = False
elif e.type == pygame.MOUSEMOTION:
player.surface = rot_center(player.surface, pygame.mouse.get_pos()[0] / 64)
redraw()
Pretty straightforward pygame code. I have a player with a simple image that I've created on mspaint, and I've used this function to rotate the image without causing out of memory issues. I'm rotating the image with the mouse (Considering a player that "aims" somewhere). Here's the original image:
And here's the extremely ugly result after moving the mouse a little:
I know I'd have better precision using OpenGL (Pyglet, for example), but in that case the rotation function from pygame would be completely useless. What am I missing? What am I doing wrong?

Keep in mind that Surfaces in Python are just grids of pixels, not mathematically perfect vector graphics. Rotating an image will cause slight destruction of quality. Continually doing so will eventually garble the image beyond recognition as you can see in your picture. Maintain a reference to the original image and never overwrite it. When you call rotate, make sure you are rotating the original picture with the cumulative angle with respect to the original, not a previously and incrementally rotated version.

Related

Pygame: How do I slowly fade and kill a sprite?

When I run this code sprite.spritecollide(a,group,True) the sprite is removed from the screen. But it disappears instantly. How do I apply a fading effect to it? I want it to slowly fade out before it gets removed completely. I have read the documentation, but still not sure how to do it.
You can make a per-pixel alpha surface transparent by filling it with white (with the desired alpha value) and also pass the pygame.BLEND_RGBA_MULT special flag. Add a self.fade attribute to your sprite subclass and set it to True to start the effect, then reduce the alpha value each frame, make a copy of the original image and make it transparent. Kill the sprite when the alpha is <= 0.
import pygame as pg
from pygame.math import Vector2
pg.init()
PLAYER_IMAGE = pg.Surface((42, 68), pg.SRCALPHA)
PLAYER_IMAGE.fill(pg.Color('dodgerblue'))
class Entity(pg.sprite.Sprite):
def __init__(self, pos, *groups):
super().__init__(*groups)
self.image = PLAYER_IMAGE
self.rect = self.image.get_rect(center=pos)
self.vel = Vector2(0, 0)
self.pos = Vector2(pos)
self.alpha = 255
self.fade = False
def update(self):
self.pos += self.vel
self.rect.center = self.pos
if self.fade: # If the fade effect is activated.
# Reduce the alpha each frame, create a new copy of the original
# image and fill it with white (with the self.alpha value)
# and pass the BLEND_RGBA_MULT special_flag to reduce the alpha.
self.alpha = max(0, self.alpha-5) # alpha should never be < 0.
self.image = PLAYER_IMAGE.copy()
self.image.fill((255, 255, 255, self.alpha), special_flags=pg.BLEND_RGBA_MULT)
if self.alpha <= 0: # Kill the sprite when the alpha is <= 0.
self.kill()
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
entity = Entity((250, 170), all_sprites)
entity2 = Entity((350, 270), all_sprites)
group = pg.sprite.Group(entity2)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_d:
entity.vel.x = 5
elif event.key == pg.K_a:
entity.vel.x = -5
elif event.key == pg.K_w:
entity.vel.y = -5
elif event.key == pg.K_s:
entity.vel.y = 5
elif event.key == pg.K_SPACE:
entity.fade = True # Start the fade effect.
elif event.type == pg.KEYUP:
if event.key == pg.K_d and entity.vel.x > 0:
entity.vel.x = 0
elif event.key == pg.K_a and entity.vel.x < 0:
entity.vel.x = 0
elif event.key == pg.K_w:
entity.vel.y = 0
elif event.key == pg.K_s:
entity.vel.y = 0
all_sprites.update()
collided = pg.sprite.spritecollide(entity, group, False)
for sprite in collided:
sprite.fade = True # Start the fade effect.
screen.fill((30, 30, 30))
all_sprites.draw(screen)
pg.display.flip()
clock.tick(60)
pg.quit()
if __name__ == '__main__':
main()

How to make your character move without tapping repeatedly on buttons?

I'm working on a racing game. I have been using this code but my player keeps moving once only. How do I solve this problem?
change = 7
dist = 7
change_r = 0
change_l = 0
dist_u = 0
dist_d = 0
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
change_r = True
elif event.key == pygame.K_LEFT:
change_l = True
elif event.key == pygame.K_UP:
dist_u = True
elif event.key == pygame.K_DOWN:
dist_d = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or event.key == pygame.K_LEFT or event.key == pygame.K_UP or event.key == pygame.K_DOWN:
change_r = False
change_l = False
dist_u = False
dist_d = False
clock.tick(60)
if change_r == True:
x += change
if change_l == True:
x -= change
if dist_u == True:
y -= dist
if dist_d == True:
y += dist
There are different ways you could go about making move-able shapes/sprites using Pygame. The code you posted in your question seems overly complex. I'll give you two different ways that are simpler, and easier to use. Using a sprite class, and using a function.
It may not seem like I'm answering your question, but if I just told you what to fix in your code you posted, I'd just be knowingly steering you down a road that will lead to many problems, and much complexity in the future.
Method 1: Using a sprite class
To make a your race car sprite, you could use a sprite class like the one below.
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 50))
self.image.fill((255, 0, 0))
self.rect = self.image.get_rect()
self.rect.x = WIDTH / 2
self.rect.y = HEIGHT / 2
self.vx = 0
self.vy = 0
def update(self):
self.vx = 0
self.vy = 0
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
self.vx = -5
elif key[pygame.K_RIGHT]:
self.vx = 5
if key[pygame.K_UP]:
self.vy = -5
elif key[pygame.K_DOWN]:
self.vy = 5
self.rect.x += self.vx
self.rect.y += self.vy
Since your class is inheriting from Pygame's sprite class, You must name your image self.image and you must name your rectangle for the image self.rect. As you can also see, the class has two main methods. One for creating the sprite(__init__) and one for updating the sprite(update)
To use your class, make a Pygame sprite group to hold all your sprites, and then add your player object to the group:
sprites = pygame.sprite.Group()
player = Player()
sprtites.add(player)
And to actual render your sprites to the screen call sprites.update() and sprites.draw() in your game loop, where you update the screen:
sprites.update()
window_name.fill((200, 200, 200))
sprites.draw(window_name)
pygame.display.flip()
The reason i highly recommended using sprite classes, is that it will make your code look much cleaner, and be much easier to maintain. You could even move each sprite class to their own separate file.
Before diving fully into the method above however, you should read up on pygame.Rect objects and pygame.sprite objects, as you'll be using them.
Method 2: Using A function
If you prefer not to get into sprite classes, you can create your game entities using a function similar to the one below.
def create_car(surface, x, y, w, h, color):
rect = pygame.Rect(x, y, w, h)
pygame.draw.rect(surface, color, rect)
return rect
If you would still like to use a sprites, but don't want to make a class just modify the function above slightly:
def create_car(surface, x, y, color, path_to_img):
img = pygame.image.load(path_to_img)
rect = img.get_rect()
surface.blit(img, (x, y))
Here is an example of how i would use the functions above to make a movable rectangle/sprite:
import pygame
WIDTH = 640
HEIGHT = 480
display = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Moving Player Test")
clock = pygame.time.Clock()
FPS = 60
def create_car(surface, x, y, w, h, color):
rect = pygame.Rect(x, y, w, h)
pygame.draw.rect(surface, color, rect)
return rect
running = True
vx = 0
vy = 0
player_x = WIDTH / 2 # middle of screen width
player_y = HEIGHT / 2 # middle of screen height
player_speed = 5
while running:
clock.tick(FPS)
for e in pygame.event.get():
if e.type == pygame.QUIT:
running = False
pygame.quit()
quit()
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_LEFT:
vx = -player_speed
elif e.key == pygame.K_RIGHT:
vx = player_speed
if e.key == pygame.K_UP:
vy = -player_speed
elif e.key == pygame.K_DOWN:
vy = player_speed
if e.type == pygame.KEYUP:
if e.key == pygame.K_LEFT or e.key == pygame.K_RIGHT or\
e.key == pygame.K_UP or e.key == pygame.K_DOWN:
vx = 0
vy = 0
player_x += vx
player_y += vy
display.fill((200, 200, 200))
####make the player#####
player = create_car(display, player_x, player_y, 10, 10, (255, 0, 0))
pygame.display.flip()
As you may see above, your code for moving your race car can be simplified.
I should note, I'm assuming a few things with each method outlined above.
That your either using a circle, square, or some type of pygame shape object.
Or that your using a sprite.
If your not currently using any of the methods outlined above, I suggest that you do. Doing so will make your code much eaiser to maintain once you begin to build larger and more complex games.
You should have a global loop irrespective of your event handling. You should place your clock.tick() and your movement there. Namely:
#some constants here
while True:
pygame.display.update()
clock.tick(60)
#update you game state
if change_r == True:
x += change
if change_l == True:
x -= change
if dist_u == True:
y -= dist
if dist_d == True:
y += dist
for event in pygame.event.get():
# react to player input by changing the game state

Pygame animation using mutiple images overlapping/not working

import pygame
pygame.init()
window = pygame.display.set_mode((800,600))
pygame.display.set_caption("TEST2")
black=(0,0,0)
white=(255,255,255)
moveX,moveY=0,0
clock = pygame.time.Clock()
class Sprite:
def __init__(self,x,y):
self.x=x
self.y=y
self.width=100
self.height=110
self.i100 = pygame.image.load("C:/Users/Trevor/SkyDrive/Documents/TEST2.0/Sprite0.PNG")
self.i1 = pygame.image.load("C:/Users/Trevor/SkyDrive/Documents/TEST2.0/Sprite1.PNG")
self.i2 = pygame.image.load("C:/Users/Trevor/SkyDrive/Documents/TEST2.0/Sprite2.PNG")
self.i3 = pygame.image.load("C:/Users/Trevor/SkyDrive/Documents/TEST2.0/Sprite3.PNG")
self.i4 = pygame.image.load("C:/Users/Trevor/SkyDrive/Documents/TEST2.0/Sprite4.PNG")
self.i5 = pygame.image.load("C:/Users/Trevor/SkyDrive/Documents/TEST2.0/Sprite5.PNG")
self.i6 = pygame.image.load("C:/Users/Trevor/SkyDrive/Documents/TEST2.0/Sprite6.PNG")
self.i7 = pygame.image.load("C:/Users/Trevor/SkyDrive/Documents/TEST2.0/Sprite7.PNG")
self.i8 = pygame.image.load("C:/Users/Trevor/SkyDrive/Documents/TEST2.0/Sprite8.PNG")
self.i9 = pygame.image.load("C:/Users/Trevor/SkyDrive/Documents/TEST2.0/Sprite9.PNG")
self.i10 = pygame.image.load("C:/Users/Trevor/SkyDrive/Documents/TEST2.0/Sprite10.PNG")
self.i11 = pygame.image.load("C:/Users/Trevor/SkyDrive/Documents/TEST2.0/Sprite11.PNG")
self.timeTarget=10
self.timeNum=0
self.currentImage=0
def update(self):
self.timeNum+=1
if(self.timeNum==self.timeTarget):
if (self.currentImage==0):
self.currentImage+=1
else:
self.currentImage=0
self.timeNum=0
self.render()
def render(self):
if (self.currentImage==0):
window.blit(self.i100, (self.x,self.y))
else:
window.blit(self.i1, (self.x,self.y))
window.blit(self.i2, (self.x,self.y))
window.blit(self.i3, (self.x,self.y))
player=Sprite(110,100)
gameLoop = True
while gameLoop:
for event in pygame.event.get():
if event.type==pygame.QUIT:
gameLoop = False
if (event.type==pygame.KEYDOWN):
if (event.key==pygame.K_LEFT):
moveX = -3
if (event.key==pygame.K_RIGHT):
moveX = 3
if (event.key==pygame.K_UP):
moveY = -3
if (event.key==pygame.K_DOWN):
moveY = 3
if (event.type==pygame.KEYUP):
if (event.key==pygame.K_LEFT):
moveX=0
if (event.key==pygame.K_RIGHT):
moveX=0
if (event.key==pygame.K_UP):
moveY=0
if (event.key==pygame.K_DOWN):
moveY=0
window.fill(black)
player.x+=moveX
player.x+=moveY
player.update()
clock.tick(50)
pygame.display.flip()
pygame.quit()
What im doing is trying to animate 11 photos into an animation with pygame. this code works but when I run it the pictures seem to almost overlap. I did window.blit for the first few images and put them under else? I feel like I rendered them wrong. also I must add im really bad at picking up what people are trying to say and best learn from examples. Thanks!
BTW: your code could look like this:
I use my images in example but there are still lines with your images.
I use timer to change images.
You can press space to pause and escape to exit.
etc.
import pygame
#----------------------------------------------------------------------
class Sprite:
def __init__(self, x, y, curren_time):
self.rect = pygame.Rect(x, y, 100, 110)
self.images = []
#for x in range(12):
for x in range(1,4):
img = pygame.image.load("ball" + str(x) +".png")
#img = pygame.image.load("C:/Users/Trevor/SkyDrive/Documents/TEST2.0/Sprite" + str(x) +".PNG")
self.images.append( img )
self.current_image = 0
self.time_num = 100 # miliseconds
self.time_target = curren_time + self.time_num
def update(self, curren_time):
if curren_time >= self.time_target:
self.time_target = curren_time + self.time_num
self.current_image += 1
if self.current_image == len(self.images):
self.current_image = 0
def render(self, window):
window.blit(self.images[self.current_image], self.rect)
#----------------------------------------------------------------------
# CONSTANS - uppercase
BLACK = (0 ,0 ,0 )
WHITE = (255,255,255)
#----------------------------------------------------------------------
# MAIN
def main():
pygame.init()
window = pygame.display.set_mode((800,600))
pygame.display.set_caption("TEST2")
move_x, move_y = 0, 0
clock = pygame.time.Clock()
curren_time = pygame.time.get_ticks()
player = Sprite(110,100, curren_time)
font = pygame.font.SysFont(None, 150)
pause_text = font.render("PAUSE", 1, WHITE)
pause_rect = pause_text.get_rect( center = window.get_rect().center ) # center text on screen
# mainloop
state_game = True
state_pause = False
while state_game:
curren_time = pygame.time.get_ticks()
# events
for event in pygame.event.get():
if event.type == pygame.QUIT:
state_game = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
state_game = False
elif event.key == pygame.K_SPACE:
state_pause = not state_pause
if event.key == pygame.K_LEFT:
move_x = -3
elif event.key == pygame.K_RIGHT:
move_x = 3
elif event.key == pygame.K_UP:
move_y = -3
elif event.key == pygame.K_DOWN:
move_y = 3
elif event.type == pygame.KEYUP:
if event.key in (pygame.K_LEFT, pygame.K_RIGHT):
move_x = 0
elif event.key in (pygame.K_UP, pygame.K_DOWN):
move_y = 0
# moves
if not state_pause:
player.rect.x += move_x
player.rect.y += move_y
player.update(curren_time)
# draws
window.fill(BLACK)
player.render(window)
if state_pause:
window.blit(pause_text, pause_rect)
pygame.display.flip()
# FPS
clock.tick(50)
# the end
pygame.quit()
#----------------------------------------------------------------------
if __name__ == '__main__':
main()
ball1.png
ball2.png
ball3.png
By putting all those window.blit(...) calls one after another, you are drawing those three frames on top of each other. Even if your computer lagged for a second between each call, you still wouldn't see them individually because they all can't appear until pygame.display.flip() is called.
You should store the images in a list, and keep a counter like currentFrame that loops from 0 to number_of_frames-1 (or len(frames)-1). Then each frame of the game you do something like this:
class Player:
...
def draw(window):
window.blit(self.frames[self.currentFrame])

Pygame sprite touching

I am attempting to build a simple game with two sprites. I can't figure out how to add code that detects if a sprite is touching the other. I am also having trouble understanding the countless tutorials on this topic. If you could try and explain this to me as simply as possible that would be amazing!
import pygame
import sys
from pygame.locals import *
pygame.init()
black = (0, 0, 0)
white = (255, 255, 255)
bg = black
square = pygame.image.load('square.png')
square1 = pygame.image.load('square1.png')
screen = pygame.display.set_mode((640, 400))
UP = 'UP'
DOWN = 'DOWN'
LEFT = 'LEFT'
RIGHT = 'RIGHT'
direction = RIGHT
movex, movey, movex1, movey1 = 100, 100, 200, 200
class player1(pygame.sprite.Sprite):
"""Player 1"""
def __init__(self, xy):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('square.png')
self.rect = self.image.get_rect()
class player2(pygame.sprite.Sprite):
"""Player 2"""
def __init__(self, xy):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('square1.png')
self.rect = self.image.get_rect()
while True:
screen.fill(black)
collide = pygame.sprite.collide_mask(player1, player2)
if collide == True:
print 'collision!'
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_w:
movey -= 10
elif event.key == K_s:
movey += 10
elif event.key == K_a:
movex -= 10
elif event.key == K_d:
movex += 10
if event.key == K_UP:
movey1 -= 10
elif event.key == K_DOWN:
movey1 += 10
elif event.key == K_LEFT:
movex1 -= 10
elif event.key == K_RIGHT:
movex1 += 10
if event.type == QUIT:
pygame.quit()
sys.exit()
screen.blit(square, (movex, movey))
screen.blit(square1, (movex1, movey1))
pygame.display.update()
Some issues first:
pygame.sprite.collide_mask never returns True. It returns a point or None. So your check collide == True will never be evaluate to True
pygame.sprite.collide_mask excepts two Sprite instances, but you call it with class objects as arguments (collide_mask(player1, player2))
You only need pygame.sprite.collide_mask when you want to do pixel perfect collision detection
You actually don't use the classes player1 and player2 in the rest of your code
If you're using the Sprite class, a simply way for collision detection is to use the Group class. But since you only have two Sprites, you can simple check for an intersection of their Rects using colliderect.
I've updated your code to make use of the Sprite class:
import pygame
import sys
from pygame.locals import *
pygame.init()
black = (0, 0, 0)
white = (255, 255, 255)
screen = pygame.display.set_mode((640, 400))
class Player(pygame.sprite.Sprite):
def __init__(self, image, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image)
self.rect = self.image.get_rect(x=x, y=y)
player1, player2 = Player('square.png', 100, 100), Player('square1.png', 200, 200)
players = pygame.sprite.Group(player1, player2)
while True:
screen.fill(black)
if player1.rect.colliderect(player2.rect):
print 'collision!'
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_w:
player1.rect.move_ip(0, -10)
elif event.key == K_s:
player1.rect.move_ip(0, 10)
elif event.key == K_a:
player1.rect.move_ip(-10, 0)
elif event.key == K_d:
player1.rect.move_ip(10, 0)
if event.key == K_UP:
player2.rect.move_ip(0, -10)
elif event.key == K_DOWN:
player2.rect.move_ip(0, 10)
elif event.key == K_LEFT:
player2.rect.move_ip(-10, 0)
elif event.key == K_RIGHT:
player2.rect.move_ip(10, 0)
if event.type == QUIT:
pygame.quit()
sys.exit()
players.draw(screen)
pygame.display.update()
Collision detection is a broad topic, but this should get you started.

pygame sprite not moving

I'm faced with a logic error where the sprite simply doesn't move regardless of input.
My code will be below so no context is left out, it's fairly short.
Is there a better way of moving the sprite apart from the blit?
I've seen somewhere stuff about updating the sprite or some such, done quite differently to simply blitting it.
import pygame
pygame.init()
import random
import math
screen=pygame.display.set_mode([700,400])
black = ( 0, 0, 0)
white = ( 255, 255, 255)
red = ( 255, 0, 0)
player_x=350
player_y=200
player_x_vel=0
player_y_vel=0
rot_player=pygame.image
pi=math.pi
class Player(pygame.sprite.Sprite):
def __init__(self):
global player
pygame.sprite.Sprite.__init__(self)
self.pos=(350,200)
self.image=pygame.image.load("arrowtest.png").convert()
self.rect=self.image.get_rect()
screen=pygame.display.get_surface()
self.area=screen.get_rect()
self.speed=10
self.state="still"
self.reinit()
def reinit(self):
self.state="still"
self.movepos=[0,0]
def update(self):
newpos=self.rect.move(self.movepos)
if self.area.contains(newpos):
self.rect=newpos
pygame.event.pump()
def moveup(self):
self.movepos[1]-=(self.speed)
self.state="moveup"
def movedown(self):
self.movepos[1]+=(self.speed)
self.state="movedown"
def moveleft(self):
self.movepos[0]-=(self.speed)
self.state="moveleft"
def moveright(self):
self.movepos[0]+=(self.speed)
self.state="moveright"
def moveupright(self):
self.movepos[1]-=(self.speed)
self.movepos[0]+=(self.speed)
def moveupleft(self):
self.movepos[1]-=(self.speed)
self.movepos[0]-=(self.speed)
def movedownright(self):
self.movepos[1]+=(self.speed)
self.movepos[0]+=(self.speed)
def movedownleft(self):
self.movepos[1]+=(self.speed)
self.movepos[0]-=(self.speed)
def angleplayer(self):
mouse_pos=pygame.mouse.get_pos()
dx=mouse_pos[0]-player_x
dy=mouse_pos[1]-player_y
rads=math.atan2(-dy, dx)
rads %= 2*pi
angle = math.degrees(rads)
print angle
rot_player.image=pygame.transform.rotate(player.image, angle-90)
done=False
clock=pygame.time.Clock()
while done==False:
player = Player()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done=True
if event.type == pygame.MOUSEBUTTONDOWN:
fired_pos=pygame.mouse.get_pos()
fired=True
if event.type == pygame.KEYDOWN:
player.angleplayer()
if event.key == pygame.K_w:
player.moveup()
if event.key == pygame.K_s:
player.movedown()
if event.key == pygame.K_a:
player.moveleft()
if event.key == pygame.K_d:
player.moveright()
print "co ords", player_x,player_y
print "x vel", player_x_vel
print "y vel", player_y_vel
if event.type == pygame.KEYUP:
player.movepos=[0,0]
player.state="still"
player.angleplayer()
screen.fill(white)
screen.blit(player.image, player.pos)
clock.tick(20)
pygame.display.flip()
pygame.quit()
Thanks in advance
First of all, you are creating a new player every iteration of your main loop:
...
while done == False:
player = Player()
...
You want to create the player once, so move the creation outside the loop:
...
player = Player()
while not done:
...
Second: To get the position of the player, you use player.pos:
...
screen.blit(player.image, player.pos)
...
but you never update player.pos (it's always (350,200)), you only change self.rect:
def update(self):
newpos=self.rect.move(self.movepos)
if self.area.contains(newpos):
self.rect=newpos
pygame.event.pump()
either use player.rect to get the player position, or update player.pos accordingly:
def update(self):
newpos=self.rect.move(self.movepos)
if self.area.contains(newpos):
self.rect = newpos
self.pos = self.rect.topleft
# don't call pygame.event.pump() here. Doesn't make any sense :-)
Third, you update the player position in the update function, but you never call it. Call it before drawing the player:
...
while not done:
...
player.update()
screen.fill(white)
screen.blit(player.image, player.pos)
...
You can simplify your code alot by setting movepos directly and removing the move... functions.
working example:
import pygame
pygame.init()
colors = pygame.color.THECOLORS
screen = pygame.display.set_mode([700,400])
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.surface.Surface((32,32))
self.image.fill(colors['green'])
self.rect = self.image.get_rect().move(350, 200)
self.speed = 4
def update(self):
dx, dy = self.movepos[0] * self.speed, self.movepos[1] * self.speed
self.rect = self.rect.move(dx, dy)
done=False
clock = pygame.time.Clock()
player = Player()
while not done:
if pygame.event.get(pygame.QUIT):
break
pressed = pygame.key.get_pressed()
l, r, u, d = [pressed[k] for k in pygame.K_a, pygame.K_d, pygame.K_w, pygame.K_s]
player.movepos = -l + r, -u + d
player.update()
screen.fill(colors['white'])
screen.blit(player.image, player.rect.topleft)
pygame.display.flip()
clock.tick(60)
You have a lot of move functions. Try combining them into a simple two function class like this example:
class Puck(pygame.sprite.Sprite):
def __init__(self, image_file, speed, location):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
The two main controllers are the self.rect.left and self.rect.top. By changing their values, you can move the sprites like in this example.
#Name of varible# = Puck('#Image File#', [#value of self.rect.left#, value of self.rect.top]
Then you can use events to change them like:
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
exit(0)
elif event.type == pygame.KEYDOWN:
if event.key == K_UP:
random.rect.top =random.rect.top - 75
elif event.key == K_LEFT:
random.rect.left = random.rect.left - 75
elif event.key == K_DOWN:
random.rect.top = random.rect.top + 75
elif event.key == K_RIGHT:
randoml.rect.left = randoml.rect.left + 75
elif event.key == K_w:
random.rect.top = random.rect.top - 50
elif event.key == K_a:
random.rect.left = random.rect.left - 50
elif event.key == K_s:
random.rect.top = random.rect.top + 50
elif event.key == K_d:
random.rect.left = random.rect.left + 50
This should be able to move your sprite.

Categories

Resources