#!/usr/bin/python
# -*- coding: utf-8 -*-
import pygame
import sys
import datetime
import time
class TextPicture(pygame.sprite.Sprite):
def __init__(self, speed, location):
pygame.sprite.Sprite.__init__(self)
now = datetime.datetime.now()
text = now.strftime("%H:%M:%S")
font = pygame.font.Font(None, 40)
time_text = font.render(text, 1, [0, 0, 0]) # show now time
self.image = time_text
self.speed = speed
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
def move(self):
self.rect = self.rect.move(self.speed)
if self.rect.left < 0 or self.rect.left > screen.get_width() - self.image.get_width():
self.speed[0] = -self.speed[0]
if self.rect.top < 0 or self.rect.top > screen.get_height() - self.image.get_height():
self.speed[1] = -self.speed[1]
pygame.init()
screen = pygame.display.set_mode([640, 480])
my_time_picture = TextPicture([1, 1], [50, 50])
while 1:
screen.fill([255, 255, 255])
my_time_picture.move()
screen.blit(my_time_picture.image, my_time_picture.rect)
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
I am designing a clock which can move in the screen. But what my code can do now is to show a invariant time. I want to clicking and count the time.
My invariable clock picture
And I want to make my clock more beautiful, but don't know how. I will be super grateful if anyone can make any suggestions.
You could do it by using pygame.time.set_timer() to make "tick events" be generated which cause the clock's image to be updated when encountered in the event processing loop.
To make implementing this easier, an update() method could be added to the DigitalClock class (which is what I renamed your generic TextPicture class) which only updates the image, but leaving the current location alone:
import datetime
import sys
import time
import pygame
class DigitalClock(pygame.sprite.Sprite):
def __init__(self, speed, location):
pygame.sprite.Sprite.__init__(self)
self.speed = speed
self.font = pygame.font.Font(None, 40)
self.rect = pygame.Rect(location, (0, 0)) # placeholder
self.update()
def update(self):
location = self.rect.left, self.rect.top # save position
time_text = datetime.datetime.now().strftime("%H:%M:%S")
self.image = self.font.render(time_text, 1, [0, 0, 0])
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location # restore position
def move(self):
self.rect = self.rect.move(self.speed)
if (self.rect.left < 0
or self.rect.left > screen.get_width()-self.image.get_width()):
self.speed[0] = -self.speed[0]
if (self.rect.top < 0
or self.rect.top > screen.get_height()-self.image.get_height()):
self.speed[1] = -self.speed[1]
Following that, you'd need to modify the processing to be something along these lines:
pygame.init()
framerate_clock = pygame.time.Clock()
screen = pygame.display.set_mode([640, 480])
my_digital_clock = DigitalClock([1, 1], [50, 50])
TICK_EVENT = pygame.USEREVENT + 1
pygame.time.set_timer(TICK_EVENT, 1000) # periodically create TICK_EVENT
while True:
for event in pygame.event.get():
if event.type == TICK_EVENT:
my_digital_clock.update() # call new method
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.fill([255, 255, 255])
my_digital_clock.move()
screen.blit(my_digital_clock.image, my_digital_clock.rect)
framerate_clock.tick(60) # limit framerate
pygame.display.flip()
You could make it more beautiful by using a different font and color. Generally anything that made it look more realistic would be an improvement. It might be cool to make the colons between the digit characters blink on and off (using a similar technique).
Related
I know that is not really a blank screen, but now I have a problem.
It takes forever to load the game.
Everytime I close the window, it fully loads????
If u need code, ask.
please help
You've to crate an PlayerClass object and you've to add the pygame.sprite.Sprite to a pygame.sprite.Group:
player = PlayerClass('player_1_0.png', [5, 0])
all_sprites = pygame.sprite.Group()
all_sprites.add(player)
In the main loop you've to updat the position of the player (player.move()). Clear the display, draw the sprites and update the display (e.g. by pygame.display.update()):
while running:
# [...]
player.move()
screen.fill([255, 255, 255])
all_sprites.draw(screen)
pygame.display.update()
Working example:
import pygame, sys
screen = pygame.display.set_mode([640,480])
clock = pygame.time.Clock()
class PlayerClass(pygame.sprite.Sprite):
def __init__(self, image_file, speed, location = [0,0]):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.center = [320, 100]
self.speed = speed
self.angle = 90
def move(self):
global points, score_text
self.rect = self.rect.move(self.speed)
if self.rect.left < 0 or self.rect.right > screen.get_width():
self.speed[0] = -self.speed[0]
if self.rect.top <= 0 :
self.speed[1] = -self.speed[1]
points = points + 1
score_text = font.render(str(points), 1, (0, 0, 0))
player = PlayerClass('player_1_0.png', [5, 0])
all_sprites = pygame.sprite.Group()
all_sprites.add(player)
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
player.move()
screen.fill([127, 127, 127])
all_sprites.draw(screen)
pygame.display.update()
pygame.quit()
The code works fine when you first load the game the two rectangles are there but when the player moves, the enemy rectangle disappears.
EXTENSION I am trying to get the enemy class to move up and down constantly without any keys needed to be pressed.
import pygame
import os
import random
from pygame.locals import * # Constants
import math
import sys
import random
pygame.init()
screen=pygame.display.set_mode((1280,720)) #(length,height)
screen_rect=screen.get_rect()
background = pygame.Surface(screen.get_size())
background = pygame.image.load('stage.png').convert()
screen.blit(background, (0, 0))
class Player(pygame.sprite.Sprite):
def __init__(self):
self.rect = pygame.draw.rect(screen, (0,0,128), (50,560,50,25)) #(colour)(x-position,y-position,width,height)
self.dist = 100
def draw_rect(self,x,y): # This is my code which should make the player move
screen.blit(background, (0, 0)) #If this isn't included then when the rectangle moves it's old positon will still be on the screen
self.rect = self.rect.move(x*self.dist, y*self.dist); pygame.draw.rect(screen, (0, 0, 128), self.rect)
pygame.display.update()
def handle_keys(self): # code to make the character move when the arrow keys are pressed
keys = pygame.key.get_pressed()
if keys[K_LEFT]:
self.draw_rect(-0.05,0)
elif keys[K_RIGHT]:
self.draw_rect(0.05,0)
elif keys[K_UP]:
self.draw_rect(0,-0.05)
elif keys[K_DOWN]:
self.draw_rect(0,0.05)
elif keys[K_SPACE]:
self.draw_rect(0.05,-0.05)
if self.rect.right > 1280:
self.rect.right = 1280
if self.rect.left < 0:
self.rect.left = 0
if self.rect.bottom > 720:
self.rect.bottom = 720
if self.rect.top < 0:
self.rect.top = 0
class Enemy(pygame.sprite.Sprite): # the enemy class which works fine
def __init__(self):
x = random.randint(50,450)
self.rect = pygame.draw.rect(screen, (128,0,0), (300,x,50,25))
player = Player()
enemy = Enemy()
def main(): #my main loop
running = True
while running:
player.handle_keys()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.display.flip() #updates the whole screen
if __name__ == '__main__': main()
you are only drawing the sprites when the class is instatiated in the __init__()
you need to be drawing them every loop in the main()function right before pygame.display.flip()
as things are right now, neither the player nor the enemy should display beyond the first frame
You have to clear the screen every frame - you can do this by blitting the background - and draw the sprites afterwards. Separate the movement from the drawing code so that you can blit the sprites after the screen has been cleared.
class Player(pygame.sprite.Sprite):
def __init__(self):
self.rect = pygame.draw.rect(screen, (0,0,128), (50,560,50,25))
self.dist = 100
# Separate the movement and the drawing.
def move(self, x, y):
self.rect = self.rect.move(x*self.dist, y*self.dist)
def draw(self, screen):
pygame.draw.rect(screen, (0, 0, 128), self.rect)
def handle_keys(self):
keys = pygame.key.get_pressed()
if keys[K_LEFT]:
self.move(-0.05,0)
elif keys[K_RIGHT]:
self.move(0.05,0)
elif keys[K_UP]:
self.move(0,-0.05)
elif keys[K_DOWN]:
self.move(0,0.05)
elif keys[K_SPACE]:
self.move(0.05,-0.05)
if self.rect.right > 1280:
self.rect.right = 1280
if self.rect.left < 0:
self.rect.left = 0
if self.rect.bottom > 720:
self.rect.bottom = 720
if self.rect.top < 0:
self.rect.top = 0
class Enemy(pygame.sprite.Sprite):
def __init__(self):
self.x = random.randint(50,450) # x is now an attribute.
def draw(self, screen):
self.rect = pygame.draw.rect(screen, (128,0,0), (300, self.x, 50, 25))
def main():
clock = pygame.time.Clock() # A clock to limit the frame rate.
player = Player()
enemy = Enemy()
running = True
while running:
player.handle_keys()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Clear the screen every frame by blitting the background.
screen.blit(background, (0, 0))
# Then draw the enemy and the player.
enemy.draw(screen)
player.draw(screen)
pygame.display.flip()
clock.tick(60) # Limit the frame rate to 60 FPS.
I also recommend checking out how sprite groups work, then you can get rid of the draw methods and can just call sprite_group.draw(screen) to draw every contained sprite. Here's a tutorial.
Im trying to make a rain effect with pygame but it seems as if the background is not cleaning up before updating the sprites.
this is what it looks like when i execute the code..
I wonder if there's a way to fix this problem.
rain.py (main file)
#!/usr/bin/python
VERSION = "0.1"
import os, sys, raindrop
from os import path
try:
import pygame
from pygame.locals import *
except ImportError, err:
print 'Could not load module %s' % (err)
sys.exit(2)
# main variables
WIDTH, HEIGHT, FPS = 300, 300, 30
# initialize game
pygame.init()
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("Rain and Rain")
# background
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((40,44,52))
# blitting
screen.blit(background,(0,0))
pygame.display.flip()
# clock for FPS settings
clock = pygame.time.Clock()
def main():
raindrops = pygame.sprite.Group()
# a function to create new drops
def newDrop():
nd = raindrop.Raindrop()
raindrops.add(nd)
# creating 10 rain drops
for x in range(0,9): newDrop()
# variable for main loop
running = True
# event loop
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
raindrops.update()
screen.blit(background,(100,100))
raindrops.draw(screen)
pygame.display.flip()
pygame.quit()
if __name__ == '__main__': main()
raindrop.py ( class for raindrops )
import pygame
from pygame.locals import *
from os import path
from random import randint
from rain import HEIGHT
img_dir = path.join(path.dirname(__file__), 'img')
class Raindrop(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.width = randint(32, 64)
self.height = self.width + 33
self.image = pygame.image.load(path.join(img_dir, "raindrop.png")).convert_alpha()
self.image = pygame.transform.scale(self.image, (self.width, self.height))
self.speedy = 5 #randint(1, 8)
self.rect = self.image.get_rect()
self.rect.x = randint(0, 290)
self.rect.y = -self.height
def update(self):
self.rect.y += self.speedy
if self.rect.y == HEIGHT:
self.rect.y = -self.height
self.rect.x = randint(0, 290)
This is the line you use to clear the screen:
screen.blit(background, (100, 100))
In other words; you're clearing the screen starting at x=100, y=100. Since pygame coordinates starts from topleft and extends to the right and downwards, you're not clearing the screen left of x=100 and above y=100.
Simple fix is blitting at 0, 0 as you did at the start of the program.
screen.blit(background, (0, 0))
#!/usr/bin/python
# -*- coding: utf-8 -*-
import pygame
import sys
class MyBallClass(pygame.sprite.Sprite):
def __init__(self, image_file, speed, location):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
self.speed = speed
def move(self):
global points, score_text
self.rect = self.rect.move(self.speed)
if self.rect.left < 0 or self.rect.right > screen.get_width():
self.speed[0] = -self.speed[0]
if self.rect.top <= 0:
self.speed[1] = -self.speed[1]
points += 1
score_text = font.render(str(points), 1, (0, 0, 0))
class MyPaddleClass(pygame.sprite.Sprite):
def __init__(self, location=[0, 0]):
pygame.sprite.Sprite.__init__(self)
image_surface = pygame.surface.Surface([100, 20])
image_surface.fill([0, 0, 0])
self.image = image_surface.convert()
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
pygame.init()
screen = pygame.display.set_mode([640, 480])
clock = pygame.time.Clock()
ball_speed = [3, 4]
myball = MyBallClass("E:\\python file\\blackball.jpg", ball_speed, [50, 50])
ballgroup = pygame.sprite.Group(myball)
paddle = MyPaddleClass([270, 400])
lives = 3
points = 0
font = pygame.font.Font(None, 50)
score_text = font.render(str(points), 1, (0, 0, 0))
textpos = [10, 10]
done = False
while 1:
clock.tick(30)
screen.fill([255, 255, 255])
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.MOUSEMOTION:
paddle.rect.centerx = event.pos[0]
if pygame.sprite.spritecollide(paddle, ballgroup, False):
myball.speed[1] = -myball.speed[1]
myball.move()
if not done:
screen.blit(myball.image, myball.rect)
screen.blit(paddle.image, paddle.rect)
screen.blit(score_text, textpos)
for i in range(lives):
width = screen.get_width()
screen.blit(myball.image, [width - 40 * i, 20])
pygame.display.flip()
if myball.rect.top <= screen.get_rect().bottom:
# In get_rect(), you cannot leave out brackets
lives -= 1
if lives == 0:
final_text1 = "Game over!"
final_text2 = 'your final score is' + str(points)
ft1_font = pygame.font.Font(None, 70)
ft2_font = pygame.font.Font(None, 50)
ft1_surface = font.render(final_text1, 1, (0, 0, 0))
ft2_surface = font.render(final_text2, 1, (0, 0, 0))
screen.blit(ft1_surface, [screen.get_width() / 2, 100])
screen.blit(ft2_surface, [screen.get_width() / 2, 200])
pygame.display.flip()
done = True
else:
pygame.time.delay(1000)
myball.rect.topleft = [50, 50]
frame_rate = clock.get_fps()
print(frame_rate)
Here is the pygame window picture of my code:(http://i.stack.imgur.com/SFyBJ.jpg)
Every time I run it, I don't have the time to control the paddle, then it shows game is over. I have been searching for a long time but can't find out why. It seems like the blackball is moving so fast that the game is over in about one second. But I already set the speed to a reasonable range, I am so confused. Can anyone help?
I could rebuild your game, and fixed the problem.
Try inverse condition here
if myball.rect.top >= screen.get_rect().bottom:
and it works fine: I can hit the ball with the bat, make it bounce, ...
I don't know why it took me so long ot figure it out: you lose the game if ball goes off the screen by the bottom. For that, top y must be greater than the bottom of the window (computer screen coordinates are 0,0 from upper left)
I am new to pygame and I am making a side scrolling game that uses a bird as the character and it flies but I am trying to get it to move up and down on the screen but I can't figure out how.
import pygame
from pygame.locals import *
import os
import sys
import time
pygame.init()
class Fly:
def __init__(self):
self.last_update = time.clock()
self.screen = pygame.display.set_mode((700, 400), 0, 32)
#Load bird
self.bird_state = 1
self.bird_frames = []
for r in xrange(1, 5):
self.bird_frames.append(pygame.image.load('bird%s.png' % r))
self.bg = pygame.image.load('bg.png').convert()
self.Loop()
def eventLoop(self):
'Take and process input from perephirals'
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
def Update(self):
self.bird_state += 1
if self.bird_state > 4:
self.bird_state = 1
def Draw(self):
self.screen.blit(self.bg, [0, 0])
self.screen.blit(self.bird_frames[self.bird_state - 1], (150, 150))
def Loop(self):
while 1:
self.eventLoop()
if time.clock() - self.last_update > 0.15:
self.Update()
self.last_update = time.clock()
self.Draw()
pygame.display.update()
Fly()
import pygame
from pygame.locals import *
import os
import sys
import time
pygame.init()
class Fly:
def __init__(self):
self.last_update = time.clock()
self.screen = pygame.display.set_mode((700, 400), 0, 32)
#Load bird
self.bird_state = 1
self.bird_frames = []
for r in xrange(1, 5):
self.bird_frames.append(pygame.image.load('bird%s.png' % r))
self.bg = pygame.image.load('bg.png').convert()
self.Loop()
def eventLoop(self):
'Take and process input from perephirals'
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
def Update(self):
self.bird_state += 1
if self.bird_state > 4:
self.bird_state = 1
def Draw(self):
self.screen.blit(self.bg, [0, 0])
self.screen.blit(self.bird_frames[self.bird_state - 1], (150, 150))
def Loop(self):
while 1:
self.eventLoop()
k = pygame.key.get_pressed()
if k[K_DOWN]:
# Do something with your bird
if k[K_UP]:
# Do something with your bird
if time.clock() - self.last_update > 0.15:
self.Update()
self.last_update = time.clock()
self.Draw()
pygame.display.update()
Fly()
The pygame.key.get_pressed will check if you pressed a button. Check the reference for what kind of options you have there. http://www.pygame.org/docs/ref/key.html
Place this in your loop because then its "realtime".
k = pygame.key.get_pressed()
if k[K_DOWN]:
# Do somthing with your bird
if k[K_UP]:
# Do somthing with your bird
If you think of your Player as a rectangle (this could apply to all of your sprites in your game) then all you have to do is set up two parameters for your rectangle called self.speedx and self.speedy. Since you you're looking for only up and down movement, speedx would not change, but you would adjust speedy depending on what button is pressed. Here's a snippet of code from one of my games. It is part of the update def for my player class. Unfortunately, in this game I just wanted lateral (left and right) movement, but you'll get the idea. If you need anymore help, let me know. Here's the code:
def update(self):
# Ensures default motion is 0
self.speedx = 0
self.speedy = 0
# This checks to see what key's are pressed
keystate = pygame.key.get_pressed()
# This gives control for movement (Can use WASD or arrow keys)
if keystate[pygame.K_a] or keystate[pygame.K_LEFT]:
self.speedx = -5
if keystate[pygame.K_d] or keystate[pygame.K_RIGHT]:
self.speedx = 5
if keystate[pygame.K_SPACE]:
self.shoot(bullet_img)
# Gives movement based on keys that are pressed
self.rect.x += self.speedx
self.rect.y += self.speedy