What works:
1) the ship and background load without hitch.
2) ship movement is functioning
3) I was able to keep the ship from being able to exit the field of view
4) the program creates pixels(to emulate bullets) at the KEYDOWN event of K_SPACEBAR
What I need help with:
1)Despite my best efforts after creating the "bullets" the sprites wont animate
2) The sprites intended to represent debris won't even create let alone animate
3) of course this means I can't even test my unit collision betwen bullets and debris
4) don't know how to begin tackling debris (sprite) detection with the ship
5) For some reason the bullet sprites render to the left of the ship. Not sure where/how to manipulate their x value
Code as it stands:
I've left notes all over the place to help explain my madness
bif="bg.jpg"
ship = "spaceship.png"
import pygame, sys
from pygame import *
from pygame.locals import *
import random
pygame.init()
yellow=(255,255,51)
green=(50,190,50)
difficulty = 10
i=0
debris_list=pygame.sprite.Group()
bullet_list=pygame.sprite.Group()
class Square(pygame.sprite.Sprite):#makes squares
def __init__(self, color):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface ([7,7])
self.image.fill(color)
self.rect=self.image.get_rect()
class Bullet(pygame.sprite.Sprite): #bullet creation
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image= pygame.Surface([7,7])
self.image.fill(yellow)
self.rect= self.image.get_rect()
def update(self): #sprite movement
if bullet:
self.rect.y-=5
if debris:
self.rect.y+=5
class debris(pygame.sprite.Sprite): #debris creation
def __init__(self,color):
pygame.sprite.Sprite.__init__(self)
self.image= pygame.Surface([15,15])
self.image.fill(green)
self.rect= self.image.get_rect()
window =pygame.display.set_caption("Space Explorer")
clock=pygame.time.Clock()
speed=250
screen = pygame.display.set_mode((800,600),0,32)
x,y =0,0
movex,movey= 0,0
background = pygame.image.load(bif).convert() # puts background on screen
ship_pos=pygame.image.load(ship).convert_alpha() #loads player ship
while True:
for event in pygame.event.get():
if event.type == QUIT: #escape functionality
pygame.quit()
sys.exit()
if event.type == KEYDOWN: #ship movement
if event.key == K_LEFT:
movex=-1
elif event.key == K_RIGHT:
movex=+1
elif event.key ==K_UP:
movey=-1
elif event.key ==K_DOWN:
movey=+1
elif event.key == K_a:
movex=-1
elif event.key == K_d:
movex=+1
elif event.key ==K_w:
movey=-1
elif event.key ==K_s:
movey=+1
if event.type==KEYUP:
if event.key == K_LEFT:
movex=0
elif event.key == K_RIGHT:
movex=0
elif event.key ==K_UP:
movey=0
elif event.key ==K_DOWN:
movey=0
elif event.key == K_a:
movex=0
elif event.key == K_d:
movex=0
elif event.key ==K_w:
movey=0
elif event.key ==K_s:
movey=0
if event.type == KEYDOWN:#player input bullet creation:
if event.key==K_SPACE:
bullet = Bullet()
bullet.rect.x=x
bullet.rect.y=y
bullet_list.add(bullet)
#hit tracking and score
#no collision detection for debris and ship yet.
for bullet in bullet_list:
debris_hit_list=pygame.sprite.spritecollide(bullet,debris_list,True)
for debris in debris_hit_list:
bullet_list.remove(bullet)
score+1
print score
if bullet.rect.y<10:
bullet_list.remove(bullet)#stop tracking rogue bullets
#debris spawn location and rate
#every 10 iterations "debris" should spawn randomly on the x axis
#and move downwards
if i == difficulty:
debris = Square(green)
debris.rect.x= random.randrange(800)
debris.rect.y=-700
debris_list.add(debris)
i=0
i=i+1
bullet_list.update()
debris_list.update()
#keeps ship within screen
if x >=680:
x=680
if x <= 5:
x=5
if y >=500:
y= 500
if y <=5:
y=5
x+=movex
y+=movey
bullet_list.draw(screen)
debris_list.draw(screen)
screen.blit(background, (0,0))
screen.blit(ship_pos,(x,y))
pygame.display.update()
(Sorry for my english)
1) In Bullet.update() you use
if bullet:
self.rect.y-=5
if debris:
self.rect.y+=5
But the objects bullet and debris are
A: Not defined (at the beginning of the code)
B: return false (I think)
But if they would both return true the bullet stays in the same place.
2) The debris class is never used (you use the rect class)
The debris y = -700 what is ABOVE the screen
3) I think the coliding works
4) Define a Ship_Rect and do
for d in debris_list:
if Ship_Rect.colliderect(d.rect):
//Stuff to do when ship collides debris
5) The X and Y of an object are in the top left corner you should do:
bullet.rect.x= x + (Ship_Rect.heigth/2)
bullet.rect.y= y + (Ship_Rect.length/2)
Related
I simply want to save the mouse position at every instant. Why is this simple code not working?
import pygame
screen = pygame.display.set_mode((500,500))
screen.fill((255,255,255))
while True:
ev = pygame.event.get()
for event in ev:
pos = pygame.mouse.get_pos()
if event.type != pygame.NOEVENT:
mouse_pos = pygame.mouse.get_pos()
x, y = event.mouse_pos
print(x, y)
The mouse position can be tracked outside of the event processing loop.
import pygame
import sys
screen = pygame.display.set_mode((500,500))
screen.fill((255,255,255))
last_pos = (-1,-1)
while True:
# handle user events
ev = pygame.event.get()
for event in ev:
if event.type == pygame.QUIT:
sys.exit()
# track the mouse co-ords
mouse_pos = pygame.mouse.get_pos()
if ( mouse_pos != last_pos ):
x,y = mouse_pos
print(x, y)
last_pos = mouse_pos
It's known that if you move a sprite without filling the screen before it leaves a trail, however, I want to leave a cool trail behind my while moving other stuff (which means I cannot simply stop filling the screen.
Thanks in advance for any help
One solution would be to create another transparent surface (called alpha_surf here) with the size of the screen onto which you blit the objects with trails. It needs to be a per-pixel alpha surface which you can create by passing the pygame.SRCALPHA special flag.
Blit the objects and reduce the alpha of all pixels on the alpha_surf each frame by filling it with a transparent white and also pass the pygame.BLEND_RGBA_MULT flag so that only the alpha channel is affected.
import pygame as pg
from pygame.math import Vector2
class Player(pg.sprite.Sprite):
def __init__(self, pos, *groups):
super().__init__(*groups)
self.image = pg.Surface((50, 50), pg.SRCALPHA)
pg.draw.circle(self.image, pg.Color('dodgerblue'), (25, 25), 25)
self.rect = self.image.get_rect(center=pos)
self.vel = Vector2(0, 0)
self.pos = Vector2(pos)
def update(self):
self.pos += self.vel
self.rect.center = self.pos
def main():
pg.init()
screen = pg.display.set_mode((640, 480))
# Blit objects with trails onto this surface instead of the screen.
alpha_surf = pg.Surface(screen.get_size(), pg.SRCALPHA)
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
player = Player((150, 150), all_sprites)
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
return
elif event.type == pg.KEYDOWN:
if event.key == pg.K_d:
player.vel.x = 5
elif event.key == pg.K_a:
player.vel.x = -5
elif event.key == pg.K_w:
player.vel.y = -5
elif event.key == pg.K_s:
player.vel.y = 5
elif event.type == pg.KEYUP:
if event.key == pg.K_d and player.vel.x > 0:
player.vel.x = 0
elif event.key == pg.K_a and player.vel.x < 0:
player.vel.x = 0
elif event.key == pg.K_w:
player.vel.y = 0
elif event.key == pg.K_s:
player.vel.y = 0
# Reduce the alpha of all pixels on this surface each frame.
# Control the fade speed with the alpha value.
alpha_surf.fill((255, 255, 255, 220), special_flags=pg.BLEND_RGBA_MULT)
all_sprites.update()
screen.fill((20, 50, 80)) # Clear the screen.
all_sprites.draw(alpha_surf) # Draw the objects onto the alpha_surf.
screen.blit(alpha_surf, (0, 0)) # Blit the alpha_surf onto the screen.
pg.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
pg.quit()
Alternatively, you could create several versions of the sprite image with different alpha values and also store the previous positions of the sprite. Then just blit the images with lower alpha at the previous positions.
You can also blit other images or particles instead of the self.image if you want to create a different kind of trail, for example smoke.
Here's another variant with a separate, different image for the trail which gets blitted before the self.images of the sprites are blitted, so that it'll appear below them:
import pygame as pg
from pygame.math import Vector2
class Player(pg.sprite.Sprite):
def __init__(self, pos, *groups):
super().__init__(*groups)
self.image = pg.Surface((50, 70), pg.SRCALPHA)
self.image.fill(pg.Color('sienna1'))
self.rect = self.image.get_rect(center=pos)
# A separate image for the trail (just a single-color circle).
self.trail_image = pg.Surface((40, 40), pg.SRCALPHA)
pg.draw.circle(self.trail_image, pg.Color('dodgerblue'), (20, 20), 20)
self.trail_rect = self.trail_image.get_rect()
self.vel = Vector2(0, 0)
self.pos = Vector2(pos)
def update(self):
self.pos += self.vel
self.rect.center = self.pos
# Update the rect of the trail as well, because we'll blit it there.
self.trail_rect.center = self.rect.center
def main():
pg.init()
screen = pg.display.set_mode((640, 480))
# Blit objects with trails onto this surface instead of the screen.
alpha_surf = pg.Surface(screen.get_size(), pg.SRCALPHA)
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
sprites_with_trails = pg.sprite.Group()
player = Player((150, 150), all_sprites, sprites_with_trails)
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
return
elif event.type == pg.KEYDOWN:
if event.key == pg.K_d:
player.vel.x = 5
elif event.key == pg.K_a:
player.vel.x = -5
elif event.key == pg.K_w:
player.vel.y = -5
elif event.key == pg.K_s:
player.vel.y = 5
elif event.type == pg.KEYUP:
if event.key == pg.K_d and player.vel.x > 0:
player.vel.x = 0
elif event.key == pg.K_a and player.vel.x < 0:
player.vel.x = 0
elif event.key == pg.K_w:
player.vel.y = 0
elif event.key == pg.K_s:
player.vel.y = 0
# Reduce the alpha of all pixels on this surface each frame.
# Control the fade speed with the alpha value.
alpha_surf.fill((255, 255, 255, 244), special_flags=pg.BLEND_RGBA_MULT)
all_sprites.update()
screen.fill((20, 50, 80)) # Clear the screen.
# Blit the trails onto the alpha_surf.
for sprite in sprites_with_trails:
alpha_surf.blit(sprite.trail_image, sprite.trail_rect)
screen.blit(alpha_surf, (0, 0)) # Blit the alpha_surf onto the screen.
all_sprites.draw(screen) # Draw the objects onto the alpha_surf.
pg.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
pg.quit()
I'm currently trying to create a simple version of the game Breakout with Pygame. The problem is that I want to make my bat move on the screen, and for this I need to deal with events and the fact that, when you press the right/left arrow, the bat instantly moves right/left. However my code is not working; the length of the bat is increasing rather than simply moving whenever I press the key. I've looked through of codes and examples, but I'm still lost.
Here's my code:
import pygame, sys
pygame.init()
width, height = 800, 600
screen = pygame.display.set_mode([width, height])
bat_speed = 30
bat = pygame.image.load('bat.png').convert()
batrect = bat.get_rect()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
batrect = batrect.move(-bat_speed, 0)
if (batrect.left < 0):
batrect.left = 0
if event.key == pygame.K_RIGHT:
batrect = batrect.move(bat_speed, 0)
if (batrect.right > width):
batrect.right = width
screen.blit(bat, batrect)
pygame.display.flip()
pygame.quit()
When you blit something on the screen it'll stay there. What's happening is that you're blitting the bat at different locations, making it seem like the width of the bat increases. Simple fix would be to clear the screen before you draw the bat.
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
batrect = batrect.move(-bat_speed, 0)
if (batrect.left < 0):
batrect.left = 0
elif event.key == pygame.K_RIGHT:
batrect = batrect.move(bat_speed, 0)
if (batrect.right > width):
batrect.right = width
screen.fill((0, 0, 0)) # This will fill the screen with a black color.
screen.blit(bat, batrect)
pygame.display.flip()
Also, use elif instead of multiple if when you don't want to check every condition, like I did above.
I'm trying to code a program that can take text and animate it to bounce on a loop, like a ball bouncing to the floor. I used a similar piece of code I found a starting point as I'm still fairly new to Pygame (thank you Pete Shinners, whoever you are), but after updating the code and playing with it for a long time I still can't get it to blit to the screen correctly. The text starts above the rendered area and then gradually falls into view, but the top part of the text is cut off.
I've tried moving the blitted region around the window and resizing the rectangles and surface the program is using, but nothing seems to fix it.
import os, sys, math, pygame, pygame.font, pygame.image
from pygame.locals import *
def bounce():
# define constants
G = 0.98
FLOOR = 0
COEFFICIENT = 0.8
#define variables
ball = 500
direction = 'DOWN'
v = 0
count = 0
#create array to store data
array = [ball]
while True:
if count == 4:
return array
elif ball > FLOOR and direction == 'DOWN':
v += G
if (ball - v) >= FLOOR:
ball = ball - v
array.append(round(ball,2))
else:
ball = FLOOR
array.append(round(ball,2))
direction = 'UP'
v *= COEFFICIENT
count += 1
elif ball >= FLOOR and direction == 'UP':
v -= G
if (ball + v) >= FLOOR:
ball = ball + v
array.append(round(ball,2))
if v <= 0:
direction = 'DOWN'
else:
ball = FLOOR
array.append(ball)
direction = 'UP'
v *= COEFFICIENT
class textBouncy:
array = bounce()
def __init__(self, font, message, fontcolor, amount=10):
# Render the font message
self.base = font.render(message, 0, fontcolor)
# bounce amount (height)
self.amount = amount
#size = rect of maximum height/width of text
self.size = self.base.get_rect().inflate(0, amount).size
#normalise array to meet height restriction
self.array = [round(-x/(500/amount),2) for x in array]
def animate(self):
# create window surface s
s = pygame.Surface(self.size)
# height = max inflated height
height = self.size[1]
# define a step-sized rectangle in the location of the step
src = Rect(0, 0, self.base.get_width(), height)
# moves the message according to the array list.
dst = src.move(0, self.array[i])
if (i + 1) == len(self.array):
global i
i = 0
# blits the information onto the screen
s.blit(self.base, dst, src)
return s
entry_info = 'Bouncing ball text'
if __name__ == '__main__':
pygame.init()
#create text renderer
i = 0
array = bounce()
bigfont = pygame.font.Font(None, 60)
white = 255, 255, 255
renderer = textBouncy(bigfont, entry_info, white, 16)
text = renderer.animate()
#create a window the correct size
win = pygame.display.set_mode(text.get_size())
win.blit(text, (0, 10))
pygame.display.flip()
#run animation loop
finished = 0
while True:
pygame.time.delay(10)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
text = renderer.animate()
i += 1
win.blit(text, (0, 10)) # blits the finished product from animate
pygame.display.flip()
(Quote) "it all comes down to math really" Kay so you need to - the y axis when you want to make it go up and + the x axis to make it go side ways you could make it go up and down will moveing it horizontally and then when it reaches a point it will stop moving horizontally and just bonce up and down +ing it more every time
That was my 100$ which took me 5 mins to write
After revisiting this I managed to work this out - I needed to add everything I blitted down to compensate for the bounce up. So in the __init__function:
self.array = [round(-x/(500/amount),2)**+self.amount** for x in array]
Works perfectly now :)
i made a program in pygame ware a mine turtle runs in a sqare but when you click in the box he explodes but when i change the image to an explodtion it shows th mineturtle first
here's my code:
import pygame, sys, time
from pygame.locals import *
pygame.init()
FPS = 40 # frames per second setting
fpsClock = pygame.time.Clock()
# set up the window
DISPLAYSURF = pygame.display.set_mode((400, 300), 0, 32)
pygame.display.set_caption('Animation')
WHITE = (255, 255, 255)
print("if you click the mine tutle box he will explode")
cat = pygame.image.load("mineturtle.PNG")
catx = 10
caty = 10
direction = 'right'
s=15
while True: # the main game loop
DISPLAYSURF.fill(WHITE)
if direction == 'right':
catx += s
if catx == 280:
direction = 'down'
elif direction == 'down':
caty += s
if caty == 220:
direction = 'left'
elif direction == 'left':
catx -= s
if catx == 10:
direction = 'up'
elif direction == 'up':
caty -= s
if caty == 10:
direction = 'right'
DISPLAYSURF.blit(cat, (catx, caty))
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
b = pygame.image.load("b.png")
time.sleep(2)
pygame.quit()
sys.exit()
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
fpsClock.tick(FPS)
i already have all of the files in the same loaction but when i did the image swich id didn't work! plz help
To show changes on screen you need to call pygame.display.update(). When you call sleep and exit, it does not update the screen, and no changes are seen.
time.
EDIT:
If you wish to show a new image for 2 seconds and then close the program, you should use pygame.time module. Have a variable that will store the time since the last click. You add the result of tick(). When the value will be high enough, you can exit pygame.
This will not freeze the window, and you will be able to see the changes.
i just did this
import pygame, sys, time
from pygame.locals import *
pygame.init()
FPS = 40 # frames per second setting
fpsClock = pygame.time.Clock()
# set up the window
DISPLAYSURF = pygame.display.set_mode((400, 300), 0, 32)
pygame.display.set_caption('Animation')
WHITE = (255, 255, 255)
print("if you click the mine tutle box he will explode")
cat = pygame.image.load("mineturtle.PNG")
catx = 10
caty = 10`enter code here`
direction = 'right'
s=15
explodetick=0
move=True
while True: # the main game loop
DISPLAYSURF.fill(WHITE)
#for event in pygame.event.get():
#
if explodetick>0:
explodetick+=1
if explodetick==81:
pygame.quit()
if move:
if direction == 'right':
catx += s
if catx == 280:
direction = 'down'
elif direction == 'down':
caty += s
if caty == 220:
direction = 'left'
elif direction == 'left':
catx -= s
if catx == 10:
direction = 'up'
elif direction == 'up':
caty -= s
if caty == 10:
direction = 'right'
DISPLAYSURF.blit(cat, (catx, caty))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
cat = pygame.image.load("b.png")
pygame.display.update()
explodetick=1
move=False
pygame.display.update()
fpsClock.tick(FPS)